Crear varias tablas o ninguna usando commit

Quiero crear una serie de tablas en una base de datos de forma que, si se produce alguna excepción en el código de alguna, no se cree ninguna. Estoy haciendo lo siguiente, pero no funciona
Todo dentro de la misma clase, en una función tengo
...
try {
conn.setAutoCommit(false);
crearTablas(conn);
conn.commit();
} catch (SQLException e) {
conn.rollback();
}
...............
La función crearTablas(Connection conn) es así
// Crea las tablas de la base de datos
private void crearTablas(Connection conn) throws SQLException {
crearTablaPregSecretas(conn);
crearTablaEmprBolsa(conn);
crearTablaUsuario(conn);
crearTablaCartera(conn);
crearTablaEmpresa(conn);
crearTablaOperacion(conn);
}
y cada una de esas funciones es así
private void crearTablaPregSecretas(Connection conn) throws SQLException {
PreparedStatement prepStat = null;
try {
// Componemos la sentencia SQL
String query = "CREATE TABLE preg_secretas (" +
"preg_secreta VARCHAR(50) NOT NULL, " +
"CONSTRAINT preg_secretas_pk PRIMARY KEY (preg_secreta)) " +
"ENGINE = INNODB;";
prepStat = conn.prepareStatement(query);
// Ejecutamos la sentencia y obtenemos el resultado
prepStat.executeUpdate();
...
¿Captas la idea? Pretendo anular el commit, crear todas las tablas, y después activar el commit, de forma que si se produce una excepción en alguna tabla, no se activa el commit y se hace un rollback. El problema es que si se produce una excepción, por ejemplo, en el método de la tercera tabla, a pesar de lanzarse la excepción y no ejecutarse la activación del commit e ir al rollback, las dos anteriores se crean. ¿Cómo lo soluciono?

1 Respuesta

Respuesta
1
Puedes intentar crear todas las tablas en el mismo bloque try y hacer el commit() al final, poniendo el rollback en el bloque catch(). Es decir:
try {
    crearTabla1();
    crearTabla2();
    ...
    crearTablaN();
    commit();
}
catch (...) {
    rollback();
}
Disculpa, me equivoqué en la primera respuesta.
Creo que lo que te conviene hacer es una transacción. La inicias antes de crear las tablas y la terminas después. El problema es que no sé si para crear tablas es necesario un commit, porque por ejemplo en Oracle las tablas se borran directamente y me imagino que se crean de la misma manera (lo primero es bastante peligroso). En ese caso no se me ocurre ninguna manera de comprobar que todas las tablas se hayan creado correctamente.
Al final no me he enterado muy bien de qué tengo que hacer! :)
Lo primero que me has escrito es lo que hago yo pero de otra manera, y de lo segundo que me has dicho no me he enterado de nada. ¿Qué es una transacción? ¿No es el bloque que hay hasta el commit?, o sea, ¿lo qué ya hago? Uso MySQL
Te recomiendo que mires esta dirección:
http://technet.microsoft.com/es-es/library/ms174377.aspx
Ahí te explican lo que es una transacción. Te lo explican para SQL Server pero supongo que en MySQL funcionan igual. Suerte.
Sí, vale, acabo de leerlo, pero es lo que ya pensaba, el bloque de código que va hasta ejecutar el commit, momento en el cual todo se hace "efectivo". El problema es que yo hago eso y no me funciona. Sí que lo tengo así y funcionando con sentencias insert y update, pero de momento con varias sentencias create no he conseguido el mismo resultado. ¿Alguna sugerencia? ¿El comportamiento de create requiere hacer algo diferente?
Un saludo
Te explico lo que pretendo hacer para que me orientes
¿Cuándo una aplicación está ya disponible y puede ser usada, las tablas y los triggers ya tienen que estar en la base de datos, pero previamente habrá que crear eso, no? ¿Cómo se suele hacer?
Ya me he dado cuenta de que si quiero crear varias tablas de forma que se creen todas o ninguna (por si se produce una excepción en la creación de alguna), para lo cual uso el commit, este no me sirve de nada porque la sentencia create table implica ya un commit.
¿Cómo resuelvo esto?
Un saludo y gracias
Lo de crear las tablas y los triggers antes de ejecutar el programa se puede hacer de muchas maneras. Yo por ejemplo utilizo SQL Tools, aunque no sé si sólo sirve para sistemas Oracle.
Lo que tú haces es simplemente un commit pero tienes que definir el principio de la transacción (BEGIN TRANSACTION) de manera que tenga que ejecutarse correctamente todo el bloque o nada.
Hola!
Lo que me has comentado no funciona. Eso me parecía, ya que creo que no hace falta usar BEGIN TRANSACTION porque está implícito al hacer setAutocommit(false), pero lo he probado de todos modos.
Es más!, me he olvidado de java y me he ido a la consola de mysql para probarlo directamente, donde aquí sí que es necesario START TRANSACTION (para mysql es así) para conseguir lo que deseo, pero parece que con sentencias CREATE no funciona.
Lo he probado de la siguiente manera:
START TRANSACTION;
create table...
create table...
...
COMMIT;
Así me crea todas las tablas porque no se produce ningún error, pero si fuerzo un error en la definición de alguna tabla (la tercera por ejemplo) y también en el COMMIT (escribiendo COMMI para que falle al ejecutarse), las tablas iniciales en las que no hubo fallo sí que se crean de todos modos. No se espera a la ejecución de COMMIT para ello
Pfff! Esto parece que no tiene solución! :(
Entonces ocurre lo que te dije en la segunda respuesta: la creación y borrado de tablas no necesitan COMMIT para completarse. Yo creo que el ROLLBACK no funciona en el DDL.
Solución: crea las tablas directamente con el SQL Tools o similares, una por una; no lo hagas en tiempo de ejecución con el programa.
Corrígeme si me equivoco, pero usar SQL Tools o similares implica definir las tablas para que existan antes de hacer el deploy de la aplicación, ¿no?
No se cómo se procede en estas situaciones porque soy novato, pero teniendo las tablas creadas previamente se me ocurrió crearlas durante el deploy. Digamos me parecía más elegante y automático! :)
¿Me puedes dar tu opinión y confirmarme lo primero?
Saludos y muchas gracias
Parece lo más elegante hacerlo durante el deploy, como tú lo llamas, pero ten en cuenta lo siguiente:
1. Estás haciendo una mezcla innecesaria de Java y SQL, cuando lo que se pretende es separar lo máximo posible ambos lenguajes.
2. Tu programa será más grande y complejo de lo necesario.
3. Es ineficiente intentar crear un montón de tablas cada vez que se inicia el programa.
4. Puede que una de las consultas falle. ¿Qué haces entonces?
Lo más sencillo es crear tu base de datos en un archivo que iría con la distribución del programa, o bien crear las tablas manualmente en el servidor de cada cliente (obviamente sólo sería hacer copias de los archivos correspondientes).
En definitiva, mi consejo es que no crees las tablas en tiempo de ejecución.
Voy a finalizarte esta pregunta para no alargarla más y enseguida te comento mis impresiones sobre tus 4 puntos para que las valores.
Un saludo

Añade tu respuesta

Haz clic para o

Más respuestas relacionadas