6.4 - Transaccions
Una transacció és un conjunt de sentències SQL d'actualització (INSERT, DELETE, UPDATE) que o bé s'executen totes o bé no s'executa ninguna.
La manera de confirmar les sentències és amb COMMIT, i la manera de rebutjar-les totes és ROLLBACK (quedant l'estat com estava abans de començar la transacció). En qualsevol dels dos casos, després d'executar les sentències de control COMMIT o ROLLBACK, començarà una transacció nova.
JDBC trasllada també aquest metodologia al seu API. Per defecte, les connexions JDBC consideren que cada objecte Statement és en si mateix una transacció. Abans de cada execució es demana l’inici d’una transacció i al final, si l’execució té èxit, s’envia un commit i si no té èxit, un rollback. Per això diem que la connexió actua en mode autocommit.
Però hi ha una altra manera de funcionar. Els Statements poden treballar sense automatitzar el commit després de cada execució, canviant la connexió de mode amb el mètode setAutoCommit(false).
A partir d’aleshores es consideraran instruccions d’una mateixa transacció totes les sentències executades entre dues cridades als mètodes commit o rollback (equivalents JDBC de les instruccions COMMIT i ROLLBACK de SQL).
A continuació tenim un programa en el qual fem una sèrie de canvis (una modificació de files i un esborrat) però després fem un rollback, i per tant no s'haurà fet cap de les actualitzacions. És sobre la Base de Dades de SQLite Empleats,sqlite, que només tenia la taula EMPLEAT. Per a mostrar que estem fent els canvis, però que després ls desfem amb rollback, mostrem un resum en el qual senzillament indiquem el número d'empleat i el total dels sous.
Prèviament ens guardem el estat que tenia l'autocommit, i després el desactivem. Quan finalitza tot el procés posem autocommit com estava en un principi.
Copieu el següent codi en un fitxer Kotlin anomenat Exemple_4_61_Transaccions.kt :
package exemples
import java.sql.DriverManager
import java.sql.Connection
fun main(args: Array<String>) {
val con = DriverManager.getConnection("jdbc:sqlite:Empleats.sqlite")
resumEmpleats(con) // estat inicial
val autocommit = con.getAutoCommit()
con.setAutoCommit(false)
val st = con.createStatement()
st.executeUpdate("UPDATE EMPLEAT SET sou = sou * 1.05")
st.executeUpdate("DELETE FROM EMPLEAT WHERE depart=10")
resumEmpleats(con) // s'han modificat els sous i s'han esborrat dos empleats
con.rollback() // desfem els canvis
resumEmpleats(con) // hem tornat a l'estat inicial:
// no s'ha fet ni l'actualització de sous ni l'esborrat d'empleats
con.setAutoCommit(autocommit)
con.close()
}
fun resumEmpleats(c: Connection) { // En el resum traurem el número d'empleats i el total de sous
val st = c.createStatement()
val rs = st.executeQuery("SELECT COUNT(*), SUM(sou) FROM EMPLEAT")
rs.next()
println("Actualment hi ha " + rs.getInt(1) + " empleats que cobren un total de " + rs.getDouble(2) + " €")
rs.close()
st.close()
}
La major part de SGBD permeten utilitzar transaccions explícites amb qualsevol instrucció SQL, fins i tot alguns SGBD també en sentències DDL (data definition language) com CREATE TABLE, etc . Les sentències de definició modifiquen directament l’estructura de les dades i, per tant, cal anar molt en compte perquè poden provocar danys importants, pèrdues de dades existents, etc.
Però hi ha alguns SGBD com Oracle que no suporten la revocació de sentències DDL i en cas d’executar rollback, obtindrem un error indicant que les sentències DDL no es poden revocar.
Llicenciat sota la Llicència Creative Commons Reconeixement CompartirIgual 2.5