2017-10-17 89 views
1

我正在使用mysql C++連接器。我有一個表:MySQL C++連接器如何從插入查詢中檢索自動增量鍵

CREATE TABLE some_table 
(
    id INT NOT NULL AUTO_INCREMENT, 
    col1 INT, 
    col2 INT, 
    PRIMARY KEY (id) 
); 

在查詢中插入多條記錄,我用:

INSERT INTO some_table 
    (col1, col2) 
VALUES 
    (0, 1), 
    (2, 3), 
    (4, 5); 

我的問題是:在插入之後,我想檢索所有自動生成的ID。有可能我可以在C++連接器中使用函數而不創建另一個查詢?

例如,在JDBC中,可以使用以下方法檢索AUTO_INCREMENT列值。

stmt.executeUpdate(
     "INSERT INTO autoIncTutorial (dataField) " 
     + "values ('Can I Get the Auto Increment Field?')", 
     Statement.RETURN_GENERATED_KEYS); 

// 
// Example of using Statement.getGeneratedKeys() 
// to retrieve the value of an auto-increment 
// value 
// 

int autoIncKeyFromApi = -1; 

rs = stmt.getGeneratedKeys(); 

if (rs.next()) { 
    autoIncKeyFromApi = rs.getInt(1); 
} else { 

    // throw an exception from here 
} 

https://dev.mysql.com/doc/connector-j/5.1/en/connector-j-usagenotes-last-insert-id.html

任何C++連接器的方法?

謝謝

+0

說實話我總是發現mysqlcpp的界面古老而笨重。我直接返回使用mysql c庫。 –

+0

從我的程序中的註釋:\t對於自動遞增ID字段,需要加載ID字段。 SQL函數LAST_STATEMENT_ID()可能不會返回正確的值,特別是如果記錄未更新或插入未導致新(增加)的記錄標識。獲得更新ID的唯一安全可靠的方法是從表中重新加載ID字段。 –

+0

@RichardHodges,是否可以使用c API檢索密鑰? – r0ng

回答

1

去年我面臨同樣的問題。解決方案是使用內建的LAST_INSERT_ID()。下面我改變了getting start example 2展示如何使用它:

//previous variable declarations and initialisation similar to the original example 
    driver = get_driver_instance(); 
    con = driver->connect("tcp://127.0.0.1:3306", "root", "root"); 
    con->setSchema("test_schema"); 

    con->setAutoCommit(false); 

    stmt = con->createStatement(); 
    stmt->execute("DROP TABLE IF EXISTS tbl__test1"); 
    stmt->execute("DROP TABLE IF EXISTS tbl_test2"); 

    const string createTbl1Statement = "CREATE TABLE `tbl__test1` (" 
      "`id` int(11) NOT NULL AUTO_INCREMENT," 
      "`col_value` varchar(45) DEFAULT NULL," 
      "PRIMARY KEY (`id`)" 
      ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; 

    const string createTbl2Statement = "CREATE TABLE `tbl_test2` (" 
      "`id` int(11) NOT NULL AUTO_INCREMENT," 
      "`tbl_test1_id` int(11) NOT NULL," 
      "`col_value` varchar(45) DEFAULT NULL," 
      "PRIMARY KEY (`id`)" 
      ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; 

    stmt->execute(createTbl1Statement); 
    stmt->execute(createTbl2Statement); 

    pstmt = con->prepareStatement(
      "INSERT INTO tbl__test1(col_value) VALUES ('abcde')"); 
    pstmt->executeUpdate(); 
    delete pstmt; 

    stmt->execute("SET @lastInsertId = LAST_INSERT_ID()"); 
    delete stmt; 

    const string insertTbl2 = "INSERT INTO tbl_test2(tbl_test1_id, col_value)" 
      " VALUES (@lastInsertId, '1234')"; 

    pstmt = con->prepareStatement(insertTbl2); 
    pstmt->executeUpdate(); 
    delete pstmt; 

    con->commit(); 

    delete con; 
    //remain code is like the example 2 from mysql site 

的是如何安全的調用LAST_INSERT_ID(),如MySQL的文檔指出:

已生成保持在該ID服務器在每個連接的基礎上。這意味着該函數返回給定客戶端的值是爲該客戶端影響AUTO_INCREMENT列的最新語句生成的第一個AUTO_INCREMENT值。即使它們生成自己的AUTO_INCREMENT值,該值也不會受到其他客戶端的影響。此行爲可確保每個客戶端都可以檢索自己的ID,而不必關心其他客戶端的活動,而無需鎖定或事務。

編輯:

給出here

沒有參數,LAST_INSERT_ID()返回表示成功插入用於AUTO_INCREMENT列作爲結果,第一自動生成的值的64位的值最近執行的INSERT語句。

因此,LAST_INSERT_ID返回最後生成的ID,而不管新行插入的表是什麼。如果需要插入多行,只需在插入每行之後立即調用LAST_INSERT_ID,以便獲得密鑰。

在以下代碼中,它在表1中插入1行,獲取生成的密鑰(返回'1'),該密鑰用於在關聯表2中插入新聞2行。不是再次將其插入1個新行的表1中,再次得到生成的密鑰(返回「2」),並在表2 2個再次新聞行插入:

#include <stdlib.h> 
#include <iostream> 

#include "mysql_connection.h" 

#include <cppconn/driver.h> 
#include <cppconn/exception.h> 
#include <cppconn/resultset.h> 
#include <cppconn/statement.h> 
#include <cppconn/prepared_statement.h> 

using namespace std; 

int main(void) { 
    cout << endl; 
    cout << "Let's have MySQL count from 10 to 1..." << endl; 

    try { 
     sql::Driver *driver; 
     sql::Connection *con; 
     sql::Statement *stmt; 
     sql::PreparedStatement *pstmt1; 
     sql::PreparedStatement *pstmt2; 

     driver = get_driver_instance(); 
     con = driver->connect("tcp://127.0.0.1:3306", "root", "root"); 
     con->setSchema("test_schema"); 

     con->setAutoCommit(false); 

     stmt = con->createStatement(); 
     stmt->execute("DROP TABLE IF EXISTS tbl__test1"); 
     stmt->execute("DROP TABLE IF EXISTS tbl_test2"); 

     const string createTbl1Statement = "CREATE TABLE `tbl__test1` (" 
      "`id` int(11) NOT NULL AUTO_INCREMENT," 
      "`col_value` varchar(45) DEFAULT NULL," 
      "PRIMARY KEY (`id`)" 
      ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; 

     const string createTbl2Statement = "CREATE TABLE `tbl_test2` (" 
      "`id` int(11) NOT NULL AUTO_INCREMENT," 
      "`tbl_test1_id` int(11) NOT NULL," 
      "`col_value` varchar(45) DEFAULT NULL," 
      "PRIMARY KEY (`id`)" 
      ") ENGINE=InnoDB DEFAULT CHARSET=latin1;"; 

     stmt->execute(createTbl1Statement); 
     stmt->execute(createTbl2Statement); 

     pstmt1 = con->prepareStatement(
      "INSERT INTO tbl__test1(col_value) VALUES (?)"); 

     pstmt1->setString(1, "abcde"); 
     pstmt1->executeUpdate(); 

     stmt->execute("SET @lastInsertId = LAST_INSERT_ID()"); 

     const string insertTbl2 = 
      "INSERT INTO tbl_test2(tbl_test1_id, col_value)" 
        " VALUES (@lastInsertId, ?)"; 
     pstmt2 = con->prepareStatement(insertTbl2); 

     pstmt2->setString(1, "child value 1"); 
     pstmt2->executeUpdate(); 

     pstmt2->setString(1, "child value 2"); 
     pstmt2->executeUpdate(); 

     pstmt1->setString(1, "xpto"); 
     pstmt1->executeUpdate(); 

     stmt->execute("SET @lastInsertId = LAST_INSERT_ID()"); 

     pstmt2->setString(1, "child value 3"); 
     pstmt2->executeUpdate(); 

     pstmt2->setString(1, "child value 4"); 
     pstmt2->executeUpdate(); 

     con->commit(); 

     delete stmt; 
     delete pstmt1; 
     delete pstmt2; 

     delete con; 

    } catch (sql::SQLException &e) { 
     cout << "# ERR: SQLException in " << __FILE__; 
     cout << "(" << __FUNCTION__ << ") on line " << __LINE__ << endl; 
     cout << "# ERR: " << e.what(); 
     cout << " (MySQL error code: " << e.getErrorCode(); 
     cout << ", SQLState: " << e.getSQLState() << ")" << endl; 
    } 

    cout << endl; 

    return EXIT_SUCCESS; 
} 

結果是在表1中的2行:

2 rows inserted in table 1

和4行中的表2每一個適當地與鍵表1相關聯:

4 rows inserted in table 2

因此,關鍵點是在插入帶有所需的生成密鑰的新行之後調用LAST_INSERT_ID()。

+0

感謝您的回答,在您的回答中插入了一條記錄。我試圖插入多個記錄。基於我的理解,查詢LAST_INSERT_ID()只返回1個ID,是嗎? – r0ng

+0

在第一個示例中,它在表1中插入1行,在表2中插入1行。請參閱我的編輯,其中提供了一個完整示例,其中在兩個表中插入了多行。 – Doleron