Puedo hacer las transacciones y bloqueos en CouchDB?

Necesito para hacer las transacciones (begin, commit o rollback), bloqueos (select for update).
Cómo puedo hacer que en un documento de modelo de base de datos?

Edición:

El caso es este:

  • Quiero ejecutar un sitio de subastas.
  • Y pienso cómo directa compra así.
  • En una compra directa tengo para disminuir la cantidad de campo en el registro de artículo, pero sólo si la cantidad es mayor que cero. Es por eso que necesito bloqueos y transacciones.
  • No sé cómo a la dirección que sin bloqueos y/o transacciones.

Puedo solucionar esto con CouchDB?

InformationsquelleAutor user2427 | 2008-11-18

7 Kommentare

  1. 139

    No. CouchDB utiliza una «simultaneidad optimista» del modelo. En términos más simples, esto significa que usted envíe una versión de documento, junto con su actualización, y CouchDB rechaza el cambio, si la actual versión del documento no coincide con lo que usted ha enviado.

    Es engañosamente simple, realmente. Usted puede replantear muchos de la operación normal basado en escenarios para CouchDB. Usted no necesita una especie de lanzar fuera de su RDBMS el conocimiento de un dominio cuando el aprendizaje de CouchDB, aunque. Es útil para el planteamiento de problemas a partir de un nivel superior, en lugar de intentar molde Sofá a un SQL basado mundo.

    Realizar un seguimiento del inventario

    El problema descrito es principalmente un inventario problema. Si usted tiene un documento que describe un elemento, e incluye un campo de «cantidad», usted puede manejar los problemas de concurrencia como este:

    1. Recuperar el documento, tomar nota de la _rev propiedad que CouchDB envía a lo largo de
    2. Disminuir la cantidad de campo, si es mayor que cero
    3. Enviar el documento actualizado de nuevo, usando la _rev propiedad
    4. Si el _rev coincide con el número almacenado en la actualidad, se puede hacer!
    5. Si hay un conflicto (cuando _rev no coincide), recuperar la más reciente versión de documento

    En este ejemplo, hay dos posibles escenarios de error pensar. Si el documento más reciente versión tiene una cantidad de 0, se manejan igual que en un RDBMS y alerta al usuario de que ellos en realidad no pueden comprar lo que quería comprar. Si el documento más reciente versión tiene una cantidad mayor que 0, simplemente repita la operación con los datos actualizados, y comenzar nuevamente desde el principio. Esto te obliga a hacer un poco más de trabajo que de un RDBMS podría obtener un poco molesto si no son muy frecuentes, las actualizaciones conflictivas.

    Ahora, la respuesta que me dio supone que vamos a hacer las cosas en CouchDB en mucho la misma manera que lo haría en un RDBMS. Yo podría abordar este problema de una manera diferente:

    Me gustaría empezar con un «maestro de productos» documento que incluye todos los datos de los descriptores (nombre, imagen, descripción, precio, etc). A continuación, me gustaría añadir un «inventario de entradas» documento para cada caso específico, con campos para product_key y claimed_by. Si usted está vendiendo un modelo de martillo, y tienen más de 20 de ellos para vender, usted puede tener documentos con claves como hammer-1, hammer-2, etc, para representar a cada una de martillo.

    A continuación, me gustaría crear una vista que me da una lista de martillos, con una reducción de la función que me permite ver un «total». Estos son totalmente sacado de la manga, pero debe darle una idea de lo que es una vista de trabajo se vería.

    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 las «entradas», por clave de producto. Podría agarrar un grupo de estos, cuando alguien quiere comprar un martillo, a continuación, recorrer el envío de actualizaciones (el uso de la id y _rev) hasta que he conseguido que afirman que uno (anteriormente decía entradas resultará en un error de actualización).

    Reducir

    function (keys, values, combine) {
        return values.length;
    }
    

    Este reducir función simplemente devuelve el número total de no reclamados inventory_ticket elementos, así que usted puede decir cómo muchos de los «martillos» están disponibles para la compra.

    Advertencias

    Esta solución representa aproximadamente 3,5 minutos del total de pensamiento para el problema en particular que usted ha presentado. Puede haber mejores maneras de hacer esto! Dicho esto, no reducir sustancialmente las actualizaciones conflictivas, y reduce la necesidad de responder a un conflicto con una nueva actualización. Bajo este modelo, que no tenga varios usuarios al intentar cambiar los datos en la principal entrada de producto. En el peor de los casos, usted tendrá múltiples usuarios que reclamaban un solo billete, y si has agarraron a varios de aquellos que desde su punto de vista, simplemente pasar a la siguiente ticket e inténtelo de nuevo.

    Referencia: https://wiki.apache.org/couchdb/Frequently_asked_questions#How_do_I_use_transactions_with_CouchDB.3F

    • No es claro para mí por qué los «billetes» que intenta reclamar en la secuencia es una mejora significativa con respecto a simplemente volver a intentar la lectura/modificar/escritura para la actualización del maestro de la entidad. Ciertamente no parece que vale la pena la sobrecarga adicional, especialmente si usted tiene grandes cantidades de stock.
    • Desde mi punto de vista, el billete de la convención es «más sencillo» para construir. Las actualizaciones fallidas en la entrada principal requerir que vuelva a cargar el documento, realice de nuevo la operación y, a continuación, guardar. El billete cosa que permite probar y la «reivindicación» de algo sin tener que solicitar más datos.
    • También, depende de qué tipo de sobrecarga usted está preocupado acerca de. Estás bien vamos a luchar con el aumento de la disputa, o tiene otras necesidades de almacenamiento. Dado que un billete también se puede doblar como un registro de la compra, no sé que no tendría que ser como mucho de un problema de almacenamiento como usted piensa.
    • Estoy editando un campo de cantidad de un producto documento. Entonces tengo que crear miles de «tickets» si la cantidad=2K, por ejemplo. Luego me la reducción de una cantidad, debo eliminar algunos billetes. Suena completamente unrelaxed para mí. Un montón de dolores de cabeza en casos de uso. Tal vez me estoy perdiendo algo, pero ¿por qué no traer de vuelta retirado previamente el comportamiento de la transacción, sólo lo hacen opcional con algo como _bulk_docs?reject_on_conflict=true. Muy útil en un único maestro configuraciones.
    • Inserciones masivas de entradas no parece un gran logro para mí. Dependiendo de su configuración, usted puede simplemente añadir un par de entradas en un momento y poner más en el cambio de cantidades. Es probable que tengas algún tipo de documento por la cantidad de reducción en cualquier caso. Si usted reduce la cantidad porque alguien compró uno, el billete también puede servir como un registro de la compra para ese tema en particular. Lo mismo va para las devoluciones o más de cualquier cosa que se reduce la cantidad.
    • Tenga en cuenta que el leer/modificar/escritura le da resultados correctos cuando se ejecuta en un único CouchDB servidor. Cuando la replicación está involucrado, instancias de aplicación de la comunicación con diferentes todos podemos realizar con éxito las actualizaciones conflictivas, y te dejan con dos versiones en conflicto en la base de datos.
    • Para evitar la contención de un inProgress campo podría ser añadido que se establece en true, tan pronto como alguien hace clic en el botón comprar. Si el tiempo de espera o cancelar sería restablecer y volver a la cuenta del inventario.
    • Respondió el bloqueo de la pregunta (un poco), pero no de las transacciones de que se trate. Lo que si necesita actualizar 2 diferentes documentos de forma atómica? I. e. una cuenta bancaria de la transferencia, desea debitar de una cuenta de crédito y otra cuenta, pero si falla la actualización, a continuación, tanto de las actualizaciones debe ser cancelado. Puede que se hacen en el Sofá? (Esto no es una crítica, yo estoy tratando de entender la filosofía y la intención del Sofá.)
    • Leer esto: guide.couchdb.org/draft/recipes.html, la respuesta se reduce a couchdb interna de discbased «nunca se puede cambiar los datos, que acaba de anexar nuevos». En el escenario que implica la creación de un (atómico) de la transacción de la cuenta a un tránsito de la cuenta de la tarjeta de débito y una segunda (atómico) de la transacción de la en-tránsito de la cuenta hacia adelante (o hacia atrás). Que es como los verdaderos bancos de hacerlo. Cada paso es siempre documentado.
    • ¿Qué pasa si yo reclamo un martillo y luego mi base de datos se bloquea antes de que se puede insertar en el documento de factura que utiliza el martillo?
    • No es necesario emitir el docid y rev en el valor de su punto de vista, se obtiene de libre en ver los resultados. De hacerlo, especialmente en un detallado manera como un diccionario, sólo va a crecer su vista innecesariamente grande.
    • no del todo seguro de lo que quieres decir por «reclamar un martillo», pero – al menos utilizando los puntos de vista descritos en mi respuesta a continuación – se escribe un documento único que utiliza el martillo. El código se escribe el documento, y en una grabación correcta, continúa con lo que quería hacer con el, dijo hammer. Si el db escribir falla, no se utiliza el martillo porque no éxito «afirmó que» es

  2. 25

    Expansión en MrKurt la respuesta. Para muchos de los escenarios que usted no necesita tener stock de boletos redimidos en orden. En lugar de seleccionar la primera entrada, usted puede seleccionar al azar de las entradas restantes. Dado que un gran número de entradas y un gran número de peticiones concurrentes, usted conseguirá mucho más reducido de contención en las entradas, frente a todo el mundo tratando de conseguir el primer billete.

  3. 20

    Un patrón de diseño para restfull transacciones es crear una «tensión» en el sistema. Para el popular ejemplo de caso de uso de una cuenta bancaria de la transacción debe asegurarse de actualizar el total de cuentas implicadas:

    • Crear un documento de la transacción «transferencia de 10 USD de cuenta 11223 a cuenta 88733». Esto crea la tensión en el sistema.
    • Para resolver cualquier tensión de escaneo de todos los documentos de la transacción y
      • Si la fuente de la cuenta no se actualiza sin embargo, la actualización de la cuenta de origen (-10 USD)
      • Si la cuenta de origen fue actualizado, pero el documento de la transacción, no se muestra este, a continuación, actualizar el documento de la transacción (por ejemplo, fijar la bandera «sourcedone» en el documento)
      • Si la cuenta de destino no está actualizado aún la actualización de la cuenta de destino (+10 USD)
      • Si la cuenta de destino fue actualizado, pero el documento de la transacción, no se muestra este, a continuación, actualizar el documento de la transacción
      • Si ambas cuentas se han actualizado puede eliminar el documento de la transacción, o guárdelo para la auditoría.

    El escaneo de tensión debe ser hecho en un servidor de proceso para todos «de la tensión de documentos» para mantener a los momentos de tensión en el sistema a corto. En el ejemplo anterior, habrá un corto tiempo previsto de incoherencias cuando la primera cuenta se ha actualizado, pero el segundo no está actualizado aún. Esto debe ser tomado en cuenta de la misma manera que vamos a tratar con la consistencia final si su Couchdb es distribuido.

    Otra posible aplicación evita la necesidad de transacciones por completo: sólo almacena la tensión de documentos y evaluar el estado de su sistema mediante la evaluación de todos los involucrados tensión documento. En el ejemplo anterior, esto significaría que el total de una cuenta sólo se determina como la suma de los valores en los documentos de la transacción donde esta cuenta está involucrado. En Couchdb se puede modelar esta muy bien como un mapa o reducir la vista.

    • Pero ¿qué pasa cuando la cuenta de adeudo, pero la tensión doc no se cambia? Cualquier escenario de fracaso entre esos dos puntos, si no están atómica, será motivo de permanente contradicción, derecho? Algo sobre el proceso tiene que ser atómico, que es el punto de una transacción.
    • Sí, usted está en lo correcto, en este caso -, mientras que la tensión no se resuelve … que habrá incompatibilidad. Sin embargo, la contradicción es sólo temporal, hasta que el siguiente análisis de la tensión de los documentos de los detecta. Que es el comercio de, en este caso, una especie de consistencia final con respecto al tiempo. Mientras decrent la fuente cuenta primero y más tarde incremento de la cuenta de destino, esto puede ser aceptable. Pero cuidado: la tensión de documentos no dará el ÁCIDO transacciones en la parte superior de DESCANSO. Pero pueden ser una buena solución de compromiso entre el puro DESCANSO y ÁCIDO.
    • Imagine que cada tensión de documento tiene una marca de tiempo, y de la cuenta de documentos de ‘el último de tensión aplicada de campo o una lista de las tensiones aplicadas. Cuando el débito de la cuenta de origen de actualizar también la última de la tensión aplicada de campo’. Estas dos operaciones son atómicas porque están en el mismo documento. La cuenta de destino también tiene un campo similar. De esa manera el sistema siempre puede decir que la tensión docs se han aplicado a lo que cuentas.
    • Cómo detectar si la fuente/destino del documento fue actualizado ya? Lo que si se produce un error después del paso 1, entonces se vuelve a ejecutar y falla de nuevo, y así sucesivamente, se va a mantener la deducción de la cuenta de origen?
    • usted tendrá constancia de que la tensión documento ha sido aplicado a la cuenta. por ejemplo, anexando la tensión de id de documento en una lista de la propiedad de la cuenta. cuando todas las cuentas tocado por la tensión del documento se han actualizado, a continuación, marca la tensión documento como «hecho» o eliminarlo. Después, el documento de identificación puede ser quitado de la lista de todas las cuentas.
    • Gracias! Que me deja claro. Sólo temporalmente mantener una lista sobre el que se aplica la tensión de documentos en un campo independiente, que puede ser actualizado de forma atómica. ‘El último de tensión aplicada también puede funcionar, pero es más difícil porque se supone monótonamente creciente de pedidos, que toma especial cuidado en una configuración distribuida.
    • Me encanta este concepto de tensión documentos, pero el «decremento» y «marca de tiempo de aplicación de las operaciones que usted está mencionando son dos operaciones diferentes, dos por separado HTTP POST llamadas a la actualización de la misma doc que es por eso que todavía estoy confundido. Puede usted aclarar cómo después de hacer un POST para disminuir el primero de la cuenta y, a continuación, se bloquea el servidor, y empezar todo de nuevo, ¿cómo se evita volver a decrecer? Supongo que si usted escribió una clave en el decremento de campo («total»:»$121.00[aplica-fecha y hora]») que iba a funcionar, pero es complicado.
    • Ahh! Puedo retirar mi pregunta, ahora veo que la mayor parte de la API incluye un opcional comportamiento transaccional por la comisión de múltiples cambios. Muy cool la punta en la tensión de los documentos de los chicos, lo agradezco! wiki.apache.org/couchdb/…
    • Todo esto sólo parece funcionar si las operaciones de lectura o escritura de las mismas se serializan documentos, es decir, uno es ejecutado completamente después de la otra. @RiyadKalla La mayor parte de la API no es transaccional más …

  4. 5

    No, CouchDB en general no es adecuado para aplicaciones transaccionales, ya que no soporta operaciones atómicas en un clúster/replica medio ambiente.

    CouchDB sacrificado transaccional de la capacidad en favor de la escalabilidad. Con el fin de tener operaciones atómicas usted necesita un central de coordinación del sistema, lo que limita su escalabilidad.

    Si puede garantizar que sólo tienen una instancia de CouchDB o que todo el mundo la modificación de un documento en particular se conecta a la misma instancia de CouchDB, a continuación, podría utilizar la detección de conflictos en el sistema para crear una especie de atomicidad mediante los métodos descritos anteriormente, pero si más adelante la escala a un clúster o utilizar un servicio alojado como Cloudant se romperá y tendrás que rehacer esa parte del sistema.

    Por lo tanto, mi sugerencia sería utilizar algo distinto de CouchDB para los saldos de su cuenta, será mucho más fácil de esa manera.

  5. 5

    Como una respuesta a la OP del problema, Sofá no es probablemente la mejor opción aquí. Uso de puntos de vista es una gran manera de mantener un seguimiento del inventario, pero de sujeción a 0 es más o menos imposible. El problema es la condición de carrera cuando se lee el resultado de una vista, decidir que usted es aceptar la utilización de un «martillo-1» elemento y, a continuación, escribir un documento para usarlo. El problema es que no hay atómica manera de escribir sólo el doc utilizar el martillo si el resultado de la vista es que hay > 0 martillo-1. Si 100 usuarios de todas las consultas de la vista al mismo tiempo y ver 1 martillo-1, todos ellos pueden escribir un doc a usar un martillo 1, resultando en -99 martillo-1. En la práctica, la condición de carrera será bastante pequeño – muy pequeño si la bd está ejecutando localhost. Pero una vez que se escala, y tener un sitio fuera de los DB del servidor o clúster, el problema se notan mucho más. En cualquier caso, es inaceptable que una condición de carrera de ese tipo en un crítico de dinero relacionados con el sistema.

    Una actualización para MrKurt de la respuesta (que sólo puede ser fechado, o puede haber sido conscientes de algunos de CouchDB características)

    Un punto de vista es una buena manera de manejar las cosas como saldos /inventarios en CouchDB.

    No es necesario emitir el docid y rev en una vista. Usted obtener tanto de los de libre a la hora de recuperar la vista de los resultados. Emisores de ellos – especialmente en un formato detallado como un diccionario – se acaba de hacer crecer su vista innecesariamente grande.

    Una vista sencilla para el seguimiento de inventario balances debería parecerse más a este (también fuera de la parte superior de mi cabeza)

    function( doc )
    {
        if( doc.InventoryChange != undefined ) {
            for( product_key in doc.InventoryChange ) {
                emit( product_key, 1 );
            }
        }
    }
    

    Y la reducción de la función es aún más simple

    _sum
    

    Ello se utiliza un construido en función de reducir que la suma de los valores de todas las filas con la coincidencia de claves.

    En este punto de vista, cualquier doc puede tener un miembro de la «InventoryChange» que los mapas product_key a un cambio en el inventario total de ellos. es decir.

    {
        "_id": "abc123",
        "InventoryChange": {
             "hammer_1234": 10,
             "saw_4321": 25
         }
    }
    

    Gustaría añadir 10 hammer_1234 y 25 saw_4321 del.

    {
        "_id": "def456",
        "InventoryChange": {
            "hammer_1234": -5
        }
    }
    

    Quemaría 5 martillos desde el inventario.

    Con este modelo, nunca estás actualizando todos los datos, sólo anexar. Esto significa que no hay ninguna oportunidad para que se produzcan conflictos de actualización. Todas las transacciones problemas de actualización de datos desaparece 🙂

    Otra cosa buena acerca de este modelo es que CUALQUIER documento en la base de datos puede agregar y restar los elementos del inventario. Estos documentos pueden tener otros tipos de datos en ellos. Usted podría tener un «Envío» documento con un montón de datos acerca de la fecha y hora de recepción, almacén, recepción de los empleados, etc. y mientras que el doc se define un InventoryChange, se actualizará el inventario. Como podría un «Venta», doc, y un «DamagedItem» doc etc. Buscando en cada documento, se lee muy claramente. Y la vista se encarga de todo el trabajo duro.

    • Estrategia interesante. Como CouchDB newb parece que con el fin de calcular el número actual de martillos, es necesario realizar un mapa de reducir a más de la empresa historia de los cambios en el inventario de martillos. Este podría ser el valor de años de cambios. Hay una función incorporada de CouchDB, que harán que este rendimiento?
    • Sí, las vistas en CouchDB son como un continuo, persistente map/reduce. Usted está en lo correcto que hacer es empezar desde cero en un gran conjunto de datos podría llevar años, pero cuando los nuevos documentos que se agregan, sólo actualizar la vista existente, no tiene que volver a calcular toda la vista. Tenga en mente que no hay tanto espacio y los requisitos de CPU para las vistas. También, al menos cuando yo trabajaba con CouchDB profesionalmente (hace varios años), fue muy importante para sólo utilizar el construido en reducir las funciones de la ie. _sum. Javascript personalizado reducir funciones eran extremadamente lento
  6. 3

    De hecho, usted puede de una manera. Eche un vistazo a la HTTP Documento API y desplácese hacia abajo en la partida de «Modificar Varios Documentos Con una Sola Solicitud».

    Básicamente, usted puede crear/actualizar/eliminar un montón de documentos en una sola petición post a URI /{dbname}/_bulk_docs y se va todo a tener éxito o no todos. El documento hace precaución de que este comportamiento puede cambiar en el futuro, sin embargo.

    EDIT: Como se predijo, a partir de la versión 0.9 de la mayor parte docs ya no funciona de esta manera.

    • Que no ayudan realmente en la situación que se está discutiendo, es decir, la contención en una sola docs a partir de múltiples usuarios.
    • Comenzando con CouchDB 0.9, la semántica de granel actualizaciones han cambiado.
  7. 0

    Sólo usar SQlite tipo de solución ligera para las transacciones, y cuando la transacción se ha completado con éxito replicar, y la marca se replica en SQLite

    Tabla SQLite

    txn_id    , txn_attribute1, txn_attribute2,......,txn_status
    dhwdhwu$sg1   x                    y               added/replicated
    

    También puede eliminar las transacciones que se replican correctamente.

Kommentieren Sie den Artikel

Bitte geben Sie Ihren Kommentar ein!
Bitte geben Sie hier Ihren Namen ein

Pruebas en línea