MYSQL獲取自增主鍵【4種方法】 通常我們在應用中對mysql執行了insert操作後,需要獲取插入記錄的自增主鍵。本文將介紹java環境下的4種方法獲取insert後的記錄主鍵auto_increment的值: 通過JDBC2.0提供的insertRow()方式 通過JDBC3.0提供的getGeneratedKeys()方式 通過SQL select LAST_INSERT_ID()函數 通過SQL @@IDENTITY 變量 1. 通過JDBC2.0提供的insertRow()方式 自jdbc2.0以來,可以通過下面的方式執行。 [java] 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] 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] 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. 通過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] INSERT INTO t VALUES -> (NULL, 'Mary'), (NULL, 'Jane'), (NULL, 'Lisa'); LAST_INSERT_ID(), @@IDENTITY都只會返回'Mary'所在的那條記錄的generatedKey