最近在搞一個電商系統中由于業務需求,需要在插入一條產品信息后返回產品Id,剛開始遇到一些坑,這里做下筆記,以防今后忘記。
類似下面這段代碼一樣獲取插入后的主鍵
1
2
3
4
5
6
7
8
|
User user = new User(); user.setUserName( "chenzhou" ); user.setPassword( "xxxx" ); System.out.println( "插入前主鍵為:" +user.getUserId()); userDao.insertAndGetId(user); //插入操作 System.out.println( "插入后主鍵為:" +user.getUserId()); |
經過查詢網上資料,發現大致有兩種方式。
方式一:
在實體類的映射文件 "*Mapper.xml" 這樣寫:
1
2
3
4
|
< insert id = "insertAndGetId" useGeneratedKeys = "true" keyProperty = "userId" parameterType = "com.chenzhou.mybatis.User" > insert into user(userName,password,comment) values(#{userName},#{password},#{comment}) </ insert > |
Tips:
useGeneratedKeys="true" 表示給主鍵設置自增長
keyProperty="userId" 表示將自增長后的Id賦值給實體類中的userId字段。
parameterType="com.chenzhou.mybatis.User" 這個屬性指向傳遞的參數實體類
這里提醒下,<insert></insert> 中沒有resultType屬性,不要亂加。
實體類中uerId 要有getter() and setter(); 方法
由于我在MySQL數據庫中建表時候已經設置了字段自增長,故最終我選擇了第二種方式。
第二種方式:
同樣在實體類的映射文件 "*Mapper.xml" 但是要這樣寫:
1
2
3
4
5
6
7
|
<!-- 插入一個商品 --> < insert id = "insertProduct" parameterType = "domain.model.ProductBean" > < selectKey resultType = "java.lang.Long" order = "AFTER" keyProperty = "productId" > SELECT LAST_INSERT_ID() </ selectKey > INSERT INTO t_product(productName,productDesrcible,merchantId)values(#{productName},#{productDesrcible},#{merchantId}); </ insert > |
Tips:
<insert></insert> 中沒有resultType屬性,但是<selectKey></selectKey> 標簽是有的。
order="AFTER" 表示先執行插入語句,之后再執行查詢語句。
可被設置為 BEFORE 或 AFTER。
如果設置為 BEFORE,那么它會首先選擇主鍵,設置 keyProperty 然后執行插入語句。
如果設置為 AFTER,那么先執行插入語句,然后是 selectKey 元素-這和如 Oracle 數據庫相似,可以在插入語句中嵌入序列調用
keyProperty="userId" 表示將自增長后的Id賦值給實體類中的userId字段。
SELECT LAST_INSERT_ID() 表示MySQL語法中查詢出剛剛插入的記錄自增長Id.
實體類中uerId 要有getter() and setter(); 方法
實現需求,上面那些就足夠了。
這里如果有興趣的,請繼續聽我講一個Mybatis中可能誤入的坑。
為什么Mybatis 中修改添加方法為有返回值后,雖然提示插入數據庫成功并且也能讀取插入的數據,但是當你打開數據庫后就是看不到插入的數據?
如果在實現上述需求時,想插入后返回主鍵的話,切記不要這樣寫。
1
2
3
4
5
6
7
8
9
10
|
@Override public Long insertProduct(ProductBean productBean) { // TODO Auto-generated method stub SqlSession session = MybatisJDBCUtil.currentSession(); ProductIDao productIDao = session.getMapper(ProductIDao. class ); // 這里*.class // 必須對應DAO的接口層 return productIDao.insertProduct(productBean); } |
Why?
因為如果你是像上面這樣寫,那么執行后返回的也不是你想要的主鍵Id,而是執行數據庫語句后受影響的行數。
而且,當你執行后你會發現提示插入成功,你用代碼也可以讀取出插入的數據,但是永遠只有一條記錄。
并且,你打開數據庫會發現,數據庫中沒有插入成功任何數據。
我在這里郁悶了N久,終于發現了關鍵所在。
有返回值和沒返回值的區別在于:
有返回值的只是對數據庫只讀模式訪問數據庫,對數據庫數據不會有任何修改,比如各種方式的查詢。
無返回值的則會以讀寫模式訪問數據庫,會對數據庫中的數據進行修改,比如刪除,增加。
除此之外,根據個人理解應該mybatis在執行插入語句時會先緩存到構造的一個類似session集合中,然后才去調用底層驅動去操作修改數據庫。
1
2
|
session.commit(); MybatisJDBCUtil.closeSession(); |
沒有返回值得才有上面這兩條語句,也就是說執行了這兩條語句才會真正執行插入到數據庫,對數據庫的數據進行修改。
相反,有返回值的就沒有執行這兩條語句,所以只是在自己構造的session中執行了添加語句,但是并沒有提交到數據庫中,故數據庫中是沒有任何記錄的。
這也就解釋了為什么Mybatis 中修改添加方法為有返回值后,雖然提示插入數據庫成功,但是當你打開數據庫看不到插入的數據。
Mybatis中插入語句方法種不要有返回值,像這樣寫是正確的。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
@Override public void insertProduct(ProductBean productBean) { // TODO Auto-generated method stub SqlSession session = MybatisJDBCUtil.currentSession(); ProductIDao productIDao = session.getMapper(ProductIDao. class ); // 這里*.class // 必須對應DAO的接口層 productIDao.insertProduct(productBean); session.commit(); MybatisJDBCUtil.closeSession(); } |
以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。
原文鏈接:http://www.cnblogs.com/xingyunblog/p/6243179.html