2015-04-09 3 views
0

Как я могу гарантировать, что SQLite не будет чередовать запросы от нескольких одновременных запросов node.js/Express HTTP в одну транзакцию?Изоляция транзакции node.js sqlite

Я хотел бы, чтобы запросы БД от разных запросов выполнялись в отдельных транзакциях, изолированных друг от друга, позволяя каждому совершать или откатываться независимо друг от друга. Учитывая особенности single-thread (и single-DB-connection?) Node.js, это кажется особенно проблематичным.

Я пробирался через десятки веб-страниц и документов и не нашел никаких ясных (для меня) объяснений того, как (или) этот сценарий обрабатывается. Например, описание db.serialize() только утверждает, что один запрос будет выполняться одновременно - он ничего не говорит о разделении запросов, принадлежащих разным транзакциям.

Любые указатели оценили!

ответ

0

Я столкнулся с той же проблемой. Вот как я это решил:

Шаг 1: доступ к базе данных Dnsure осуществляется через набор функций библиотеки, где база данных передается в качестве первого входного параметра.

Шаг 2: При создании объекта базы данных (с помощью new sqlite3.Database('path')), оберните объект с некоторой дополнительной метаинформацией:

Вот как я завернут мой:

var wrap = { db_obj : new sqlite3.Database('path'), locked : "UNLOCKED", work_queue : [] } 

Шаг 3: Создайте функцию, которая будет использоваться для запуска функций db. Если база данных заблокирована, эта функция отложит их выполнение до конца. Я назвал мое «runAsync»:

function runAsync(db, fn, callBack) { 
    if (db.locked === "LOCKED") { 
     db.work_queue.push(function() { runAsync(db, fn, callBack); }); 
     return; 
    } 
    fn(db,callBack); 
} 

Мы можем видеть, что эта функция проверяет состояние упакованного объекта БД. Если он заблокирован, мы откладываем выполнение, сохраняя функцию в «рабочей очереди», которая будет выполнена позже (путем выполнения fn()).

Шаг 4: Создать функцию, которая будет использоваться для запуска БД функции исключительно. Если база данных заблокирована, эта функция отсрочит выполнение до конца, иначе она заблокирует базу данных, запустит ее функцию и затем разблокирует базу данных. Я назвал мое: runAsyncExclusive():

function runAsyncExclusive(db, fn, callBack) { 
    if(db.locked === "LOCKED") { 
     db.work_queue.push(function() { runAsyncExclusive(db, fn, callBack) }); 
     return; 
    } 
    var exclusiveDb = { 
     db_obj : db.db_obj, 
     locked : "UNLOCKED", 
     work_queue : [] 
    }; 
    db.locked = "LOCKED"; 
    fn(exclusiveDb, function(err,res) { 
     db.locked = "UNLOCKED"; 
     var workItems = db.work_queue; 
     _.each(workItems, function(fn) { fn(); }); 
     db.work_queue = []; 
     callBack(err,res); 
    }) 
} 

Объект exclusiveDb, который передается в функцию позволит монопольный доступ к БД. Этот объект может быть заблокирован, что допускает сколь угодно глубокую вложенную блокировку.

Шаг 5: Настройте библиотеку функций таким образом, что они называют asyncRun() и asyncRunExclusive() где это уместно:

function get(db,sql,params,callBack) { 
    db.get(sql,params,callBack); 
} 

становится ...

function get(db,sql,params,callBack) { 
    runAsync(db, function(db,cb) { db.get(sql,params,cb); }, callBack); 
} 

Вуаля!

(Извините, если это было недостаточно ясно)

+1

Это имеет смысл - спасибо! Я полагаю, что вы используете пару функций runAsync и runAsyncExclusive для реализации таких шаблонов, как multi-reader-vs-single-writer? –

+0

Не похоже на потокобезопасность. Чтение-запись db.locked не выполняется атомарно. Что делать, если два потока одновременно называют runAsyncExclusive? Вы могли бы получить два потока, читающих db.locked === "UNLOCKED" и начать свой бизнес. –

+0

Вы правы в том, что это не потокобезопасно. Это не должно быть проблемой, хотя node.js имеет однопоточную правку? – maambmb

Смежные вопросы