Considere un sitio de comercio electrónico, donde Alice y Bob están editando las listas de productos. Alice está mejorando las descripciones, mientras que Bob está actualizando los precios. Comienzan a editar Acme Wonder Widget al mismo tiempo. Bob termina primero y guarda el producto con el nuevo precio. Alice tarda un poco más en actualizar la descripción, y cuando termina, guarda el producto con su nueva descripción. Desafortunadamente, ella también sobrescribe el precio con el precio anterior, que no estaba previsto.
En mi experiencia, estos problemas son extremadamente comunes en las aplicaciones web. Algunos programas (p. Ej., Software wiki) tienen protección contra esto; por lo general, el segundo guardado falla con "la página se actualizó mientras estaba editando". Pero la mayoría de los sitios web no tienen esta protección.
Vale la pena señalar que los métodos del controlador son seguros para subprocesos en sí mismos. Usualmente usan transacciones de bases de datos, lo que las hace seguras en el sentido de que si Alice y Bob intentan ahorrar en el mismo momento preciso, no causarán corrupción. La condición de carrera surge de que Alice o Bob tienen datos obsoletos en su navegador.
¿Cómo podemos prevenir tales condiciones de carrera? En particular, me gustaría saber:
- ¿Qué técnicas se pueden usar? por ejemplo, rastrear el tiempo del último cambio Cuáles son los pros y los contras de cada uno.
- ¿Qué es una experiencia útil para el usuario?
- ¿En qué marcos se ha incorporado esta protección?
fuente
Respuestas:
Debe "leer sus escritos", lo que significa que antes de escribir un cambio, debe leer el registro nuevamente y verificar si se realizaron cambios desde la última vez que lo leyó. Puede hacer esto campo por campo (de grano fino) o en base a una marca de tiempo (de grano grueso). Mientras realiza esta comprobación, necesita un bloqueo exclusivo en el registro. Si no se realizaron cambios, puede escribir sus cambios y liberar el bloqueo. Si el registro ha cambiado mientras tanto, cancela la transacción, libera el bloqueo y notifica al usuario.
fuente
He visto 2 formas principales:
Agregue la marca de tiempo de la última actualización de la página que el uso está editando en una entrada oculta. Al confirmar, la marca de tiempo se compara con la actual y si no coinciden, otra persona la ha actualizado y devuelve un error.
pro: múltiples usuarios pueden editar diferentes partes de la página. La página de error puede conducir a una página de diferencias donde el segundo usuario puede fusionar sus cambios en la nueva página.
contra: a veces se desperdician grandes partes del esfuerzo durante grandes ediciones simultáneas.
Cuando un usuario comienza a editar la página, bloquéela durante un período de tiempo razonable, cuando otro usuario intente editar, recibirá una página de error y tendrá que esperar hasta que el bloqueo caduque o el primer usuario se haya comprometido.
pro: los esfuerzos de edición no se desperdician.
con: un usuario sin escrúpulos puede bloquear una página indefinidamente. Una página con un bloqueo caducado aún puede comprometerse a menos que se trate de otra manera (utilizando la técnica 1)
fuente
Utilizar control de simultaneidad optimista .
Agregue una columna versionNumber o versionTimestamp a la tabla en cuestión (el entero es el más seguro).
El usuario 1 lee el registro:
El usuario 2 lee el registro:
El usuario 1 guarda el registro, esto incrementa la versión:
El usuario 2 intenta guardar el registro que leen:
Hibernate / JPA puede hacer esto automáticamente con el
@Version
anotaciónDebe mantener el estado del registro de lectura en algún lugar, generalmente en sesión (esto es más seguro que en una variable de forma oculta).
fuente
SQLAlchemy
no apunta a nada sobre bloqueos optimistas fuera de línea, y no puedo encontrarlo en los documentos. ¿Tenía un enlace más útil o simplemente señalaba a las personas en SQLAlchemy en general?Algunos sistemas de Mapeo Relacional de Objetos (ORM) detectarán qué campos de un objeto han cambiado desde que se cargaron desde la base de datos, y construirán la declaración de actualización de SQL para establecer solo esos valores. ActiveRecord para Ruby on Rails es uno de esos ORM.
El efecto neto es que los campos que el usuario no cambió no están incluidos en el comando ACTUALIZACIÓN enviado a la base de datos. Las personas que actualizan diferentes campos al mismo tiempo no sobrescriben los cambios de los demás.
Según el lenguaje de programación que esté utilizando, investigue qué ORM están disponibles y vea si alguno de ellos solo actualizará las columnas de la base de datos marcadas como "sucias" en su aplicación.
fuente