Pregunta

Tengo una sencilla tabla con una clave principal. La mayor parte de las operaciones de lectura buscar una fila por el valor exacto de la llave.

Los datos de cada fila mantiene algún tipo de relación con filas antes y después de que en el orden de la clave. Así que cuando inserto una nueva fila Necesito leer las 2 filas entre las que se va a introducir, hacer algo de computación y luego insertar.

La preocupación, claramente, es que al mismo tiempo, otra conexión puede añadir una fila con un valor clave en el mismo intervalo. Estoy cubierto si es exactamente el mismo valor de la clave como el segundo inserto fallaría, pero si el valor de la clave es diferente pero en el mismo intervalo de la relación puede estar roto.

La solución parece ser la de bloquear toda la tabla para escribir cuando decido añadir una nueva fila, o (si es posible, cosa que dudo) para bloquear un intervalo de valores clave. Sin embargo, yo prefiero que las transacciones de sólo lectura no serían bloqueados en ese momento.

Estoy utilizando ODBC con libodbc ++ envoltura para C ++ en el programa cliente y IBM DB2 edición gratuita (aunque la elección de DB todavía puede cambiar). Esto es lo que ocurrió hacer:

  • se inicia la conexión en la auto-entrega y el modo de aislamiento predeterminado
  • cuando es necesario añadir una nueva fila, sistema de auto-entrega a modo de falsas y el aislamiento a serializado
  • leer las filas antes y después de que el nuevo valor de la clave
  • computación e insertar la nueva fila
  • cometer
  • posterior retorno a la auto-entrega y el modo de aislamiento predeterminado

Será esto hacer el trabajo? Se permitirán otras transacciones para leer al mismo tiempo? ¿Hay otras formas mejores de hacerlo /?

Por cierto, no veo en el libodbc ++ i / f una forma de especificar una transacción de sólo lectura. ¿Es posible en ODBC?

Edit: Gracias por las respuestas muy útiles, que tenían una selección de problemas.

¿Fue útil?

Solución

Si su base de datos está en modo SERIALIZABLE, que no tiene ningún problema en absoluto. Dada una clave K, para obtener las claves anterior y siguiente que tiene que ejecutar las siguientes consultas:

select key from keys where key > K order by key limit 1;      # M?
select key from keys where key < K order by key desc limit 1; # I?

Los trabajos anteriores en MySQL. Esta consulta equivalente funciona en DB2 (a partir de los comentarios):

select key from keys where key = (select min(key) from keys where key > K);
select key from keys where key = (select max(key) from keys where key < K);

Los primeros conjuntos de consulta un bloqueo de rango que impide que otras transacciones desde la inserción de una mayor clave de K y menor o igual a M.

Los segundos conjuntos de consulta un bloqueo de rango que impide que otras transacciones desde la inserción de una llave de menos de K y mayor que o igual a I.

El índice único en la clave principal impide K se inserte dos veces. Por lo que está completamente cubierto.

Esto es lo que las transacciones tienen que hacer; para que pueda escribir el código como si toda la base de datos está bloqueado.

Nota: Esto requiere una base de datos que soporta cierto serializabilidad. Afortunadamente, DB2 hace. que el apoyo verdadero serializabilidad otros DBMS: SQL Server, MySQL y / InnoDB. DBMS de que no lo hacen: Oracle, PostgreSQL

Otros consejos

Si su base de datos y el almacenamiento del motor permite que, se debe emitir SELECT FOR UPDATE para ambas filas que están tratando de insertar el medio.

Este conflicto con cualquier SELECT FOR UPDATE concurrente.

El inconveniente es que un bloqueo de filas 10 y 12 (a 11 inserto) también evitará que la selección de 8 y 10 (a 9 inserto).

InnoDB en MySQL También puede colocar una cerradura next-key en el índice, que es bloqueo del registro de índice y la brecha entre el siguiente registro.

En este caso, sería sólo tendrá que emitir una SELECT FOR UPDATE en la primera fila y así insertar simultáneamente una fila antes de eso.

Sin embargo, esto requiere forzar el índice y proporcionar una condición range en el índice que puede o no puede ser posible en función de la consulta.

Su enfoque general es correcta. Sin embargo, se debe utilizar una instrucción SELECT que cubre las dos filas y todas las filas posibles en el medio. Por ejemplo:

SELECT * FROM MYTABLE WHERE PKCOL BETWEEN 6 AND 10

En los sistemas de bases de datos con el bloqueo pesimista y la transacción serializable nivel de aislamiento, esta instrucción SELECT debe impedir nuevas filas a insertar que iba a cambiar el resultado de SELECT.

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