PostgreSQL - Detectar registro bloqueado en Postgres

 
Vista:

Detectar registro bloqueado en Postgres

Publicado por Fritos (3 intervenciones) el 10/02/2003 12:42:30
Hola,

Estoy trabajando con un proyecto desarrollado en Java y trabajando con transacciones, y no sé como detectar si un registro de una tabla de una base de datos Postgres está bloqueado por otro usuario.

Un usuario hace un "SELECT .... FOR UPDATE" y mientras no lo modifica y lo mantiene abierto, cualquier otro usuario que haga el mismo "SELECT ... FOR UPDATE" se queda esperando a que el anterior usuario acabe de modificarlo y cierre la transacción.

Lo que quiero saber es como detectar que ese registro está bloqueado cuando hago el SELECT y darle un mensaje de información, yno que se me quede esperando a que el otro finalice la transacción.

Muchas gracias.
Valora esta pregunta
Me gusta: Está pregunta es útil y esta claraNo me gusta: Está pregunta no esta clara o no es útil
0
Responder

RE:Detectar registro bloqueado en Postgres

Publicado por David Pinelo (82 intervenciones) el 12/02/2003 13:54:17
Hola!,

No estoy muy seguro pero creo que no hay forma de detectar el bloqueo. Es decir, en una transacción, esta se quedaría esperando indefinidamente la liberación del registro para completarla y corresponde a la utilidad cliente la cancelación si la operación tarda demasiado. Pero ya te digo, no estoy seguro. Si supieras si hay algún modo de detectarlo, por favor, dínoslo! ;-)

Saludos,
David
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Con un semaforo

Publicado por Fritos (3 intervenciones) el 12/02/2003 14:57:36
Hola David,

Despues de mucho buscar, probar.. etc.. hemos llegado a la conclusión de que no se puede. Finalmente hemos optado por la opcion del semáforo (o flag, o chivato..).
Hemos creado un campo Estado en cada tabla, y cuando alguien lee un registro, modificamos es campo a false, y cuando acaba la modificacion, lo volvemos a poner a true.
De este modo, antes de coger un registro, primero comprobamos que el campo sea true, en caso de que sea false se muestra el mensaje de que alguien lo esta modificando.

Otra manera, un poco mas arcaica pero tambien te saca de apuros.. es antes de leer el fichero, mostrar un mensaje diciendo que el registro está siendo modificado. En caso de que no lo esté, al momento saldrá otra pantalla, pero en caso de que este bloqueado por otro usuario se quedará en pantalla ese mensaje hasta que el otro lo desbloquee.

Un saludo!
Fritos
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

RE:Con un semaforo

Publicado por David Pinelo (82 intervenciones) el 12/02/2003 18:14:29
Ajah, un semáforo. Pero debeis tener en cuenta una cosa. Si es una base de datos en producción con muchos accesos concurrentes, y se realizan transacciones para realizar operaciones sobre los datos, puede ocurrir lo siguiente:
- Un usuario (1) quiere modificar un registro, para lo que inicia una transacción (aquí es donde tendríais el problema), y pone estado=false. Y se pone a modificar.
- Otro usuario (2) solicita, en el mismo momento en el q el primer usuario inicia la transaccion, el mismo registro para modificarlo (esto puede ocurrir, si como he dicho hay mucha concurrencia), y este usuario lee estado=true (aun no ha terminado la transacción el usuario 1 y por tanto no ha puesto estado=false aun).
- Usuario (2) inicia una transaccion para poner estado=false (pq él lo ha visto true). Cuando usuario (1) termine la transacción q pone estado=false, usuario (2) realiza su transaccion poniendo estado=false.

Teneis así dos usuarios que creen pueden modificar el mismo registro a la misma vez, con la posibilidad de machacar datos. Se producen condiciones de carrera (¿se llamaba así?).
Espero haberme explicado bien.
Un saludo!
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Probad con Transaction Isolation

Publicado por Fritos (3 intervenciones) el 12/02/2003 18:26:06
Te he entenido perfectamente.
En nuestro caso no habra mucha concurrencia ya que es para el mantenimiento de unos precios en una tienda, y.. como mucho habra 2 o 3 personas que lo hagan a la vez. En teoria solo habra un encargado de hacerlo, pero podria ser que fueran 2 o 3.. no mas, por lo que no nos hemos preocupado mucho

Igualmente, te comento que hay diferentes tipos de Transacciones. Yo he buscado informacion pero como no era lo que necesitabamos, no le he parado mucha atencion. Se llama "Transaction Isolation" y hay 4 o 5 tipos diferentes. El postgres solo soporta dos, pero.. nose.. alomejor os sirve de algo.

Te paso esta direccion por si lo quieres mirar :

http://www.ctv.es/USERS/pagullo/arti/jdbc2/jdbc2.htm

En java se usa el metodo setTransactionIsolation en el objeto Connection.

Un Saludo!
Fritos
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar

Metodo

Publicado por PABLO MAXIMILIANO (1 intervención) el 20/10/2014 01:06:28
Quiero aportar una idea que uso y que me funciona. Lo que yo hago es bloquear la base enteramente cuando se tratan de escrituras. Para controlar el bloqueo uso un semaforo pero añado un mecanismo que usa un numero aleatorio (de varios digitos pero q usted puede hacerlo mas grande para q sea mas seguro pero no es necesario). La idea de mantener un semaforo que lei en el post anterior es buena pero existe la posibilidad de que 2 usuarios lean el semaforo al mismo tiempo. Para minimizar aun mas esta posibilidad uso la funcion (abajo escrita) de bloquear la base, y luego la desbloqueo para q los demas tengan acceso a escribir. En el peor de los casos que se corte la energia cuando graba se queda bloqueada la base solo seria cuestion de desfloquearla manualmente (update) para poner a FALSE el valor del campo "bloq_bloqueo".
La logica es la siguiente para leer y actualizar el registro q uso para bloqueos: El procedimiento q bloquea lo q hace es actualizar el valor random que esta en la tabla bloqueo, lo actualiza una vez y luego vuelve a actulizarlo pero si encuentra q es el mismo valor q actualizo en el paso anterior entonces graba el valor TRUE en el registro bloq_bloqueo, y si encuentra q el valor cambio quiere decir q hay otro que gano su turno y sigue el bucle hasta q lea 1 vez el valor que haya puesto en el paso anterior; todo esto pasa en milesimas de segundo por tanto no hay tiempos de espera que el usuario pueda notar. Se preguntaran si es posible q 2 usuarios puedan obtener un mismo numero random y entrar al mismo tiempo, bueno es dificil pero para eso tmb se puede agregar al metodo el ip del usuario para q ya sea imposible q pase eso. El procedimiento funciona bien, pero tal vez se pueda mejorar obviamente:

BASE DE DATOS POSTGRESQL:

CREATE TABLE bloqueo
(
bloq_random character(10),
bloq_usuario integer,
bloq_fecha character(21),
bloq_bloqueo boolean
)
WITH (
OIDS=FALSE
);
ALTER TABLE bloqueo
OWNER TO postgres;
GRANT ALL ON TABLE bloqueo TO postgres;
GRANT ALL ON TABLE bloqueo TO public;

EN VISUAL BASIC NET:

Public Sub Esperar_y_Bloquear_PostgreSQL()
Randomize()
Bloqueo_Random = Int((2147483647 * Rnd()) + 1)
Bloqueo_Fecha = Date.Today.ToShortDateString & " " & Date.Today.ToShortTimeString
Leer: If dsPostgreSQL.Tables.Contains("bloqueo") = True Then dsPostgreSQL.Tables("bloqueo").Clear()
cmdPostgreSQL.CommandText = "update bloqueo set bloq_random='" & Bloqueo_Random.ToString & "', bloq_usuario=" & Usuario_Id & ", bloq_fecha='" & Bloqueo_Fecha & "' where bloq_bloqueo=False"
cmdPostgreSQL.ExecuteNonQuery()
cmdPostgreSQL.CommandText = "update bloqueo set bloq_bloqueo=True where bloq_random='" & Bloqueo_Random.ToString & "' and bloq_usuario=" & Usuario_Id & " and bloq_fecha='" & Bloqueo_Fecha & "'"
cmdPostgreSQL.ExecuteNonQuery()
cmdPostgreSQL.CommandText = "select * from bloqueo"
daPostgreSQL.Fill(dsPostgreSQL, "bloqueo")
If dsPostgreSQL.Tables("bloqueo").Rows(0).Item("bloq_bloqueo") = False _
Or Trim(dsPostgreSQL.Tables("bloqueo").Rows(0).Item("bloq_random")) <> Trim(Bloqueo_Random.ToString) _
Or dsPostgreSQL.Tables("bloqueo").Rows(0).Item("bloq_usuario") <> Usuario_Id _
Or Trim(dsPostgreSQL.Tables("bloqueo").Rows(0).Item("bloq_fecha")) <> Trim(Bloqueo_Fecha) Then
GoTo Leer
End If
End Sub

Public Sub Desbloquear_PostgreSQL()
cmdPostgreSQL.CommandText = "update BLOQUEO set bloq_bloqueo=False"
cmdPostgreSQL.ExecuteNonQuery()
End Sub
Valora esta respuesta
Me gusta: Está respuesta es útil y esta claraNo me gusta: Está respuesta no esta clara o no es útil
0
Comentar