2012-04-23 15 views
6

Creo que debe haber algo básico que no entiendo sobre el bloqueo de avisos en postgres. Si entro en los siguientes comandos en el cliente de línea de comandos psql, la función retorna verdadero en ambas ocasiones:Adquirir bloqueos de aviso en postgres

SELECT pg_try_advisory_lock(20); --> true 
SELECT pg_try_advisory_lock(20); --> true 

yo esperaba que el segundo mandato debe devolver falso, ya que la cerradura ya debería haber sido adquirida. Curiosamente, me pongo el siguiente, lo que sugiere que el bloqueo ha sido adquirida en dos ocasiones:

SELECT pg_advisory_unlock(20); --> true 
SELECT pg_advisory_unlock(20); --> true 
SELECT pg_advisory_unlock(20); --> false 

así que supongo que mi pregunta es, ¿Cómo se adquiere un bloqueo de asesoramiento de una manera que deja que se adquiere de nuevo?

+8

Desde la misma sesión puede adquirir el mismo candado todas las veces que quiera; pero debe liberarlo la misma cantidad de veces o cerrar la sesión antes de que otra sesión pueda adquirir el bloqueo. – kgrittn

Respuesta

11

¿Qué pasa si intentas hacer esto desde las 2 sesiones diferentes de PostgreSQL?

Eche un vistazo a más in the docs.

+2

Ah veo, así que una vez que una sesión ha adquirido un bloqueo, puede adquirirlo nuevamente, pero otra sesión no puede. ¡Gracias! – foldl

3

Mi primera impresión en los bloqueos de aviso fue similar. Esperaba que la segunda consulta (SELECT pg_tryadvisory_lock (20)) también devuelva falso (porque el primero obtuvo el bloqueo). Pero esta consulta solo confirmó que un bigInt con valor 20 tiene un bloqueo. La interpretación depende del usuario.

Imagine los bloqueos de aviso como una tabla donde puede almacenar un valor y obtener un bloqueo en ese valor (normalmente un BigInt). No es un bloqueo explícito y ninguna transmisión se retrasará. Depende de usted cómo interpretar y usar el resultado, y no está bloqueando.

Lo uso en mis proyectos con las opciones de dos enteros. SELECCIONE pg_try_advisory_lock (classId, objId) mientras que ambos parámetros son enteros.

Para que funcione con más de una tabla sólo tiene que utilizar el OID de la tabla como classId y el ID de primaria (en este caso 17) como ObjID:

SELECT pg_try_advisory_lock((SELECT 'first_table'::regclass::oid)::integer, 17);

En este ejemplo "primera_tabla" es el nombre de la tabla y el segundo entero es la identificación de la clave principal (aquí: 17).

El uso de un parámetro BigInt como permite un rango más amplio de identificadores, pero si lo usa con "second_table", el id 17 también se bloqueará (porque bloqueó el número "17" y no la relación con una fila específica en una mesa).

Me tomó un tiempo darme cuenta de eso, así que espero que ayude a entender el funcionamiento interno de los bloqueos de aviso.

+0

No entendí esto ... mencionas 'pero si lo usas con" second_table "que el id 17 también está bloqueado' ¿cómo es que id 17 estaría bloqueado en el caso anterior con el siguiente bloqueo de aviso cuando utilizo la siguiente consulta 'SELECT pg_try_advisory_lock ((SELECT 'first_table' :: regclass :: oid) :: integer, 17);' – Viren