El 27/07/2015 a las 17:10, Alvaro Herrera escribió:
Kernel escribió:
Por lo que veo hay varios casos en los que podemos obtener un deadlock de
estos :
1.- que una transacción t1 necesite que termine la t2 y esta t2 a su vez
necesita que termine t1 para poder terminar, entonces el gestor detecta esto
y elimina la mas antigua (por ejemplo la t1) y devuelve el deadlock en la
t1, y la t2 termina correctamente.
Esto es correcto, excepto que la transacción terminada no es
necesariamente la más antigua, sino la que primero detecta el deadlock.
Si en tu descripción de arriba reemplazas t1+t2 por un conjunto de
varias transacciones las cuales forman un ciclo de relaciones "ti
espera a tj", entonces lo de arriba es una descripción del algoritmo
general.
2.- Empieza la transaccion t1(1) (varios insert en la tabla x), y despues
otro usuario lanza la misma transaccion t1(2), si la t1(1) tarda mucho
tiempo en terminar, el gestor devuelve el deadlock a la t1(1) y asi la t1(2)
se puede comenzar y terminar correctamente
Esta parte no es muy precisa. Una inserción no causa que otras
transacciones se queden esperando. En versiones antiguas podía suceder
si es que había llaves foráneas en las tablas involucradas, pero esto es
algo que hemos ido solucionando paulatinamente, y a menos que involucres
UPDATEs, no deberían ocurrir bloqueos ni deadlocks.
Tengo un proceso de cierre de inventario que puede tardar 10 minutos en
terminar y no quiero que nadie pueda tocar la tabla , ni insertar, ni
modificar.
No tengo clara esta parte. Quizás quieras usar el modo SERIALIZABLE
(transaction isolation).
Había pensado que si pongo 'LOCK TABLE movimientos IN EXCLUSIVE MODE'
y no recibía ningún error, la tabla ya era de uso exclusivo de mi proceso,
que nadie podía molestar a mi proceso y que al resto de procesos debían de
esperar para iniciarse o les daría un error al iniciar, pero mi sorpresa es
que mi proceso recibe un deadlock y el resto termina bien.
Seguramente tu proceso necesita examinar otras tablas.
Yo creo que deberías hacer que tu proceso de clausura no requiera que no
se inserten movimientos nuevos, sino sólo que no se inserten movimientos
anteriores al timestamp del cierre.
En le proceso de cierre trabajo con dos tablas ,
una que inserta en la tabla de movimientos un regitro por articulo,
almacen y otra en la que detallo contenedores y lotes
movimientos
...
id serial, (primary key)
id_articulo integer,
id_almacen integer,
fecha date,
unidades numeric
.....
contenedores
....
id serial, (primary key)
id_movimientos integer, (foreign key de movimientos)
id_contenedor integer,
id_lote integer,
unidades integer
como tengo que hacer todos los articulos y sus contenedores hago esto
BEGIN
LOCK TABLE movimientos IN EXCLUSIVE MODE
LOCK TABLE contendores IN EXCLUSIVE MODE
cursor con las sumas hasta la fecha por articulo, almacen
inserto en movimientos ...
cursor con los contenedores
inserto los contenedores
end cursor
end cursor
COMMIT
Si alguien intenta meter un movimiento es cuando me da el deadlock.
No se si el problema esta en los campos SERIAL.
Podría hacer un begin por cada articulo, pero la verdad es que prefería
hacerlo para todos.
-
Enviado a la lista de correo pgsql-es-ayuda (pgsql-es-ayuda@postgresql.org)
Para cambiar tu suscripción:
http://www.postgresql.org/mailpref/pgsql-es-ayuda