2010-10-07 51 views
18

Tengo una tabla user con el campo lastusedecnumber.Cómo bloquear una sola fila

Necesito acceder e incrementar lastusedecnumber.

Durante ese tiempo de acceso necesito bloquear esa fila de usuario en particular (no toda la tabla).

¿Cómo puedo hacer esto?

El tipo de tabla es MyISAM.

+5

[Solo InnoDB tiene bloqueo de fila; MyISAM, MEMORY y MERGE son de nivel de tabla] (http://dev.mysql.com/doc/refman/5.1/en/internal-locking.html) –

+1

Asegúrese de consultar otras preguntas de Stackoverflow con respecto a bloqueos a nivel de fila que se van a Seguro que estás haciendo una elección educada. – belwood

Respuesta

22

MySQL solo utiliza el bloqueo a nivel de tabla de las tablas MyISAM. Si puede, cambie a InnoDB para el bloqueo a nivel de fila.

Aquí hay un enlace al sitio MySQL que describe bloqueos establecidos por sentencias SQL para tablas InnoDB. http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html

+0

¿Funciona ese bloqueo solo para esa transacción o es permanente para toda la base de datos? –

+0

A veces para transacciones, a veces globales. Debe leer y comprender el bloqueo cuidadosamente antes de usarlo. Por ejemplo, hay diferentes tipos de bloqueos, como "bloqueo de lectura global". A veces, los bloqueos se liberan automáticamente en la confirmación, otros pueden liberarse al inicio de una transacción. Sus requisitos deben dictar qué tipo de bloqueo debe usar y cómo usarlo. – belwood

1

Como solución alternativa se podría añadir una columna a la tabla, como locked TINYINT(1) - siempre que lo desee la fila que va a bloquear lo establece en 1. Cuando intente acceder a esta fila, lo primero que debe hacer es verificar si los campos locked están configurados.

Para desbloquear la fila, simplemente ajústela a 0 nuevamente. No es agradable, pero es una solución muy simple.

+0

Si la conexión está cerrada, cierre el navegador, etc. Si se desbloquea automáticamente para otros, creo que no funcionará. ¿Estoy correcto? – svk

+0

No, por supuesto que no. Puede proporcionar un tipo de trabajo que comprueba periódicamente si hay una sesión abierta para el usuario que activó el bloqueo de fila. Por supuesto, debe agregar información de usuario a la tabla. – dhh

+6

Pero esto es como un semáforo defectuoso que no elimina las condiciones de carrera. Si 2 consultas simultáneas piensan 'LOCK = 0', entonces ambas proceden a la sección crítica, _both_ establecen' LOCK = 1', y usted tiene un error de condición de raza oculta. – bobobobo

-1

Una mejor solución consiste en crear una columna que contenga una marca de tiempo. Cuando quiera bloquear la fila, la actualiza a la hora actual. Para desbloquear la actualización a un tiempo al menos x minutos en el pasado. Luego, para verificar si está bloqueado, verifique que la marca de tiempo tenga al menos x minutos de antigüedad.

De esta forma, si el proceso falla (o el usuario nunca completa su operación), el bloqueo expira efectivamente después de x minutos.

+2

No es bueno, ya que la verificación y actualización no es una operación única, esto permite que dos conexiones bloqueen la misma fila sin darse cuenta mutuamente. (Probablemente haya una forma de hacerlo bien, pero sería complejo y fácil perderlo.) – Brilliand

+0

Nunca use el tiempo como sustituto para el bloqueo. –

2

poco tarde, pero espero que ayude a alguien:

UPDATE user SET lastusedecnumber = LAST_INSERT_ID(lastusedecnumber + 1); 
SELECT LAST_INSERT_ID(); 

le dará incremento atómico de lastusedecnumber y la capacidad para leer la nueva lastusedecnumber valor de campo (después de la subasta) usando SELECT LAST_INSERT_ID().

+8

No está claro cómo se relaciona esto con el bloqueo de una fila ... – Brilliand

+0

Esta es una buena sugerencia, ya que le permite actualizar la fila y leer el valor (aunque tal como está escrito actualmente, lee el valor actualizado, en lugar del antiguo uno). Lo que no menciona es que, como es una escritura en la mesa, bloquea toda la tabla mientras actualiza la fila, ya que eso es lo que hace MyISAM, no se puede evitar. – davidsheldon

0

No tenía ganas de convertir mi base de datos completa de myisam. Así que simplemente intento crear una nueva tabla nombrada basada en la identificación del registro que quiero bloquear. Si create table es exitoso, haga mi trabajo y elimine la tabla al final. Si la tabla de creación no es exitosa, deténgase.

Cuestiones relacionadas