2017-10-17 56 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