Могу ли я делать транзакции и блокировки в CouchDB?


Мне нужно сделать транзакции (begin, commit или rollback), блокировки (выберите для обновления). Как я могу это сделать в БД модели документа?

Edit:

дело обстоит так:

  • Я хочу запустить сайт аукционов.
  • и я думаю, как направить покупку, а также.
  • при прямой покупке я должен уменьшить поле количество в записи товара, но только если количество больше нуля. Вот почему мне нужны замки и операции.
  • Я не знаю, как решить эту проблему без блокировок и/или транзакций.

могу ли я решить эту проблему с помощью CouchDB?

7 76

7 ответов:

нет. CouchDB использует модель "оптимистического параллелизма". Проще говоря, это просто означает, что вы отправляете версию документа вместе с вашим обновлением, и CouchDB отклоняет изменение, если текущая версия документа не соответствует тому, что вы отправили.

это обманчиво просто, на самом деле. Вы можете переформулировать многие обычные сценарии на основе транзакций для CouchDB. Однако вам нужно как-то выбросить свои знания о домене RDBMS при изучении CouchDB. Это полезно, чтобы подойти проблемы с более высокого уровня, а не пытаться формировать диван в мире, основанном на SQL.

отслеживание запасов

проблема, которую вы изложили, в первую очередь является проблемой инвентаризации. Если у вас есть документ, описывающий товар, и он включает поле "доступное количество", вы можете обрабатывать такие проблемы параллелизма:

  1. извлеките документ, обратите внимание на _rev свойство, которое CouchDB отправляет вместе
  2. уменьшите поле Количество, если оно больше нуля
  3. отправить обновленный документ, с помощью _rev свойства
  4. если _rev соответствует в настоящее время хранится номер, будет сделано!
  5. если есть конфликт (когда _rev не совпадает), получить самую новую версию документа

в этом случае есть два возможных сценария отказа, о которых нужно подумать. Если последняя версия документа имеет количество 0, вы обрабатываете его так же, как и в СУБД, и предупреждаете пользователя о том, что они не могут купить то, что хотели купить. Если самая последняя версия документа имеет количество больше 0, просто повторите операцию с обновленными данными и начните с самого начала. Это заставляет вас делать немного больше работы, чем СУБД, и может немного раздражать, если есть частые, конфликтующие обновления.

теперь ответ, который я только что дал, предполагает, что вы собираетесь делать вещи в CouchDB во многом так же, как и в СУБД. Я мог бы подойти к этой проблеме немного иначе:

Я бы начал с документа "master product", который включает все данные дескриптора (имя, Изображение, Описание, Цена и т. д.). Затем я бы добавил документ "инвентарный билет" для каждого конкретного экземпляра с полями для product_key и claimed_by. Если вы продаете модель молотка, и у вас есть 20 из них, чтобы продать, у вас могут быть документы с ключами, такими как hammer-1,hammer-2, etc, чтобы представить каждый доступный молоток.

затем я бы создал представление, которое дает мне список доступных молотков, с функцией уменьшения, которая позволяет мне видеть "всего". Они полностью снимаются с манжеты, но должны дать вам представление о том, как будет выглядеть рабочий вид.

карта

function(doc) 
{ 
    if (doc.type == 'inventory_ticket' && doc.claimed_by == null ) { 
        emit(doc.product_key, { 'inventory_ticket' :doc.id, '_rev' : doc._rev }); 
    } 
}

это дает мне список доступных "билетов", по ключ продукта. Я могу взять группу из них, когда кто-то хочет купить молоток, затем повторите отправку обновлений (используя id и _rev) до тех пор, пока я успешно не заявлю один (ранее заявленные билеты приведут к ошибке обновления).

уменьшить

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

эта функция уменьшения просто возвращает общее количество невостребованных inventory_ticket элементов, так что вы можете сказать, сколько "молотки" доступны для покупки.

предостережения

это решение представляет собой примерно 3.5 минуты полного размышления над конкретной проблемой, которую вы представили. Там могут быть лучшие способы сделать это! Тем не менее, это существенно уменьшает конфликтующие обновления и сокращает необходимость реагировать на конфликт с новым обновлением. В этой модели несколько пользователей не будут пытаться изменить данные в записи основного продукта. В самом худшем случае у вас будет несколько пользователей, пытающихся претендовать на один билет, и если вы захватили несколько из них с Вашего взгляда, вы просто перейдите к следующему билету и повторите попытку.

ссылка: https://wiki.apache.org/couchdb/Frequently_asked_questions#How_do_I_use_transactions_with_CouchDB.3F

расширение ответа Мркурта. Для многих сценариев вам не нужно иметь акции билеты погашены в порядке. Вместо выбора первого билета, вы можете выбрать случайным образом из оставшихся билетов. Учитывая большое количество билетов и большое количество одновременных запросов, вы получите гораздо меньше конкуренции на эти билеты, по сравнению со всеми, кто пытается получить первый билет.

шаблон проектирования для транзакций restfull заключается в создании "напряжения" в системе. В популярном примере использования транзакции банковского счета вы должны убедиться, что обновили общую сумму для обоих задействованных счетов:

  • создать документ транзакции "перевод USD 10 со счета 11223 на счет 88733". Это создает напряжение в системе.
  • для разрешения любого напряжения сканирования для всех документов транзакций и
    • если исходная учетная запись не является обновление пока обновление исходного счета (-10 долларов)
    • если исходный счет был обновлен, но документ транзакции не показывает это, то обновите документ транзакции (например, установите флаг "sourcedone" в документе)
    • если целевой счет еще не обновлен обновите целевой счет (+10 USD)
    • Если целевой счет был обновлен, но документ транзакции не показывает это, то обновите документ транзакции
    • Если обе учетные записи имеют после обновления вы можете удалить документ транзакции или сохранить его для аудита.

сканирование натяжения должно выполняться в бэкэнд-процессе для всех "документов натяжения", чтобы время натяжения в системе было коротким. В приведенном выше примере будет недолгое ожидаемое несоответствие, когда первая учетная запись была обновлена, но вторая еще не обновлена. Это должно быть принято во внимание так же, как вы будете иметь дело с возможной последовательностью, если ваши механизмы распространяется.

другая возможная реализация позволяет полностью избежать необходимости транзакций: просто храните документы напряжения и оценивайте состояние своей системы, оценивая каждый вовлеченный документ напряжения. В приведенном выше примере это означает, что общая сумма для счета определяется только как сумма значений в документах транзакций, в которых участвует этот счет. В Couchdb вы можете очень хорошо смоделировать это как вид карты / уменьшения.

нет, CouchDB обычно не подходит для транзакционных приложений, поскольку он не поддерживает атомарные операции в кластеризованной/реплицированной среде.

CouchDB пожертвовал транзакционными возможностями в пользу масштабируемости. Чтобы иметь атомарные операции, вам нужна центральная система координации, которая ограничивает вашу масштабируемость.

Если вы можете гарантировать, что у вас есть только один экземпляр CouchDB или что все изменяющие конкретный документ подключаются к одному и тому же Затем вы можете использовать систему обнаружения конфликтов для создания своего рода атомарности, используя методы, описанные выше, но если вы позже масштабируетесь до кластера или используете размещенный сервис, такой как Cloudant, он сломается, и вам придется переделать эту часть системы.

Итак, мое предложение было бы использовать что-то другое, чем CouchDB для остатков на вашем счете, это будет намного проще.

в качестве ответа на проблему ОП, диван, вероятно, не лучший выбор здесь. Использование представлений-отличный способ отслеживать запасы, но зажим до 0 более или менее невозможен. Проблема заключается в состоянии гонки, когда вы читаете результат представления, решите, что вы в порядке, чтобы использовать элемент "hammer-1", а затем напишите документ для его использования. Проблема в том, что нет атомарного способа только написать документ для использования молотка, если результат представления состоит в том, что есть > 0 молотков-1. Если 100 пользователей все запрос к представлению одновременно и увидеть 1 молоток-1, все они могут написать доктору, чтобы с помощью молотка 1, в результате чего -99 молоток-1 по. На практике, условие гонки будет довольно небольшой - очень небольшой, если ваша БД работает на localhost. Но как только вы масштабируетесь и имеете сервер или кластер БД вне сайта, проблема станет гораздо более заметной. Несмотря на это, недопустимо иметь такое состояние гонки в системе, связанной с критическими деньгами.

обновление ответа MrKurt (it может быть, просто датирован, или он, возможно, не знал о некоторых функциях CouchDB)

представление-это хороший способ обрабатывать такие вещи, как балансы / запасы в CouchDB.

вам не нужно выдавать docid и rev в представлении. Вы получаете бесплатно, когда вы получаете результаты. Испускание их-особенно в подробном формате, таком как словарь - просто увеличит ваш взгляд излишне большим.

простой вид для отслеживания остатков запасов должен выглядеть больше вот так (тоже с головы)

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

и функция уменьшения еще более проста

_sum

используется встроенная функция reduce это просто суммирует значения всех строк с совпадающими ключами.

С этой точки зрения, любой док может быть членом "InventoryChange", что карты ключ_продукта к изменению общего запаса из них. то есть.

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

добавил бы 10 hammer_1234 и 25 saw_4321's.

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

сожгли бы 5 молотков из инвентаря.

С этой моделью вы никогда не обновляете никаких данных, только добавляя. Это означает, что нет возможности для конфликтов обновлений. Все транзакционные вопросы обновления данных уходят:)

еще одна приятная вещь в этой модели заключается в том, что любой документ в БД может как добавлять, так и вычитать элементы из инвентаря. Эти документы могут содержать все виды других данных. Возможно, у вас есть "Отгрузка" документ с кучей сведения о дате и времени получил, склад, прием работника и т. д. и пока этот документ определяет InventoryChange, он обновит инвентарь. Как и" продажа "doc, и" DamagedItem " doc и т. д. Глядя на каждый документ, они читали очень четко. И вид обрабатывает всю тяжелую работу.

на самом деле, вы можете в пути. Взгляните на HTTP Document API и прокрутите вниз до заголовка "изменить несколько документов с помощью одного запроса".

в основном вы можете создавать / обновлять / удалять кучу документов в одном запросе post на URI / {dbname} / _bulk_docs и они либо все преуспеют, либо все потерпят неудачу. Однако в документе содержится предостережение о том, что это поведение может измениться в будущем.

изменить: как и прогнозировалось, из версии 0.9 массовые документы больше не работают таким образом.

просто используйте SQLite вид легкого решения для транзакций, и когда транзакция будет завершена успешно реплицировать его, и отметьте его реплицируется в SQLite

таблица SQLite

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

вы также можете удалить операции, которые успешно реплицируются.