1. 程式人生 > 其它 >【轉載】詳解mysql插入資料後返回自增ID的七種方法_java

【轉載】詳解mysql插入資料後返回自增ID的七種方法_java

引言

mysql 和 oracle 插入的時候有一個很大的區別是:

  • oracle 支援序列做 id;
  • mysql 本身有一個列可以做自增長欄位。

mysql 在插入一條資料後,如何能獲得到這個自增 id 的值呢?

一:使用 last_insert_id()

SELECT LAST_INSERT_ID();

   1. 每次 mysql 的 query 操作在 mysql 伺服器上可以理解為一次“原子”操作, 寫操作常常需要鎖表, 這裡的鎖表是 mysql 應用伺服器鎖表不是我們的應用程式鎖表。

   2. 因為 LAST_INSERT_ID 是基於 Connection 的,只要每個執行緒都使用獨立的 Connection 物件,LAST_INSERT_ID 函式 將返回該 Connection 對 AUTO_INCREMENT列 最新的 insert or update* 作生成的第一個 record 的ID。這個值不能被其它客戶端(Connection)影響,保證了你能夠找回自己的 ID 而不用擔心其它客戶端的活動,而且不需要加鎖。使用單INSERT 語句插入多條記錄,  LAST_INSERT_ID 返回一個列表。
   3. LAST_INSERT_ID 是與 table 無關的,如果向表 a 插入資料後,再向表 b 插入資料,LAST_INSERT_ID 會改變。

二:使用 max(id)

如果不是頻繁的插入我們也可以使用這種方法來獲取返回的id值

select max(id) from user;

這個方法的缺點是不適合高併發。如果同時插入的時候返回的值可能不準確。

三:建立一個儲存過程

在儲存過程中呼叫先插入再獲取最大值的操作。

DELIMITER $$
DROP PROCEDURE IF EXISTS `test` $$
CREATE DEFINER=`root`@`localhost` PROCEDURE `test`(in name varchar(100),out oid int)
BEGIN
 insert into user(loginname) values(name);
 select max(id) from user into oid;
 select oid;
END $$
DELIMITER ;
call test('gg',@id);

四:使用 @@identity

select @@IDENTITY

    @@identity 是表示的是最近一次向具有 identity 屬性(即自增列)的表插入資料時對應的自增列的值,是系統定 義的全域性變數。一般系統定義的全域性變數都是以@@開頭,使用者自定義變數以@開頭。比如有個表 A,它的自增列是 id,當向 A 表插入一行資料後,如果插入資料 後自增列的值自動增加至 101,則通過select @@identity得到的值就是 101。使用@@identity的前提是在進行 insert 操作後,執行 select @@identity 的時候連線沒有關閉,否則得到的將是 NULL 值。

五:是使用 getGeneratedKeys()

Connection conn = ;
Serializable ret = null;
PreparedStatement state = .;
ResultSet rs=null;
try {
  state.executeUpdate();
  rs = state.getGeneratedKeys();
  if (rs.next()) {
    ret = (Serializable) rs.getObject(1);
  }   
} catch (SQLException e) {
}
return ret;

總結:在 mysql 中做完插入之後獲取 id 在高併發的時候是很容易出錯的。另外 last_insert_id 雖然是基於 session 的但是不知道為什麼沒有測試成功。    

六:selectkey:

其實在 ibtias 框架裡使用 selectkey 這個節點,並設定 insert 返回值的型別為 integer,就可以返回這個 id 值。

SelectKey 在Mybatis中是為了解決 Insert 資料時不支援主鍵自動生成的問題,他可以很隨意的設定生成主鍵的方式。

不管 SelectKey 有多好,儘量不要遇到這種情況吧,畢竟很麻煩。

SelectKey 需要注意 order 屬性:

  • Mysql 一類支援自動增長型別的資料庫中,order 需要設定為 after 才會取到正確的值。
  • Oracle 這樣取序列的情況,需要設定為 before,否則會報錯。

xml 的例子:

<insert id="insert" parameterType="map"> 
  insert into table1 (name) values (#{name}) 
  <selectKey resultType="java.lang.Integer" keyProperty="id"> 
   SELECT LAST_INSERT_ID() AS id 
  </selectKey> 
</insert>

上面 xml 的傳入引數是 map,selectKey 會將結果放到入引數 map 中。用 POJO 的情況一樣,但是有一點需要注意的是,keyProperty 對應的欄位在 POJO 中必須有相應的 setter 方法,setter 的引數型別還要一致,否則會報錯。

註解的形式:

@Insert("insert into table2 (name) values(#{name})") 
@SelectKey(statement="call identity()", keyProperty="nameId", before=false, resultType=int.class) 
int insertTable2(Name name); 

方法七:使用<insert 中的useGeneratedKeys 和 keyProperty 兩個屬性

1.在Mybatis Mapper檔案中新增屬性 “useGeneratedKeys”和“keyProperty”,其中 keyProperty 是 Java 物件的屬性名,而不是表格的欄位名。

<insert id="insert" parameterType="Spares"   
    useGeneratedKeys="true" keyProperty="id">  
    insert into system(name) values(#{name})  
</insert> 

2.Mybatis 執行完插入語句後,自動將自增長值賦值給物件 systemBean 的屬性id。因此,可通過 systemBean 對應的 getter 方法獲取!

int count = systemService.insert(systemBean);  
int id = systemBean.getId(); //獲取到的即為新插入記錄的ID 

【注意事項】

1.Mybatis Mapper 檔案中,“useGeneratedKeys” 和 “keyProperty” 必須新增,而且 keyProperty 一定得和 java 物件的屬性名稱一直,而不是表格的欄位名。

2. java Dao中的 Insert 方法,傳遞的引數必須為 java 物件,也就是 Bean,而不能是某個引數。

原文:https://blog.csdn.net/qq_30715329/article/details/80868411