es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo puedo garantizar que una inserción en lote de JDBC se realice de forma atómica?

Tengo el siguiente código (pseudoish) para insertar ~5000 filas en una tabla de SQL Server. Estoy usando Hikari (el código ds que se muestra a continuación es mi HikariDataSource).

try (Connection connection = ds.getConnection();
     PreparedStatement statement = connection.prepareStatement(
          "insert into Dog (name, age, breed) values (?, ?, ?)");) {


        for (Dog d : dogs) {
            statement.setString(1, d.getName());
            statement.setInt(2, d.getAge());
            statement.setString(3, d.getBreed());
            statement.addBatch();
         }

         statement.executeBatch();
} 
// capturar excepciones, etc.

Esto funciona correctamente (en el sentido de que las inserciones funcionan como se esperaba), pero si alguien consulta la tabla en medio de la inserción por lotes (que lleva unos segundos), puede obtener un conjunto incompleto de filas. Quiero que obtengan nada (suponiendo que la tabla esté vacía al principio) o todas las filas que inserto.

Supongo que necesito hacer algo especial para bloquear la tabla o realizar todas las inserciones como una transacción única (asumí que eso era lo que hacía la inserción por lotes, pero estaba equivocado).

¿Cómo puedo hacer esto?

Tags:  , , ,

Answer

  1. Avatar for davy.ai

    Para asegurarse de que todas las inserciones se realicen como una única transacción, puede envolver todo el bloque de código en una transacción. Puede hacer esto creando un objeto de transacción a partir de la conexión y configurando la propiedad de autocommit en falso.

    Después de la inserción por lotes, puede confirmar la transacción. Esto garantiza que se inserten todas las filas o ninguna. Además, mientras la transacción esté en progreso, cualquier consulta a la tabla quedará bloqueada hasta que se confirme o se revierta la transacción.

    El código modificado se vería así:

    “`
    try (Connection connection = ds.getConnection()) {
    connection.setAutoCommit(false); // establecer autocommit en falso para habilitar la transacción

    try (PreparedStatement statement = connection.prepareStatement(
               "insert into Dog (name, age, breed) values (?, ?, ?)")) {
    
        for (Dog d : dogs) {
            statement.setString(1, d.getName());
            statement.setInt(2, d.getAge());
            statement.setString(3, d.getBreed());
            statement.addBatch();
        }
    
        statement.executeBatch();
        connection.commit(); // confirmar transacción
    } catch (SQLException e) {
        connection.rollback(); // revertir transacción en caso de excepción
        // manejar excepción
    }
    

    } catch (SQLException e) {
    // manejar excepción
    }

    Con esta modificación, cualquier consulta a la tabla esperará a que la transacción se complete antes de devolver resultados, asegurando que se inserten todas las filas o ninguna.

Comments are closed.