mysql插入數據後返回自增ID的方法
mysql和oracle插入的時候有一個很大的區別是,oracle支持序列作id,mysql自己有一個列能夠作自增加字段,mysql在插入一條數據後,如何能得到到這個自增id的值呢?
方法一:是使用last_insert_idjava
mysql> SELECT LAST_INSERT_ID();
產生的ID 每次鏈接後保存在服務器中。這意味着函數向一個給定客戶端返回的值是該客戶端產生對影響AUTO_INCREMENT列的最新語句第一個 AUTO_INCREMENT值的。這個值不能被其它客戶端影響,即便它們產生它們本身的 AUTO_INCREMENT值。這個行爲保證了你可以找回本身的 ID 而不用擔憂其它客戶端的活動,並且不須要加鎖或處理。
每次mysql_query操做在mysql服務器上能夠理解爲一次「原子」操做, 寫操做經常須要鎖表的, 是mysql應用服務器鎖表不是咱們的應用程序鎖表。
值得注意的是,若是你一次插入了多條記錄,這個函數返回的是第一個記錄的ID值。
由於LAST_INSERT_ID是基於Connection的,只要每一個線程都使用獨立的Connection對象,LAST_INSERT_ID函數 將返回該Connection對AUTO_INCREMENT列最新的insert or update*做生成的第一個record的ID。這個值不能被其它客戶端(Connection)影響,保證了你可以找回本身的 ID 而不用擔憂其它客戶端的活動,並且不須要加鎖。使用單INSERT語句插入多條記錄, LAST_INSERT_ID返回一個列表。
LAST_INSERT_ID 是與table無關的,若是向表a插入數據後,再向表b插入數據,LAST_INSERT_ID會改變。
方法二:是使用max(id)
使用last_insert_id是基礎鏈接的,若是換一個窗口的時候調用則會一直返回10
若是不是頻繁的插入咱們也可使用這種方法來獲取返回的id值mysql
select max(id) from user;
這個方法的缺點是不適合高併發。若是同時插入的時候返回的值可能不許確。
方法三:是建立一個存儲過程,在存儲過程當中調用先插入再獲取最大值的操做sql
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()session
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的可是不知道爲何沒有測試成功。
方法6:selectkey:併發
其實在ibtias框架裏使用selectkey這個節點,並設置insert返回值的類型爲integer,就能夠返回這個id值。oracle
SelectKey在Mybatis中是爲了解決Insert數據時不支持主鍵自動生成的問題,他能夠很隨意的設置生成主鍵的方式。app
無論SelectKey有多好,儘可能不要遇到這種狀況吧,畢竟很麻煩。框架
屬性 | 描述 |
---|---|
keyProperty | selectKey 語句結果應該被設置的目標屬性。 |
resultType | 結果的類型。MyBatis 一般能夠算出來,可是寫上也沒有問題。MyBatis 容許任何簡單類型用做主鍵的類型,包括字符串。 |
order | 這能夠被設置爲 BEFORE 或 AFTER。若是設置爲 BEFORE,那麼它會首先選擇主鍵,設置 keyProperty 而後執行插入語句。若是設置爲 AFTER,那麼先執行插入語句,而後是 selectKey 元素-這和如 Oracle 數據庫類似,能夠在插入語句中嵌入序列調用。 |
statementType | 和前面的相 同,MyBatis 支持 STATEMENT ,PREPARED 和CALLABLE 語句的映射類型,分別表明 PreparedStatement 和CallableStatement 類型。 |
SelectKey須要注意order屬性,像Mysql一類支持自動增加類型的數據庫中,order須要設置爲after纔會取到正確的值。
像Oracle這樣取序列的狀況,須要設置爲before,不然會報錯。
另外在用Spring管理事務時,SelectKey和插入在同一事務當中,於是Mysql這樣的狀況因爲數據未插入到數據庫中,因此是得不到自動增加的Key。取消事務管理就不會有問題。
下面是一個xml和註解的例子,SelectKey很簡單,兩個例子就夠了:
<insert id="insert" parameterType="map"> insert into table1 (name) values (#{name}) <selectKey resultType="java.lang.Integer" keyProperty="id"> CALL IDENTITY() </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);
上面是註解的形式。
方法:7:使用<insert中的useGeneratedKeys 和keyProperty 兩個屬性
1.在Mybatis Mapper文件中添加屬性「useGeneratedKeys」和「keyProperty」,其中keyProperty是Java對象的屬性名,而不是表格的字段名。
2.Mybatis執行完插入語句後,自動將自增加值賦值給對象systemBean的屬性id。所以,可經過systemBean對應的getter方法獲取!
【注意事項】
1.Mybatis Mapper 文件中,「useGeneratedKeys」和「keyProperty」必須添加,並且keyProperty必定得和java對象的屬性名稱一直,而不是表格的字段名
2.java Dao中的Insert方法,傳遞的參數必須爲java對象,也就是Bean,而不能是某個參數。