一.為什么要獲取insert的id
寫了測試類測試插入,插入之后用select查詢出來進行Assert
插入成功后,不管Select對比的結果成功還是失敗,都希望刪除掉測試插入的結果
二.運行環境
mysql自增主鍵
mapper中的insert下是,這是通過mybatis_generator自動生成的,最新版本1.3.6.
<selectKey keyProperty="id" order="BEFORE" resultType="java.lang.Long">
SELECT LAST_INSERT_ID()
</selectKey>
然后
goodsClassService.insertGoodsClass(goodsclass);
但是用斷點調試發現goodsclass的id一直是0,這讓我不得其解.
三.原因
感覺Mybatis的這個自動生成的xml有問題.
參考:http://blog.csdn.net/slvher/article/details/42298355
6. last_insert_id()的值是由MySQL server來維護的,而且是為每條連接維護獨立的值,也即,某條連接調用last_insert_id()獲取到的值是這條連接最近一次insert操作執行后的自增值,該值不會被其它連接的sql語句所影響。這個行為保證了不同的連接能正確地獲取到它最近一次insert sql執行所插入的行的自增值,也就是說,last_insert_id()的值不需要通過加鎖或事務機制來保證其在多連接場景下的正確性。
mybatis的連接和客戶端,比如workbench連接不同,last_insert_id()不能進行比較.
每一次測試運行都是新的連接,所last_insert_id()都是0,
mybatis默認生成的selectKey是在before之前,手動插入id為0,
如果給自增列插入0或者null,那么自增列設置為根據當前最大的id+1
如果批量插入就有問題了
Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Duplicate entry '66671' for key 'PRIMARY'
第一次插入id是0,可以自增.因為用了連接池,即使關閉了sqlsession也可能是同一個連接,第二次插入取出了last_insert_id()為66671,再插入,重復id錯誤.
三.解決辦法
將上面的改為
<selectKey keyProperty="id" order="AFTER" resultType="java.lang.Long">
SELECT LAST_INSERT_ID()
</selectKey>
這是插入之后取出SELECT LAST_INSERT_ID(),插入的時候id默認不插入,mysql會自動幫我們自增.
插入之后二中的goodsclass的id就變為last_id,可以取出來用了.
所以我覺得mybatis_generator這個配置操作有點小bug的
四.測試代碼
省略了部分Assert代碼
插入成功后,無論查詢對比失敗或者成功,都將插入的數據刪掉.
//測試添加商品分類 //isok()返回狀態碼200 @Test public void test_add_goodsClass() throws Exception { //測試插入是否成功 String ret=mockMvc.perform(post("/goods_class/add") .param("pid","1")) .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); ObjectMapper objectMapper=new ObjectMapper(); Map<String,String> map=objectMapper.readValue(ret,Map.class); Assert.assertNotNull(map); Long last_insert_id=Long.valueOf(map.get("id")); Assert.assertNotEquals(last_insert_id,Long.valueOf(0)); try {
//測試插入結果 Goodsclass goodsclass= goodsClassService.getGoodsClassById(last_insert_id); Assert.assertEquals(goodsclass.getParent().getId(),Long.valueOf(1)); } finally { goodsClassService.deleteGoodsClassById(last_insert_id); Assert.assertNull(goodsClassService.getGoodsClassById(last_insert_id)); } }