Pregunta

Necesito ejecutar una selección y luego actualizar algunas de las filas en el ResultSet de forma atómica.

El código que estoy utilizando parece (simplificado):

stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("SELECT ...");

while (rs.next()) {
    if (conditions_to_update) {
        rs.updateString(...);
        rs.updateRow();
    }
}
  • ¿Puedo garantizar que las actualizaciones se ejecutarán de forma atómica? Si no, ¿cómo podría asegurar eso?
  • ¿Qué sucede si cualquier otro proceso ha cambiado la fila de la base de datos que está actualizando a través de updateRow () ? ¿Hay alguna forma de bloquear las filas en el ResultSet ?
¿Fue útil?

Solución

Probablemente hay una gran cantidad de tecnologías y conceptos que entran en juego aquí, y las cosas comienzan a ponerse un poco complicadas cuando comienzas a considerar aplicaciones de multihebra / solicitud múltiple.

Como dijo Iassevk, debería considerar el uso de Transactions para garantizar la naturaleza atómica de sus actualizaciones: un ejemplo de muy bajo nivel sería hacer algo como:

...
con.setAutoCommit(false);
try {
  while (rs.next()) {
    if (conditions_to_update) {
      rs.updateString(...);
      rs.updateRow();
    }
  }
  con.setAutoCommit(true);
} catch (Exception ex) {
  //log the exception and rollback
  con.rollback();
} finally {
  con.close();
}

Todas las actualizaciones se agruparán en la misma transacción. Si alguna de las actualizaciones generara una Excepción (como un valor no válido o la conexión fallada en la mitad de los resultados), el lote completo se revertiría. (Finalmente añadido porque soy un campeón de la misma; p)

Sin embargo, esto no solucionará su segundo problema, que consiste en dos métodos en competencia que intentan actualizar la misma tabla: una condición de carrera. Hay, en mi opinión, dos enfoques principales aquí: cada uno tiene sus méritos e inconvenientes.

El enfoque más sencillo sería Bloquea la tabla - esto requeriría cambios mínimos de código pero tiene un inconveniente bastante grande. Trabajando en el supuesto de que, al igual que con la mayoría de las aplicaciones, es más leído que escribir: el bloqueo de la tabla evitará que todos los demás usuarios vean los datos, con la probabilidad de que el código se bloquee, esperando a que el bloqueo se libere antes de que se agote el tiempo de conexión. patea y lanza una excepción.

El enfoque más complejo es garantizar que los métodos para realizar estas actualizaciones se implementen de manera segura para subprocesos. Para ello:

  • Todas las actualizaciones para esta tabla pasan a través de una sola Clase
  • Esa clase implementa un patrón Singleton, o expone los métodos de actualización como métodos estáticos
  • Los métodos de actualización utilizan la Sincronizado palabra clave para prevenir condiciones de carrera

Otros consejos

Utilizar transacciones.

  

¿Qué sucede si cualquier otro proceso ha cambiado la fila de la base de datos que está actualizando a través de updateRow ()? ¿Hay alguna forma de bloquear las filas en el ResultSet?

En Oracle, puedes marcar un poco ciertas filas para actualizar emitiendo el siguiente SQL.

select cola, colB from tabA for update;

La siguiente transacción / hilo / aplicación que intenta actualizar esta fila obtendrá una excepción. vea esto para obtener más detalles, http://asktom.oracle.com/pls/asktom/f?p=100:11:0:::P11_QUESTION_ID:4530093713805

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top