實際場景可能複雜,簡單還原場景html
user 字段名稱 | 類型 ---|--- id | int(10) auto_increment name | varchar(50)java
score 字段名稱 | 類型 ---|--- id | int(10) auto_increment user_id | int(10) score | int(3)mysql
user.mapper 非相關 省略spring
<insert id="insert" parameterType="User" > <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> SELECT LAST_INSERT_ID() AS id </selectKey> insert into user (id, name) values (#{id,jdbcType=INTEGER}, #{name,jdbcType=CHAR} ) </insert>
score.mapper 非相關 省略sql
<insert id="insert" parameterType="User" > <selectKey resultType="java.lang.Integer" order="AFTER" keyProperty="id"> SELECT LAST_INSERT_ID() AS id </selectKey> insert into score (id, user_id,score) values (#{id,jdbcType=INTEGER}, #{userId,jdbcType=INTEGER}, #{score,jdbcType=INTEGER} ) </insert>
插入user後須要插入sore須要獲取到user_id,非同一事物中服務器
在線上出現插入user後獲取到id不爲當前插入後的id而爲score表的id(系統存在併發狀況可能存在多個插入同時操做)mybatis
LAST_INSERT_ID(), LAST_INSERT_ID(expr) 沒有參數, LAST_INSERT_ID()返回一個64位值,表示AUTO_INCREMENT因爲最近執行的INSERT 語句而致使爲列成功插入的第一個自動生成的值 。在此以前,該值具備BIGINT UNSIGNEDMySQL 5.6.9 類型BIGINT(簽名)。LAST_INSERT_ID()若是沒有成功插入行,則該值 保持不變。 使用一個參數, LAST_INSERT_ID()返回MySQL 5.6.9以前的無符號整數,一個有符號的整數。 例如,在插入生成AUTO_INCREMENT值的行以後 ,能夠獲得以下值: mysql> SELECT LAST_INSERT_ID(); -> 195 當前執行的語句不影響其值 LAST_INSERT_ID()。假設您AUTO_INCREMENT使用一個語句生成值,而後LAST_INSERT_ID()在多行INSERT語句中引用 ,該行將行插入到具備其自身AUTO_INCREMENT列的表中 。LAST_INSERT_ID()第二個聲明中的價值 將保持穩定; 其第二行和更後一行的值不受早期行插入的影響。(可是,若是混合引用 LAST_INSERT_ID()和 效果未定義。) LAST_INSERT_ID(expr) 若是之前的語句返回錯誤,則值爲 LAST_INSERT_ID()undefined。對於事務表,若是語句因爲錯誤而回滾,則該值將 LAST_INSERT_ID()保持未定義。對於手動 ROLLBACK,LAST_INSERT_ID() 交易前的值不會恢復; 它仍然是在它的位置 ROLLBACK。 在MySQL 5.6.15以前,若是使用複製過濾規則,則此函數未正確複製。(Bug#17234370,Bug#69861) 在存儲的例程(過程或函數)或觸發器LAST_INSERT_ID()的正文內,更改的值與 在這些對象的體外執行的語句相同。存儲的例程或觸發器對其值的影響 LAST_INSERT_ID()由如下語句所看到取決於例程的種類: 若是存儲過程執行更改值的語句,則更改的值LAST_INSERT_ID()將由過程調用後面的語句看到。 對於存儲的功能和更改值的觸發器,當函數或觸發器結束時,該值將被恢復,所以如下語句將不會看到更改的值。 生成的ID在每一個鏈接的基礎上維護在服務器中 。這意味着函數返回給給定客戶端的AUTO_INCREMENT值是爲該客戶端影響AUTO_INCREMENT列的最新語句生成的第一個 值 。即便這些AUTO_INCREMENT值生成了本身的值,也不會受到其餘客戶端的影響 。此行爲確保每一個客戶端能夠檢索本身的ID,而不用擔憂其餘客戶端的活動,而且不須要鎖或事務。
其中app
生成的ID在每一個鏈接的基礎上維護在服務器中 。這意味着函數返回給給定客戶端的AUTO_INCREMENT值是爲該客戶端影響AUTO_INCREMENT列的最新語句生成的第一個 值 。即便這些AUTO_INCREMENT值生成了本身的值,也不會受到其餘客戶端的影響 。此行爲確保每一個客戶端能夠檢索本身的ID,而不用擔憂其餘客戶端的活動,而且不須要鎖或事務
一個insert執行流程函數
SqlSessionTemplate.insert-->DefaultSqlSession.insert-->SimpleExecutor.update-->PreparedStatementHandler.update
其中insert into user 先執行,其後執行 select last_inset id (1.ps.execute() 2.keyGenerator.processAfter)
經過debug能夠看到經過SpringManagedTransaction.getConnection兩次open一次直接返回一次能夠肯定兩次操做爲同一Connection(非併發環境)
同時模擬insrt後經過mysql工具鏈接插入數據後返回id正確
生成的ID在每一個鏈接的基礎上維護在服務器中 。這意味着函數返回給給定客戶端的AUTO_INCREMENT值是爲該客戶端影響AUTO_INCREMENT列的最新語句生成的第一個 值 。即便這些AUTO_INCREMENT值生成了本身的值,也不會受到其餘客戶端的影響 。此行爲確保每一個客戶端能夠檢索本身的ID,而不用擔憂其餘客戶端的活動,而且不須要鎖或事務
以及
經過debug能夠看到經過SpringManagedTransaction.getConnection兩次open一次直接返回一次能夠肯定兩次操做爲同一Connection
無(對比僅供參考)
替換last_inset id 經過插入後再查詢name獲取id