2012-06-30 36 views
7

Tengo un sitio web donde los usuarios pueden comprar boletos, pero las cantidades de boletos suelen ser limitadas y van rápidamente. Estoy tratando de implementar un sistema de depósito en garantía de manera que un usuario pueda hacer clic en que quiere x número de boletos, y en ese momento los pondré en un estado de depósito en garantía. Eso les da varios minutos para ingresar la información de su tarjeta de crédito y completar la compra.Operaciones atómicas MySQL y bloqueo de tabla

Tengo tres tablas relevantes: eventos, boletos y fideicomiso. Una fila en la tabla de eventos describe el evento en sí, incluida la cantidad máxima de tickets disponibles.

La mesa de entradas sostiene lo siguiente:

user_id: el usuario que compró las entradas

number_of_tickets: ¿cuántos billetes se compran

event_id: el evento relevante

La tabla de depósito en garantía contiene lo siguiente:

user_id: el usuario en el proceso de compra de billetes

number_of_tickets: cuántas entradas que quieren

event_id: el evento relevante

Actualmente, hago tres MySQL consultas, una para las entradas máximas, una para el número de boletos vendidos y una para el número de boletos que ya están en custodia. Entonces calculo:

$remaining_tickets = $max_tickets - $tickets_sold - $tickets_in_escrow; 
if ($remaining_tickets >= $tickets_desired) 
{ 
    beginEscrow($user_id, $event_id, $tickets_desired); 
} 
else 
{ 
    echo "Error: not enough ticket remain."; 
} 

Mi problema es que es posible que más de un usuario a ser la ejecución de este código a la vez. Si un usuario fuera a llamar al beginEscrowdespués de otro usuario ya había leído el número de boletos que ya estaban en custodia, es posible que venda el programa en exceso.

Estoy usando el motor InnoDB para mis tablas, y he leído cómo bloquear una sola fila usando SELECT .... FOR UPDATE, pero no estoy actualizando una sola fila. La función beginEscrow simplemente insertará una nueva fila en la tabla de custodia. Calculo $tickets_in_escrow leyendo todas las filas con la identificación de evento correcta y sumando el número de tickets en cada una de ellas.

Tal vez estoy haciendo todo mal?

¿Debo bloquear toda la tabla?

No puedo ser el primero en escribir un sistema de fideicomiso de boletos. Me busqué en la red tratando de encontrar algún tutorial sobre este tipo de cosas, pero me pongo nervioso. Cualquier idea sería útil.

Gracias!

Respuesta

9

Estás muy cerca de tu diseño, pero no del todo.

En primer lugar, su tabla de eventos debe contener la cantidad de boletos disponibles para su evento (además de cualquier otra cosa que desee).

En segundo lugar, su tabla de depósito en garantía debe tener una columna DATETIME que indique cuándo vence el depósito de garantía. Debes establecer ese valor siempre que los boletos ingresen en custodia.

En tercer lugar, la operación de poner las entradas en depósito necesita

  1. bloquear la fila evento.
  2. lea la columna de entradas disponibles. (abortar si no hay suficientes disponibles)
  3. inserte una fila en la tabla de custodia
  4. actualice la fila del evento para disminuir la columna de tickets disponibles.
  5. desbloquea la fila del evento.

En cuarto lugar, la acción de completar la venta debe eliminar la fila de custodia e insertar una fila de boleto vendido. Esto no es difícil.

En quinto lugar, necesita una operación de limpieza de depósito en garantía. Esto tiene que buscar todas las filas de plica que han caducado (que tienen una fecha de caducidad en el pasado) y, para cada uno:

  1. bloquear la fila evento correspondiente.
  2. lea el número de boletos custodiados de la mesa de custodia
  3. borre la fila de la tabla de custodia.
  4. actualice la fila del evento para incrementar la columna de tickets disponibles.
  5. desbloquea la fila del evento.

El truco es tener el número de entradas disponibles mantenidos de una manera que está enclavado correctamente, por lo que las condiciones de carrera entre los usuarios no exagerar su evento.

+0

Por lo tanto, en otras palabras, todo el conteo de los tickets en custodia debe estar en una sola fila en una sola tabla, en lugar de una suma de las filas en la tabla de custodia. Veo cómo eso tiene sentido. Gracias. – user1493634

+0

En realidad, todo el conteo de boletos, disponible, en depósito y vendido, debe estar en una sola columna de una sola fila en una sola tabla. Esa columna llega a cero, no hay más asientos para vender. Pero tienes la idea. –

+0

En StackOverflow, si una respuesta lo ayuda, debe aceptarlo haciendo clic en la marca de verificación verde. –

Cuestiones relacionadas