No. CouchDB utiliza un modelo de "concurrencia optimista". En los términos más simples, esto solo significa que envía una versión del documento junto con su actualización, y CouchDB rechaza el cambio si la versión actual del documento no coincide con lo que envió.
Es engañosamente simple, de verdad. Puede replantear muchos escenarios normales basados en transacciones para CouchDB. Sin embargo, es necesario descartar su conocimiento del dominio RDBMS al aprender CouchDB. Es útil abordar los problemas desde un nivel superior, en lugar de intentar adaptar Couch a un mundo basado en SQL.
Seguimiento del inventario
El problema que describió es principalmente un problema de inventario. Si tiene un documento que describe un artículo e incluye un campo para "cantidad disponible", puede manejar problemas de simultaneidad como este:
- Recupere el documento, tome nota de la
_rev
propiedad que envía CouchDB
- Disminuir el campo de cantidad, si es mayor que cero
- Devuelva el documento actualizado, utilizando la
_rev
propiedad
- Si
_rev
coincide con el número almacenado actualmente, ¡listo!
- Si hay un conflicto (cuando
_rev
no coincide), recupere la versión más reciente del documento
En este caso, hay dos posibles escenarios de falla en los que pensar. Si la versión más reciente del documento tiene una cantidad de 0, lo maneja como lo haría en un RDBMS y alerta al usuario de que en realidad no puede comprar lo que quería comprar. Si la versión más reciente del documento tiene una cantidad mayor que 0, simplemente repita la operación con los datos actualizados y comience desde el principio. Esto le obliga a hacer un poco más de trabajo que lo que haría un RDBMS, y podría resultar un poco molesto si hay actualizaciones frecuentes y conflictivas.
Ahora, la respuesta que acabo de dar presupone que va a hacer las cosas en CouchDB de la misma manera que lo haría en un RDBMS. Podría abordar este problema de manera un poco diferente:
Comenzaría con un documento de "producto maestro" que incluye todos los datos del descriptor (nombre, imagen, descripción, precio, etc.). Luego agregaría un documento de "ticket de inventario" para cada instancia específica, con campos para product_key
y claimed_by
. Si usted está vendiendo un modelo de martillo, y tienen 20 de ellos para vender, es posible que tenga documentos con teclas como hammer-1
, hammer-2
, etc., para representar cada martillo disponibles.
Luego, crearía una vista que me da una lista de martillos disponibles, con una función de reducción que me permite ver un "total". Estos están completamente fuera de lugar, pero deberían darle una idea de cómo se vería una vista de trabajo.
Mapa
function(doc)
{
if (doc.type == 'inventory_ticket' && doc.claimed_by == null ) {
emit(doc.product_key, { 'inventory_ticket' :doc.id, '_rev' : doc._rev });
}
}
Esto me da una lista de "tickets" disponibles, por clave de producto. Podría tomar un grupo de estos cuando alguien quiera comprar un martillo, luego repetir el envío de actualizaciones (usando id
y _rev
) hasta que reclame con éxito uno (los boletos reclamados anteriormente darán como resultado un error de actualización).
Reducir
function (keys, values, combine) {
return values.length;
}
Esta función de reducción simplemente devuelve el número total de inventory_ticket
artículos no reclamados , para que pueda saber cuántos "martillos" están disponibles para su compra.
Advertencias
Esta solución representa aproximadamente 3,5 minutos de pensamiento total para el problema particular que ha presentado. ¡Puede haber mejores formas de hacer esto! Dicho esto, reduce sustancialmente las actualizaciones en conflicto y reduce la necesidad de responder a un conflicto con una nueva actualización. Bajo este modelo, no tendrá varios usuarios intentando cambiar datos en la entrada del producto principal. En el peor de los casos, tendrá varios usuarios intentando reclamar un solo boleto, y si ha tomado varios de ellos desde su vista, simplemente pase al siguiente boleto e intente nuevamente.
Referencia: https://wiki.apache.org/couchdb/Frequency_asked_questions#How_do_I_use_transactions_with_CouchDB.3F