MYSQL擷取自增主鍵【4種方法】

來源:互聯網
上載者:User

標籤:

  • 通過JDBC2.0提供的insertRow()方式
  • 通過JDBC3.0提供的getGeneratedKeys()方式
  • 通過SQL select LAST_INSERT_ID()函數
  • 通過SQL @@IDENTITY 變數

 

1. 通過JDBC2.0提供的insertRow()方式

自jdbc2.0以來,可以通過下面的方式執行。

 

[java] view plain copy print?
  1. Statement stmt = null;  
  2. ResultSet rs = null;  
  3. try {  
  4.     stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,  // 建立Statement  
  5.                                 java.sql.ResultSet.CONCUR_UPDATABLE);  
  6.     stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");  
  7.     stmt.executeUpdate(                                                // 建立demo表  
  8.             "CREATE TABLE autoIncTutorial ("  
  9.             + "priKey INT NOT NULL AUTO_INCREMENT, "  
  10.             + "dataField VARCHAR(64), PRIMARY KEY (priKey))");  
  11.     rs = stmt.executeQuery("SELECT priKey, dataField "                 // 檢索資料  
  12.        + "FROM autoIncTutorial");  
  13.     rs.moveToInsertRow();                                              // 移動遊標到待插入行(未建立的偽記錄)  
  14.     rs.updateString("dataField", "AUTO INCREMENT here?");              // 修改內容  
  15.     rs.insertRow();                                                    // 插入記錄  
  16.     rs.last();                                                         // 移動遊標到最後一行  
  17.     int autoIncKeyFromRS = rs.getInt("priKey");                        // 擷取剛插入記錄的主鍵preKey  
  18.     rs.close();  
  19.     rs = null;  
  20.     System.out.println("Key returned for inserted row: "  
  21.         + autoIncKeyFromRS);  
  22. }  finally {  
  23.     // rs,stmt的close()清理  
  24. }  
Statement stmt = null;ResultSet rs = null;try {    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,  // 建立Statement                                java.sql.ResultSet.CONCUR_UPDATABLE);    stmt.executeUpdate("DROP TABLE IF EXISTS autoIncTutorial");    stmt.executeUpdate(                                                // 建立demo表            "CREATE TABLE autoIncTutorial ("            + "priKey INT NOT NULL AUTO_INCREMENT, "            + "dataField VARCHAR(64), PRIMARY KEY (priKey))");    rs = stmt.executeQuery("SELECT priKey, dataField "                 // 檢索資料       + "FROM autoIncTutorial");    rs.moveToInsertRow();                                              // 移動遊標到待插入行(未建立的偽記錄)    rs.updateString("dataField", "AUTO INCREMENT here?");              // 修改內容    rs.insertRow();                                                    // 插入記錄    rs.last();                                                         // 移動遊標到最後一行    int autoIncKeyFromRS = rs.getInt("priKey");                        // 擷取剛插入記錄的主鍵preKey    rs.close();    rs = null;    System.out.println("Key returned for inserted row: "        + autoIncKeyFromRS);}  finally {    // rs,stmt的close()清理}

優點:早期較為通用的做法

 

缺點:需要操作ResultSet的遊標,代碼冗長。

2. 通過JDBC3.0提供的getGeneratedKeys()方式 [java] view plain copy print?
  1. Statement stmt = null;  
  2. ResultSet rs = null;  
  3. try {  
  4.     stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,  
  5.                                 java.sql.ResultSet.CONCUR_UPDATABLE);    
  6.     // ...  
  7.     // 省略若干行(如上例般建立demo表)  
  8.     // ...  
  9.     stmt.executeUpdate(  
  10.             "INSERT INTO autoIncTutorial (dataField) "  
  11.             + "values (‘Can I Get the Auto Increment Field?‘)",  
  12.             Statement.RETURN_GENERATED_KEYS);                      // 向驅動指明需要自動擷取generatedKeys!  
  13.     int autoIncKeyFromApi = -1;  
  14.     rs = stmt.getGeneratedKeys();                                  // 擷取自增主鍵!  
  15.     if (rs.next()) {  
  16.         autoIncKeyFromApi = rs.getInt(1);  
  17.     }  else {  
  18.         // throw an exception from here  
  19.     }   
  20.     rs.close();  
  21.     rs = null;  
  22.     System.out.println("Key returned from getGeneratedKeys():"  
  23.         + autoIncKeyFromApi);  
  24. }  finally { ... }  
Statement stmt = null;ResultSet rs = null;try {    stmt = conn.createStatement(java.sql.ResultSet.TYPE_FORWARD_ONLY,                                java.sql.ResultSet.CONCUR_UPDATABLE);      // ...    // 省略若干行(如上例般建立demo表)    // ...    stmt.executeUpdate(            "INSERT INTO autoIncTutorial (dataField) "            + "values (‘Can I Get the Auto Increment Field?‘)",            Statement.RETURN_GENERATED_KEYS);                      // 向驅動指明需要自動擷取generatedKeys!    int autoIncKeyFromApi = -1;    rs = stmt.getGeneratedKeys();                                  // 擷取自增主鍵!    if (rs.next()) {        autoIncKeyFromApi = rs.getInt(1);    }  else {        // throw an exception from here    }     rs.close();    rs = null;    System.out.println("Key returned from getGeneratedKeys():"        + autoIncKeyFromApi);}  finally { ... }
這種方式只需要2個步驟:1. 在executeUpdate時啟用自動擷取key; 2.調用Statement的getGeneratedKeys()介面 優點:1. 操作方便,代碼簡潔2. jdbc3.0的標準3. 效率高,因為沒有額外訪問資料庫 這裡補充下,a.在jdbc3.0之前,每個jdbc driver的實現都有自己擷取自增主鍵的介面。在mysql jdbc2.0的driver org.gjt.mm.mysql中,getGeneratedKeys()函數就實現在org.gjt.mm.mysql.jdbc2.Staement.getGeneratedKeys()中。這樣直接引用的話,移植性會有很大影響。JDBC3.0通過標準的getGeneratedKeys很好的彌補了這點。b.關於getGeneratedKeys(),官網還有更詳細解釋:OracleJdbcGuide 3. 通過SQL select LAST_INSERT_ID() [java] view plain copy print?
  1. Statement stmt = null;  
  2. ResultSet rs = null;  
  3. try {  
  4.     stmt = conn.createStatement();  
  5.     // ...  
  6.     // 省略建表  
  7.     // ...  
  8.     stmt.executeUpdate(  
  9.             "INSERT INTO autoIncTutorial (dataField) "  
  10.             + "values (‘Can I Get the Auto Increment Field?‘)");  
  11.     int autoIncKeyFromFunc = -1;  
  12.     rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");             // 通過額外查詢擷取generatedKey  
  13.     if (rs.next()) {  
  14.         autoIncKeyFromFunc = rs.getInt(1);  
  15.     }  else {  
  16.         // throw an exception from here  
  17.     }   
  18.     rs.close();  
  19.     System.out.println("Key returned from " +  
  20.                        "‘SELECT LAST_INSERT_ID()‘: " +  
  21.                        autoIncKeyFromFunc);  
  22. }  finally {...}  
Statement stmt = null;ResultSet rs = null;try {    stmt = conn.createStatement();    // ...    // 省略建表    // ...    stmt.executeUpdate(            "INSERT INTO autoIncTutorial (dataField) "            + "values (‘Can I Get the Auto Increment Field?‘)");    int autoIncKeyFromFunc = -1;    rs = stmt.executeQuery("SELECT LAST_INSERT_ID()");             // 通過額外查詢擷取generatedKey    if (rs.next()) {        autoIncKeyFromFunc = rs.getInt(1);    }  else {        // throw an exception from here    }     rs.close();    System.out.println("Key returned from " +                       "‘SELECT LAST_INSERT_ID()‘: " +                       autoIncKeyFromFunc);}  finally {...}
這種方式沒什麼好說的,就是額外查詢一次函數LAST_INSERT_ID().優點:簡單方便缺點:相對JDBC3.0的getGeneratedKeys(),需要額外多一次資料庫查詢。 補充:1. 這個函數,在mysql5.5手冊的定義是:“returns a BIGINT (64-bit) value representing the first automatically generated value successfully inserted for an AUTO_INCREMENT column as a result of the most recently executed INSERT statement.”。文檔點此2. 這個函數,在connection維度上是“安全執行緒的”。就是說,每個mysql串連會有個獨立儲存LAST_INSERT_ID()的結果,並且 只會被當前串連最近一次insert操作所更新。也就是2個串連同時執行insert語句時候,分別調用的LAST_INSERT_ID()不會相互覆蓋。舉個栗子:串連A插入表後LAST_INSERT_ID()返回100,串連B插入表後LAST_INSERT_ID()返回101,但是串連A重複執行LAST_INSERT_ID()的時候,始終返回100,而不是101。這個可以通過監控mysql串連數和執行結果來驗證,這裡不詳述實驗過程。3.  在上面那點的基礎上,如果在同一個串連的前提下同時執行insert,那可能2次操作的傳回值會相互覆蓋。因為LAST_INSERT_ID()的隔離程度是串連層級的。這點,getGeneratedKeys()是可以做的更好,因為getGeneratedKeys()是statement層級的。同個connection的多次statement,getGeneratedKeys()是不會被相互覆蓋。 4. 通過SQL SELECT @@IDENTITY這個方式和LAST_INSERT_ID()效果是一樣的。官網文檔如此表述:“This variable is a synonym for the last_insert_id variable. It exists for compatibility with other database systems. You can read its value with SELECT @@identity, and set it using SET identity.” 文檔點此  重要補充:無論是SELECT LAST_INSERT_ID()還是SELECT @@IDENTITY,對於一條insert語句插入多條記錄,永遠只會返回第一條插入記錄的generatedKey.如: [java] view plain copy print?
  1. INSERT INTO t VALUES  
  2.     -> (NULL, ‘Mary‘), (NULL, ‘Jane‘), (NULL, ‘Lisa‘);  
INSERT INTO t VALUES    -> (NULL, ‘Mary‘), (NULL, ‘Jane‘), (NULL, ‘Lisa‘);
LAST_INSERT_ID(), @@IDENTITY都只會返回‘Mary‘所在的那條記錄的generatedKey小結所以,最好還是通過JDBC3 提供的getGeneratedKeys()函數來擷取insert記錄的主鍵。不但簡單,而且效率高。 在mybatis中,就有相關設定: [java] view plain copy print?
  1. <insert id="save" parameterType="MappedObject" useGeneratedKeys="true" keyProperty="id">  
  2. </insert>  

(轉)MYSQL擷取自增主鍵【4種方法】

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.