2015-07-24 2 views
3

Есть ли возможность создавать транзакции с атомной базой данных с книжной полкой? У меня проблема с дубликатами в базе данных. Проблематично код, как показано ниже:bookshelf.js операции блокировки

bookshelf.transaction(function (t) { 
    var modelLocation = new Models.Location({'name':event.venue}); 
    modelLocation.fetch({transacting:t}) 
     .then(function (fetchedLocation) { 
      if (!fetchedLocation) { 
       modelLocation.save(null,{transacting:t}).then(function (savedModel) { 
        t.commit(savedModel) 
       }).catch(function (err) { 
        t.rollback(err) 
       }); 
      } 
      else{ 
       t.commit(fetchedLocation) 
      } 
     }) 
}) 

я вызвать метод, содержащий этот код почти Simultaniously и асинхронно в 20 раз. Из этих 20 имеется 5 дублирующих наборов данных. В результате получается около 2-3 дубликатов в базе данных. Текущее обходное решение состоит в том, чтобы обернуть все это в setTimeout со случайным интервалом между 0 и 10 секундами, который почти никогда не дает мне дубликатов. Но это, очевидно, не готовое к производству решение.

ответ

0

ОК, поэтому, в конце концов, я решил пойти с библиотекой async.js и это очередь. Очередь гарантирует, что одновременно выполняются максимум n задач асинхронной работы. В этом случае 1. Я создал модуль, который экспортирует экземпляр очереди. Таким образом, я могу использовать его для нескольких модулей. Он просто ждет обещания выполнить.

var async = require('async'); 

module.exports = async.queue(function (task, callback) { 
    task().then(function() { 
     callback(); 
    }); 
},1); 

Затем в модуле, где мне нужна «атомную» транзакция У меня есть следующий код:

var queue = require('./transactionQueue'); 
... 
... 
queue.push(function(){ 
    return bookshelf.transaction(function (t) { 
     var modelLocation = new Models.Location({'name':event.venue}); 
     return modelLocation 
      .fetch({transacting:t}) 
      .then(function (fetchedLocation) { 
       if (!fetchedLocation) { 
        return modelLocation 
         .save(null,{transacting:t}); 
       } 
      }); 
    }); 
}); 

Очень важно, чтобы обернуть транзакцию в функцию, так что не будет выполнено верно далеко.

+0

Не удалось ли решить вашу проблему с помощью ключа UNIQUE? То, что вы пытаетесь достичь, это своего рода «транзакционное отсутствие», эта концепция для меня совершенно новая. AFAIK no DB реализует такой механизм. Можете ли вы работать с другими технологиями? – flaviodesousa

+0

Я изначально хотел решить его с помощью уникальных ключей, но потом он просто бросает ошибки, и вам придется их поймать. Поэтому я предпочитаю ручное планирование запросов. Мне нужно это https://en.wikipedia.org/wiki/Two-phase_locking. Это базовая функциональность db. – user1862511

+0

Да, knex поддерживает блокировку по тофу, хотя forUpdate() и forShare(). Но по вашему сценарию нет объекта блокировки или, как я уже сказал, «транзакционного отсутствия», я думаю, что двухфазная блокировка не покрывает это. – flaviodesousa

1

Поскольку транзакции книжной полки являются обещаниями, вам не нужно явно звонить commit() или rollback(). Просто позвольте исполненному обещанию взять на себя обязательства, или вы можете заставить откат, выбросив исключение.

В вашем коде есть, видимо, небольшая ошибка, которая может быть причиной проблемы: аргумент отсутствует из fetch() «s then() - этот аргумент является результатом от fetch() вызова, экземпляра, если объект был найден или null если не.

bookshelf.transaction(function (t) { 
    var modelLocation = new Models.Location({'name':event.venue}); 
    return modelLocation 
    .fetch() 
    .then(function (fetchedLocation) { 
     if (!fetchedLocation) { 
      modelLocation 
       .save(null,{transacting:t}); 
     } 
    })l 
}); 

Я не могу проверить это сейчас, но я надеюсь, что это поможет.

+1

ooops извините недостающий параметр из-за переименования некоторых переменных из-за внутренних вещей компании. Я трижды проверял, и теперь это то же самое. Но проблема не исчезла. Теперь я рассматриваю решение с очередью async.js. – user1862511