2017-03-08 66 views
0

我在執行UPDATE之後,通過執行INSERT來檢測我的應用程序中的node-mysql事務,這將違反UNIQUE鍵約束。雖然INSERT失敗,但我發現最初的UPDATE成功了,儘管使用ROLLBACK的事務是成功的。 MySQL UPDATE不執行隱式提交,所以我不確定這裏究竟發生了什麼。在唯一鍵違規後,node-mysql事務未回滾

pool.getConnection(function (err, connection) { 

    connection.beginTransaction(function (err) { 
     if (err) { 
      console.log(" --- error 1: " + JSON.stringify(err)); 
     } 

     console.log(" --- A"); 

     connection.query('update course_person set rescheduled_date = CURDATE() where idperson = ? and rescheduled_date is null', [idperson], function (err, rows, fields) { 

      if (err) { 
       connection.rollback(function() { 
        console.log(" --- error 2: " + JSON.stringify(err)); 
       }); 

       console.log(" --- B"); 

      } 

      console.log(" --- C"); 

     }); 

     connection.query('insert into course_person (idcourse, idperson) VALUES (?, ?)', [newidcourse, idperson], function (err, rows, fields) { 

      if (err) { 
       connection.rollback(function() { 
        console.log(" --- error 3: " + JSON.stringify(err)); 
       }); 

       console.log(" --- D"); 

      } 

      console.log(" --- E"); 

     }); 

     connection.commit(function (err) { 
      if (err) { 
       connection.rollback(function() { 
        console.log(" --- error 4: " + JSON.stringify(err)); 
       }); 

       console.log(" --- F"); 

      } 

      console.log(" --- G"); 

      req.flash('success', 'Person was updated successfully.'); 
      res.redirect('/person/' + idperson); 

      connection.release(); 
     }); 

    }); 

}); 

我得到下面的輸出順序:

--- A 
--- C 
--- D 
--- E 
--- G 
--- error 3: {"code":"ER_DUP_ENTRY","errno":1062,"sqlState":"23000","index":0} 

,這裏是我的證明:)

enter image description here

回答

1

如果你想異步函數按順序運行,你會必須嵌套它們,或者將它們作爲承諾數組的一部分進行調用,或者使用async/await樣式代碼......某種東西。你在做什麼在這裏呼籲

  1. pool.getConnection
  2. connection.beginTransaction
  3. connection.query & connection.query & connection.commit都在同一時間

離場我會試試這樣的:

router.get('/myfunc', async (req, res) => { 

    try { 

    const connection = await pool.getConnection(); 

    try { 

     await connection.beginTransaction(); 

     // update statement 
     const sql_update = `update course_person 
          set rescheduled_date = CURDATE() 
          where idperson = ? 
          and rescheduled_date is null`; 
     await connection.query(sql_update, [idperson]); 

     // insert statement 
     const sql_insert = `insert into course_person (idcourse, idperson) VALUES (?, ?)`; 
     await connection.query(sql_insert, [newidcourse, idperson]); 

     // commit 
     await connection.commit(); 

     req.flash('success', 'Person was updated successfully.'); 
     return res.redirect('/person/' + idperson); 

    } finally { 
     pool.releaseConnection(connection);  
    } 

    } catch (err) { 
    await connection.rollback(); 
    console.log(err); 
    } 

}); 

注意:我沒有測試過這段代碼。但是這是我使用的模式。

這將需要您使用promise-mysql而不是node-mysql,因爲async/await語法需要承諾使用。你也可以使用Bluebird來節約node-mysql。另外,如果你的節點版本不支持異步/等待,你需要使用像babel這樣的東西來傳遞它。 (我用巴貝爾在我的工作流程。)

如果你想簡單地窩異步調用,而不是爲一個更傳統的編碼風格,你可以做這樣的事情:

pool.getConnection(function (err, connection) { 

    connection.beginTransaction(function (err) { 
    if (err) { 
     console.log(" --- error 1: " + JSON.stringify(err)); 
     throw err; 
    } 

    connection.query('update course_person set rescheduled_date = CURDATE() where idperson = ? and rescheduled_date is null', [idperson], function (err, rows, fields) { 
     if (err) { 
     connection.rollback(function() { 
      console.log(" --- error 2: " + JSON.stringify(err)); 
      throw err; 
     }); 
     } 

     connection.query('insert into course_person (idcourse, idperson) VALUES (?, ?)', [newidcourse, idperson], function (err, rows, fields) { 
     if (err) { 
      connection.rollback(function() { 
      console.log(" --- error 3: " + JSON.stringify(err)); 
      throw err; 
      }); 
     } 

     connection.commit(function (err) { 
      if (err) { 
      connection.rollback(function() { 
       console.log(" --- error 4: " + JSON.stringify(err)); 
       throw err; 
      }); 
      } 

      req.flash('success', 'Person was updated successfully.'); 
      res.redirect('/person/' + idperson); 

      connection.release(); 
     }); 
     }); 
    }); 
    }); 
}); 

注意每個呼叫是如何嵌套在先前調用的回調函數內。這開始變得與所有的縮進(即「回撥地獄」)混亂。使用promise或async/await的代碼從長遠來看更易讀易維護。

+0

非常感謝,特別是對於這些例子!我認爲它必須是異步相關的東西。我認爲我現在要堅持使用嵌套版本,至少直到節點在版本8中正式支持異步/等待。這也會給我一些時間來學習和練習使用promise。 – littleK