I use in a Windows 8 project (js/html) the SQLite3-WinRT library https://github.com/doo/SQLite3-WinRT.
I create a function that is called in a for loop.
I have this error:
SQLiteError: 0x800700aa: eachAsync("INSERT INTO home (id, url, cksum)VALUES (16, 'main_page_2.jpg', 'e0d046ca3421a3c2df328b293ad5981a');", ) database is locked
I think the error is because I create a new connection every iteration of loop, but I don't understand another method. Who can help me?
This is the function:
function insertInDB(dbPath, tbName, arrayCol, arrayVal) {
SQLite3JS.openAsync(dbPath).then(function (db) {
var query = "INSERT INTO " + tbName;
var column = " (";
var values = "VALUES (";
for (var i = 0; i < arrayCol.length; i++) {
if (i == arrayCol.length - 1) {
column = column + arrayCol[i] + ")";
} else {
column = column + arrayCol[i] + ", ";
}
}
for (var i = 0; i < arrayVal.length; i++) {
if (i == arrayCol.length - 1) {
values = values + arrayVal[i] + ");";
} else {
values = values + arrayVal[i] + ", ";
}
}
query = query + column + values;
return db.eachAsync(query).done(function () {
console.log("Ok");
db.close();
},
function (error) { console.log(error); },
function (progress) { });
});
}
and this is the loop that call a previous function:
listHome.forEach(function(value, index, array){
var valconfig = new Array(value.id, "'" + value.url + "'", "'" + value.cksum + "'");
console.log("id=" + value.id + " url=" + value.url + " ck=" + value.cksum);
insertInDB(sqlPath, "home", colconfig, valconfig);
})
If I'm reading this correctly, your calling code is iterating over a list of values synchronously. listHome.forEach
will call insertInDB
for each item in listHome
... but it doesn't wait for insertInDB
to return before making the next call to insertInDB
.
Inside insertInDB
you have call to SQLite3JS.openAsync
and db.eachAsync
- both asynchronous methods. After perusing SQLite3JS a little bit (which looks pretty cool), both of those methods return promises, where internally they call into a WinRT component. Great design.
So this is what I suspect is happening: one of the asynchronous calls in insertInDB
puts a lock on the database. However, insertInDB
returns control back to the listHome.forEach
loop as soon as it hits the first asynchronous method call. If the lock on the database remains once forEach
gets to the next item in listHome, then the operation will attempt to write to a locked database. Hence the error.
I'll think about this a little bit and see if I can come up with a solution.
-- edit --
Okay, I have a solution that might work for you. You might want to create a "DataBaseHelper" class that will queue up the transactions that you need to make in the database.
Here's a rough prototype that I threw together:
[Replaces your foreach loop]
DBHelper.queueUpdates(listHome);
[DBHelper module definition]
(function () {
var _queue;
function queueUpdates(array) {
_queue = array;
scheduleUpdates();
}
function scheduleUpdates() {
if (_queue.length > 0) {
var transaction = _queue.pop();
insertInDB("path", "table", "column", transaction);
}
}
function insertInDB(dbPath, tbName, arrayCol, arrayVal) {
return SQLite3JS.openAsync(dbPath).then(function (db) {
// Construct your SQL query ...
return db.eachAsync(query).done(function () {
db.close();
scheduleUpdates();
},
function (error) { console.log(error); },
function (progress) { });
});
}
WinJS.Namespace.define("DBHelper", {
queueUpdates: queueUpdates
})
})();
User contributions licensed under CC BY-SA 3.0