2016-09-28 64 views
1

我想從我的node.js應用程序使用node-sqlite3執行數據庫中的INSERT + UPDATE事務。但是,我不知道如何在事務完成時獲取last_insert_rowid。我的查詢看起來是這樣的:如何從交易中獲取last_insert_rowid?

BEGIN TRANSACTION; 
    INSERT INTO <table> (field1, ...) VALUES (value1, ...); 
    UPDATE <table> SET prev=last_insert_rowid() WHERE <condition>; 
END TRANSACTION; 

此字符串(減去多餘的空格)被分配給VAR q

我有我的數據庫使用這種在某個時間點打開:

var db = new sqlite3.Database(dbfile) 

但是,如果我嘗試使用:

db.run(q, function(err) { 
    if (err) ... 
    console.log(this.lastId) 
}) 

它不僅能打印出「0」,沒有錯誤,但不會更改數據庫!如果我使用exec而不是run,那麼查詢運行成功,但我無法從exec獲取任何數據。

我也嘗試過這樣的事情:

db.exec(q, function(err) { 
    if (err) ... 
    db.run(";", function(err) { 
     if (err) ... 
     console.log(this.lastId) 
    }) 
}) 

但在「運行」中的「這個」背景下不具有lastId財產!

我也看了一下sqlite3-transaction包,但它似乎沒有在事務回調中提供任何信息!

我不能將插入作爲單獨運行(),得到this.lastId然後用它來運行更新,因爲這會使數據庫在兩個語句之間處於無效狀態(因此需要一個交易)。

如何從此事務中獲取last_insert_rowid()?

+0

只是想知道,但在MySQL中,獲取最近插入的ID的能力可以取決於所使用的驅動程序(例如Perl + DBI + DBD :: mysql模塊)以及一些前提條件,如表ID必須是一個Integer PK設置爲自動增量。您是否檢查過您的特定情況下是否有類似/不同的要求適用?它也可能取決於哪個查詢最後運行,因此可能需要檢查是否有可能在實際事務的上下文中執行該查詢。 – ray

+0

您可以分別調用'run'並仍然使用事務。只要調用'run(「BEGIN TRANSACTION」,...)'等,並確保在完成時調用「COMMIT TRANSACTION」或者在出現錯誤時調用ROLLBACK TRANSACTION。 – cartant

+0

@cartant謝謝,我確實在昨天不得不離開之前發現並嘗試了這一點,但還沒有時間記錄它。 – Michael

回答

0

爲了獲得last_insert_rowid(),有必要按如下方式將事務分解成塊。首先,運行一個查詢開始交易:

db.run("BEGIN TRANSACTION") 

接下來,運行命令插入行,得到的rowid在回調:

// replace stuff in angle brackets and ellipses with proper values 
db.run("INSERT INTO <table> (field1, ...) VALUES (value1, ...);", function(err,data) { 
    if (err) ... 
    rowid=this.lastID // rowid declared in scope visible outside callback 
}) 

接下來,運行更新。由於交易尚未完成,所有這些回調都不會被調用。

db.run("UPDATE <table> SET prev=last_insert_rowid() WHERE <condition>;", function(err,data) { 
    // do whatever needs doing after update is done here 
}) 

現在提交的事務:

db.run("END TRANSACTION;") 

在這種情況下,由於更新是在交易的最後一條語句,如果成功,整個交易應該會成功,所以它應該是安全的做無論在那個地方的交易之後需要做什麼。

相關問題