Sigueme en Facebook Sigueme en Twitter Sigueme en Instagram Sigueme en Youtube
JC Mouse Bolivia
Index / Java / Transacciones – Uso de Commit y Rollback

Transacciones – Uso de Commit y Rollback

Autor jc mouse martes, abril 7, 2015

Cuando desarrollamos aplicaciones en java con base de datos debemos tener cuidado en que se cumplan un conjunto de características conocida como ACID (Atomicidad, Consistencia, Aislamiento, Durabilidad), en el caso de este post nos centraremos en la Atomicidad y Consistencia

Atomicidad: es la propiedad que asegura que la operación se ha realizado o no, y por lo tanto ante un fallo del sistema no puede quedar a medias. Se dice que una operación es atómica cuando es imposible para otra parte de un sistema encontrar pasos intermedios. Si esta operación consiste en una serie de pasos, todos ellos ocurren o ninguno. Por ejemplo, en el caso de una transacción bancaria o se ejecuta tanto el depósito como la deducción o ninguna acción es realizada. [Wikipedia]
Consistencia: Integridad. Es la propiedad que asegura que sólo se empieza aquello que se puede acabar. Por lo tanto se ejecutan aquellas operaciones que no van a romper las reglas y directrices de integridad de la base de datos. La propiedad de consistencia sostiene que cualquier transacción llevará a la base de datos desde un estado válido a otro también válido. “La Integridad de la Base de Datos nos permite asegurar que los datos son exactos y consistentes, es decir que estén siempre intactos, sean siempre los esperados y que de ninguna manera cambien ni se deformen. De esta manera podemos garantizar que la información que se presenta al usuario será siempre la misma.” [Wikipedia]

Planteando una situación para este tutorial

Si tenemos una serie de sentencias SQL INSERT por ejecutar y por un motivo XYZ 🙂 surge un error que no permite que se completen todas estas sentencias nos encontramos con el problema de que hasta el punto que se produjo el error, los INSERT se ejecutaron y se guardaron nuevos registros en la base de datos, entonces estaríamos violando los criterios de Atomicidad y de Consistencia porque no primeramente no se completo la transacción en su totalidad pero tenemos nuevos registros en la base de datos pero estos registros están incompletos.

¿Como podemos solucionar este problema?

Necesitamos

  • Java
  • IDE Netbeans 7.x o Eclipse
  • Libreria MySQL JDBC Driver
  • MySQL

Nivel: Intermedio

Tiempo. 15 minutos

Base de datos.

Para el ejemplo de este post, utilizaremos dos tablas “miTabla” y “miOtraTabla“, su estructura es la siguiente:

-- 
-- Estructura de tabla para la tabla 'mitabla'
-- 

CREATE TABLE mitabla (
  DNI varchar(12) default NULL,
  correo varchar(32) default NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

-- 
-- Estructura de tabla para la tabla 'miotratabla'
-- 

CREATE TABLE miotratabla (
  nombre varchar(20) default NULL,
  apellido varchar(20) default NULL,
  edad int(20) default NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

IMPORTANTE al crear las tablas, debemos utilizar ENGINE=InnoDB y no MyISAM esto porque InnoDB tiene soporte para transacciones, bloqueo de registros y nos permite tener las características ACID  garantizando la integridad de nuestras tablas.

Proyecto Netbeans

Nuestro proyecto base sera el siguiente:

rollback commit

  • Le añadimos el conector JDBC al proyecto
  • Tenemos una clase llamada Database.java que nos permite conectarse a la base de datos MySQL
  • Tenemos dos clases Main, JNoRollback y JRollback, en la primera clase se implementara las instrucciones INSERT sin el uso de Commit y Rollback , en la segunda clase con el uso de estos 2 métodos, el fin es apreciar mejor que pasa cuando se produce un error al ejecutar estas transacciones.
Clase Database.java
package app;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
/**
 * @web http://www.jc-mouse.net/
 * @author Mouse
 */
public class Database {

   private final static String bd = "BASE_DE_DATOS";
   private final static String login = "USUARIO";
   private final static String password = "CONTRASEÑA";
   private final static String url = "jdbc:mysql://localhost/"+bd;

    public static Connection getConnection(){
        try{
         Class.forName("com.mysql.jdbc.Driver");         
         Connection conn = DriverManager.getConnection(url,login,password);
         if (conn!=null){
            System.out.println("Conectado a la base de datos ["+bd+"]");
         }
         return conn;
      }catch(SQLException e){
         System.err.println(e.getMessage());
      }catch(ClassNotFoundException e){
         System.err.println(e.getMessage());
      }
      return null;
   }

}
Clase JNoRollback.java
En esta clase no se hace uso de los métodos Commit y RollBack por lo que las instrucciones INSERT se irán ejecutando una tras otra afectando directamente a la base de datos, si no se encontrara ningún error todo terminaría normalmente, sin embargo en la linea de código 46 intencionalmente se intercambia el tipo de dato INT por un STRING  esto para provocar una excepción, entonces las instrucciones INSERT de las lineas 30,35,40 se ejecutaran pero no así la linea 47.
01 package app;
02 import java.sql.Connection;
03 import java.sql.PreparedStatement;
04 import java.sql.SQLException;
05 /**
06  * @web http://www.jc-mouse.net/
07  * @author Mouse
08  */
09 public class JNoRollback {
10 
11     /**
12  * @param args the command line arguments
13  */
14     public static void main(String[] args) {
15         
16          //Obtenemos conexion a la base de datos
17         Connection connection = Database.getConnection();
18          
19         PreparedStatement stmt1=null;
20         PreparedStatement stmt2=null;         
21         
22         try {            
23             //Se preparan las sentencias SQL
24             stmt1 = connection.prepareStatement("INSERT INTO miTabla VALUES( ?, ? );");            
25             stmt2 = connection.prepareStatement("INSERT INTO miOtraTabla VALUES( ?, ?, ? );");
26             
27             System.out.println( "Primer INSERT tabla [miTabla] " ); 
28             stmt1.setString(1, "000001");
29             stmt1.setString(2, "micorreo@mail.com");
30             stmt1.executeUpdate();
31         
32             System.out.println( "Segundo INSERT tabla [miTabla] " ); 
33             stmt1.setString(1, "000002");
34             stmt1.setString(2, "amayuya@mail.com");
35             stmt1.executeUpdate();
36             
37             System.out.println( "Tercer INSERT tabla [miTabla] " ); 
38             stmt1.setString(1, "000003");
39             stmt1.setString(2, "diosdado@mail.com");
40             stmt1.executeUpdate();
41             
42             System.out.println( "Primer INSERT tabla [miOtraTabla]" );
43             stmt2.setString(1, "Juan");
44             stmt2.setString(2, "Perez");            
45             //stmt2.setInt(3, 99); //Tipo de dato CORRECTO INT
46             stmt2.setString(3, "Hola soy un error");//Tipo de dato INCORRECTO 
47             stmt2.executeUpdate();
48       
49         } catch (SQLException ex) {
50             System.err.println("ERROR: " + ex.getMessage());                            
51         }finally{
52             System.out.println( "cierra conexion a la base de datos" );    
53             try {
54                 if(stmt1!=null) stmt1.close();                
55                 if(stmt2!=null) stmt2.close();                
56                 if(connection!=null) connection.close();
57             } catch (SQLException ex) {
58                 System.err.println( ex.getMessage() );    
59             }
60         }      
61         
62     }//end:main
63 }
Ejecutando la clase Main JNoRollback obtenemos el siguiente resultado por consola:
mal
Como dijimos más arriba, al ejecutar este código se produce una excepción “ERROR: Incorrect integer value: ‘Hola soy un error’ for column ‘edad’ at row 1” y si revisamos la base de datos, podremos observar como en la tabla “miTabla” se registraron 3 nuevas filas pero si abrimos la tabla “miOtraTabla” no existen registros, es decir no se esta cumpliendo con lo principio de ATOMICIDAD Y CONSISTENCIA
Clase JRollback.java
Este clase contiene el mismo código de más arriba pero se le agrego algunas lineas de código extra
01 package app;
02 
03 import java.sql.Connection;
04 import java.sql.PreparedStatement;
05 import java.sql.SQLException;
06 /**
07  * @web http://jc-mouse.net/
08  * @author Mouse
09  */
10 public class JRollback {
11     
12     public static void main(String[] args) {
13 
14         //Obtenemos conexion a la base de datos
15         Connection connection = Database.getConnection();
16          
17         PreparedStatement stmt1=null;
18         PreparedStatement stmt2=null;         
19         
20         try {
21             //se deshabilita el modo de confirmación automática
22             connection.setAutoCommit(false);            
23             //Se preparan las sentencias SQL
24             stmt1 = connection.prepareStatement("INSERT INTO miTabla VALUES( ?, ? );");            
25             stmt2 = connection.prepareStatement("INSERT INTO miOtraTabla VALUES( ?, ?, ? );");
26             
27             System.out.println( "Primer INSERT tabla [miTabla] " ); 
28             stmt1.setString(1, "000001");
29             stmt1.setString(2, "micorreo@mail.com");
30             stmt1.executeUpdate();
31         
32             System.out.println( "Segundo INSERT tabla [miTabla] " ); 
33             stmt1.setString(1, "000002");
34             stmt1.setString(2, "amayuya@mail.com");
35             stmt1.executeUpdate();
36             
37             System.out.println( "Tercer INSERT tabla [miTabla] " ); 
38             stmt1.setString(1, "000003");
39             stmt1.setString(2, "diosdado@mail.com");
40             stmt1.executeUpdate();
41             
42             System.out.println( "Primer INSERT tabla [miOtraTabla]" );
43             stmt2.setString(1, "Juan");
44             stmt2.setString(2, "Perez");            
45             //stmt2.setInt(3, 99); //Tipo de dato CORRECTO INT
46             stmt2.setString(3, "Hola soy un error");//Tipo de dato INCORRECTO
47             stmt2.executeUpdate();
48             
49             //se indica que se deben aplicar los cambios en la base de datos
50             connection.commit();
51       
52         } catch (SQLException ex) {
53             System.err.println("ERROR: " + ex.getMessage());
54             if(connection!=null)
55             {
56                 System.out.println("Rollback");
57                 try {
58                     //deshace todos los cambios realizados en los datos
59                     connection.rollback();
60                 } catch (SQLException ex1) {
61                     System.err.println( "No se pudo deshacer" + ex1.getMessage() );    
62                 }
63             }                
64         }finally{
65             System.out.println( "cierra conexion a la base de datos" );    
66             try {
67                 if(stmt1!=null) stmt1.close();                
68                 if(stmt2!=null) stmt2.close();                
69                 if(connection!=null) connection.close();
70             } catch (SQLException ex) {
71                 System.err.println( ex.getMessage() );    
72             }
73         }      
74         
75     }//end:main
76 }
Explicación:
22 : Se deshabilita el modo de confirmación automática, es decir todas las instrucciones SQL a partir de ese punto se agrupan en una sola transacción que finalizara con una llamada al método commit o al método rollback.
45 : Este es el tipo de dato correcto que acepta la instrucción SQL, para usarlo des-comenta y comenta la linea de código 46
46 : El error de tipo de dato es el mismo que de la clase anterior
50 :  Aquí hacemos uso del método commit(), es decir si se llega hasta este punto quiere decir que no se encontró ningún error y por tanto todas las instrucciones SQL (en este caso INSERT) serán confirmadas.
59 : Si se produce alguna excepción, se hará un llamado al método rollback() este método deshace todos los cambios realizados en la transacción actual y libera cualquier bloque en la base de datos que contenga en esos momentos este objeto
 64 : Para terminar se cierra la conexión actual a la base de datos
Ejecutando esta clase obtenemos la siguiente salida en pantalla:
transaccion
Como en el caso anterior provocamos una excepción, sin embargo en esta oportunidad  la transacción no llega a ser confirmada (commit) y es anulada por el método rollback. Si nos fijamos en nuestra base de datos, veremos que tanto en la tabla “miTabla” y “miOtraTabla” no se registro nada.
Descarga el proyecto AQUI
🙂

Tags

Si te ha gustado podrías compartirlo o dejar un comentario. ¡Muchas gracias!
Autor: JC Mouse

Yo soy yo :) JC Mouse, Soy orgullosamente boliviano soy fundador y CEO de la web jc-Mouse.net uno de las pocas web en emprendimiento y tecnología en Bolivia.

Toda la información que encuentres en este sitio es y sera completamente gratis siempre, puedes copiar, descargar y re-publicar si así lo deseas en otros blogs o sitios web, solo te pido a cambio que dejes una referencia a esta web. Esto nos ayuda a crecer y seguir aportando. Bye

Enjoy! :)

También Te Podría Interesar

Como capturar cambios del Slider en JavaFX

Como capturar cambios del Slider en JavaFX

En este tutorial veremos como usar el componente Slider de JavaFX , capturas los cambios que realice el usuario y con es...

Problema “Sucesión de ULAM”

Problema “Sucesión de ULAM”

La siguiente se llama conjetura de ULAM en honor del matematico S.Ulam Comience con cualquier entero positivo Si es par,...

Abrir enlace web desde JLabel con Java

Abrir enlace web desde JLabel con Java

El siguiente código te permite abrir enlaces web desde un JLabel, ademas aprovechando el soporte a etiquetas HTML del co...

Agregar soporte para JNLP en servidor Apache

Agregar soporte para JNLP en servidor Apache

Java Network Launching Protocol (JNLP) es una especificación usada por Java Web Start. Esta especificación, permite tene...

Envío de correo con JavaMail/Netbeans

Envío de correo con JavaMail/Netbeans

JavaMail es una expansión de Java que facilita el envío y recepción de e-mail desde código java. JavaMail implementa el...

Numero a Literal en Java

Numero a Literal en Java

Cuando se realizan trabajos donde se necesita mostrar al cliente un determinado monto de dinero, tipo factura, recibo, c...

4 comentarios en “Transacciones – Uso de Commit y Rollback”

  1. Oscar dice:

    Muy bueno, Mouse. Gracias por el esfuerzo de publicar lo que sabes.

  2. manuel dice:

    Jc, un consulta como haces en JAVA para usar el begin o el start transaction de la sintaxis de mysql server?

  3. rediespinoza dice:

    exceletente forma de explicar el manejo de las transciones muchas gracias

  4. Rances dice:

    Hey gracios por la explicación y el codigo me fue de gran ayuda 😀

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

*

Comparte lo que sabes

Categorias

Últimas entradas

Si quieres cambiar el nombre de tus atributos sin tener que reescribir código java por X o Y razón, GSON te permite reno...

Un JList nos permite almacenar objetos en una lista y mostrarlos gráficamente en una serie vertical en el cual el usuari...

El proyecto “Java Decompiler” tiene como objetivo desarrollar herramientas para descompilar y analizar byte...

En este post aprenderemos lo que es un JSON Web Token, como crear nuestro propio token de acceso y como usarlo en un Ser...

Android Bolivia

Bandera en Alto