前面對MyBatis框架的學習中,我們對Mapper.xml映射文件多少有些瞭解。本文將對Mapper.xml映射文件作更加細緻的梳理,首先從Mapper.xml文件中的輸入和輸出映射開始。本文案例代碼的編寫是建立在前文MyBatis框架的學習(三)案例基礎之上的!
輸入映射和輸出映射
Mapper.xml映射文件中定義了操作數據庫的sql,每個sql是一個statement,映射文件是mybatis的核心。
parameterType(輸入類型)
傳遞簡單類型
傳遞簡單類型,我之前已講過,這裏只給出案例,如下:
傳遞pojo對象
MyBatis使用ognl表達式解析對象字段的值,#{}或者${}括號中的值爲pojo屬性名稱。傳遞pojo對象之前也已講過,這裏同樣只給出案例,如下:
傳遞pojo包裝對象
開發中通過pojo傳遞查詢條件,查詢條件是綜合的查詢條件,不僅包括用戶查詢條件還包括其它的查詢條件(比如將用戶購買商品信息也作爲查詢條件),這時可以使用包裝對象傳遞輸入參數。即pojo類中包含pojo類。 例如這樣一個需求:根據用戶id查詢用戶信息,查詢條件放到QueryVo類的user屬性中。有需求,就要解決它。我們可在cn.itheima.mybatis.po包下新建一個QueryVo類,如下:
public class QueryVo {
private User user;
public User
getUser () {
return user;
}
public void setUser (User user) {
this .user = user;
}
}
接下來我們就要在UserMapper.xml映射文件中編寫sql語句了,即在UserMapper.xml映射文件中添加如下配置信息:
<
select id=
"getUserByQueryVo" parameterType=
"queryvo" resultType=
"user" >
select *
from user
where id=
#{user.id};
</
select >
使用包裝類型查詢用戶時,可使用ognl從對象中取屬性值,並且如果是包裝對象可以使用.
操作符來取內容的屬性。 然後在UserMapper接口中添加如下方法:
User get
UserByQueryVo (
QueryVo query Vo );
最後在UserMapperTest單元測試類編寫如下測試方法:
@Test
public void testGetUserByQueryVo () {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
QueryVo queryVo =
new QueryVo();
User user =
new User();
user.setId(
10 );
queryVo.setUser(user);
User result = userMapper.getUserByQueryVo(queryVo);
System.
out .println(result);
sqlSession.close();
}
傳遞HashMap
傳遞HashMap在實際開發中用的很少,但我還是要講一下。以例明示——傳遞HashMap綜合查詢用戶信息,在UserMapper.xml映射文件中添加如下配置信息:
<select id ="findUserByHashmap" parameterType ="hashmap" resultType ="user" >
select * from user where id=#{id} and username like '%${username}%'
</select >
上面的id和username是HashMap的key。 接着在UserMapper接口中添加如下方法:
User findUserByHashmap(HashMap<
String ,
Object > map);
最後在UserMapperTest單元測試類編寫如下測試方法:
@Test
public void testFindUserByHashmap() {
SqlSession sqlSession
= sqlSessionFactory
. openSession();
UserMapper userMapper
= sqlSession
. getMapper(UserMapper
. class);
HashMap
< String , Object
> map = new HashMap
< String , Object
> ();
map . put(
"id" ,
30 );
map . put(
"username" ,
"趙雲" );
User result
= userMapper
. findUserByHashmap(
map );
System
. out
. println(result);
sqlSession
. close();
}
resultType(輸出類型)
輸出簡單類型
有這樣一個需求:查詢用戶表中的記錄數。有需求就要解決它,我們首先在UserMapper.xml映射文件中添加如下配置信息:
<select id ="getUserCount" resultType ="int" >
SELECT COUNT(*) FROM `user`
</select >
接着在UserMapper接口中添加如下方法:
Integer getUserCount();
最後在UserMapperTest單元測試類編寫如下測試方法:
@Test
public void testGetUserCount () {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
int count = userMapper.getUserCount();
System.
out .println(count);
sqlSession.close();
}
輸出簡單類型必須查詢出來的結果集只有一條記錄,最終將第一個字段的值轉換爲輸出類型。
輸出pojo對象
輸出pojo對象,我之前已講過,這裏只給出案例,如下:
輸出pojo列表
輸出pojo列表,我之前同樣已講過,這裏只給出案例,如下: 這兒再給出一個案例——查詢訂單的所有信息。我們mybatis數據庫中已經有了訂單表(orders表)了,如下: 大家可能想到不會想,就會像下面這樣做。首先在cn.itheima.mybatis.po包下新建一個Orders類:
public class Orders {
private Integer id;
private Integer userId;
private String number;
private Date createtime;
private String note;
public Integer
getId () {
return id;
}
public void setId (Integer id) {
this .id = id;
}
public Integer
getUserId () {
return userId;
}
public void setUserId (Integer userId) {
this .userId = userId;
}
public String
getNumber () {
return number;
}
public void setNumber (String number) {
this .number = number ==
null ?
null : number.trim();
}
public Date
getCreatetime () {
return createtime;
}
public void setCreatetime (Date createtime) {
this .createtime = createtime;
}
public String
getNote () {
return note;
}
public void setNote (String note) {
this .note = note ==
null ?
null : note.trim();
}
}
然後在cn.itheima.mybatis.mapper包下創建一個OrderMapper.xml映射文件,其內容爲:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace ="cn.itheima.mybatis.mapper.OrderMapper" >
<select id ="getOrderList" resultType ="orders" >
select * from orders;
</select >
</mapper >
緊接着在cn.itheima.mybatis.mapper包下創建一個OrderMapper接口:
public interface OrderMapper {
List<Orders> getOrderList();
}
最後創建OrderMapper接口的單元測試類——OrderMapperTest.java,修改OrderMapperTest類的內容爲:
public class OrderMapperTest {
private SqlSessionFactory sqlSessionFactory =
null ;
@Before
public void init ()
throws IOException {
SqlSessionFactoryBuilder sqlSessionFactoryBuilder =
new SqlSessionFactoryBuilder();
InputStream inputStream = Resources.getResourceAsStream(
"SqlMapConfig.xml" );
sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream);
}
@Test
public void testGetOrderList () {
SqlSession sqlSession = sqlSessionFactory.openSession();
OrderMapper orderMapper = sqlSession.getMapper(OrderMapper.class);
List<Orders> orderList = orderMapper.getOrderList();
for (Orders orders : orderList) {
System.out.println(orders);
}
sqlSession.close();
}
}
在testGetOrderList方法中的以下代碼處打一個斷點:
for (Orders orders : orderList) {
然後以Debug模式運行該方法,可發現查詢出來的每一個Orders對象中的userId屬性值都爲null,如下: 很明顯這並不是我們所想要的結果。爲了達到我們預期的效果,可爲user_id列加別名,即將OrderMapper.xml映射文件中id爲getOrderList的select元素修改爲:
<
select id=
"getOrderList" resultType=
"orders" >
select id,user_id userId,number,createtime,note
from orders;
</
select >
只要你返回的結果的列名和pojo中的屬性一致,就可以自動映射了。 這樣當我們再次以Debug模式運行testGetOrderList方法,就能達到我們預期的結果了,如下: 這種方式比較簡單粗暴,其實要達到我們所預期的效果,還有另一種方式,那就是使用resultMap這個屬性,下面我就會講到。
resultMap
resultMap可以指定pojo將查詢結果映射爲pojo,但需要pojo的屬性名和sql查詢的列名一致方可映射成功。如果sql查詢字段名和pojo的屬性名不一致,可以通過resultMap將字段名和屬性名作一個對應關係 ,resultMap實質上還需要將查詢結果映射到pojo對象中。 resultMap可以實現將查詢結果映射爲複雜類型的pojo,比如在查詢結果映射對象中包括pojo和list實現一對一查詢和一對多查詢。 現在我就來實現查詢訂單所有信息的需求,而不是像上面那樣簡單粗暴地給user_id列加別名。首先在OrderMapper.xml映射文件中添加如下<select>
元素:
<
select id=
"getOrderListResultMap" resultMap=
"order_list_result_map" >
select id,user_id,number,createtime,note
from orders;
</
select >
使用resultMap指定上邊定義的order_list_result_map。 接着定義resultMap。由於上邊的OrderMapper.xml映射文件中sql查詢列和Orders.java類屬性不一致,因此需要定義resultMap:order_list_result_map將sql查詢列和Orders.java類屬性對應起來。
<resultMap type ="orders" id ="order_list_result_map" >
<id property ="id" column ="id" />
<result property ="userId" column ="user_id" />
<result property ="number" column ="number" />
<result property ="createtime" column ="createtime" />
<result property ="note" column ="note" />
</resultMap >
type:指resultMap要映射成的數據類型(返回結果映射的pojo,可以使用別名)。
<id />
:此屬性表示查詢結果集的唯一標識,非常重要。如果是多個字段爲複合唯一約束則定義多個<id />
。
property:表示Orders類的屬性。
column:表示sql查詢出來的字段名。 column和property放在一塊兒表示將sql查詢出來的字段映射到指定的pojo類屬性上。
<result />
:普通列使用result標籤映射。
然後在OrderMapper接口添加如下方法:
List
<Orders > getOrderListResultMap();
最後在OrderMapperTest單元測試類中添加如下測試方法:
@Test
public void testGetOrderListResultMap() {
SqlSession sqlSession = sqlSessionFactory
.openSession ()
OrderMapper orderMapper = sqlSession
.getMapper (OrderMapper
.class )
List<Orders> orderList = orderMapper
.getOrderListResultMap ()
for (Orders orders : orderList) {
System
.out .println (orders)
}
sqlSession
.close ()
}
同樣在testGetOrderListResultMap方法中的以下代碼處打一個斷點:
for (Orders orders : orderList) {
然後以Debug模式運行該方法,可發現查詢出來的每一個Orders對象中的userId屬性都有值了。
動態sql
我們可通過mybatis提供的各種標籤方法實現動態拼接sql。
if
現有這樣一個需求:傳遞pojo類綜合查詢用戶信息,更具體地說就是我們使用用戶的id和username能更加靈活地查詢用戶信息。 爲了解決這個需求,我們就要使用<if>
標籤了。首先在UserMapper.xml映射文件中添加如下<select>
元素:
<
select id=
"findUserList" parameterType=
"user" resultType=
"user" >
select *
from user
where 1 =
1
<
if test=
"id!=null" >
and id=
#{id}
</
if >
<
if test=
"username!=null and username!=''" >
and username
like
</
if >
</
select >
注意:
username要做不等於空字符串的校驗。
User類中id屬性的類型要改爲Integer包裝類型,因爲int類型的id是不可能爲null的!
然後在UserMapper接口添加如下方法:
List
<User > findUserList(User user);
最後在UserMapperTest單元測試類中添加如下測試方法:
@Test
public void testFindUserList () {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user =
new User();
user.setUsername(
"張" );
List<User> userList = userMapper.findUserList(user);
for (User user2 : userList) {
System.
out .println(user2);
}
sqlSession.close();
}
讀者可試着給User對象只爲id屬性賦值,或者只爲username屬性賦值,又或者兩者同時賦值。
where
UserMapper.xml映射文件中如下<select>
元素:
<
select id=
"findUserList" parameterType=
"user" resultType=
"user" >
select *
from user
where 1 =
1
<
if test=
"id!=null" >
and id=
#{id}
</
if >
<
if test=
"username!=null and username!=''" >
and username
like
</
if >
</
select >
也可使用<where>
標籤寫爲:
<
select id=
"findUserList" parameterType=
"user" resultType=
"user" >
select *
from user
<
where >
<
if test=
"id!=null" >
and id=
#{id}
</
if >
<
if test=
"username != null and username != ''" >
and username
like
</
if >
</
where >
</
select >
<where />
可以自動處理第一個and。
foreach
現有這樣一個需求:傳入多個id查詢用戶信息。如若編寫sql語句,可用下邊兩個sql實現:
SELECT * FROM USER WHERE username LIKE '%張%' AND (id =10 OR id =89 OR id=16)
SELECT * FROM USER WHERE username LIKE '%張%' id IN (10,89,16)
爲了解決這個需求,首先在QueryVo類中定義List屬性ids存儲多個用戶id,並添加getter/setter方法,如下:
public class QueryVo {
private User user;
private List<Integer> ids;
public List<Integer>
getIds () {
return ids;
}
public void setIds (List<Integer> ids) {
this .ids = ids;
}
public User
getUser () {
return user;
}
public void setUser (User user) {
this .user = user;
}
}
然後在UserMapper.xml映射文件中添加如下<select>
元素:
<select id ="findUserByIds" parameterType ="queryvo" resultType ="user" >
SELECT * FROM `user`
<where >
<foreach collection ="ids" item ="id" open ="and id in(" close =")" separator ="," >
#{id}
</foreach >
</where >
</select >
向sql中傳遞數組或List,mybatis將使用foreach解析。 接着在UserMapper接口添加如下方法:
List <
User > find
UserByIds (
QueryVo query Vo );
最後在UserMapperTest單元測試類中添加如下測試方法:
@Test
public void testFindUserByIds() {
SqlSession sqlSession = sqlSessionFactory
.openSession ()
// 獲得mapper代理對象
UserMapper userMapper = sqlSession
.getMapper (UserMapper
.class )
// 設置查詢條件
QueryVo queryVo = new QueryVo()
List<Integer> ids = new ArrayList<Integer>()
ids
.add (
1 )
ids
.add (
10 )
ids
.add (
16 )
ids
.add (
22 )
queryVo
.setIds (ids)
// 執行查詢
List<User> userList = userMapper
.findUserByIds (queryVo)
for (User user2 : userList) {
System
.out .println (user2)
}
sqlSession
.close ()
}
sql片段
sql中可將重複的sql提取出來,使用時用include引用即可,最終達到sql重用的目的,如下:
<
select id=
"findUserList" parameterType=
"user" resultType=
"user" >
select *
from user
<
where >
<
if test=
"id!=null" >
and id=
#{id}
</
if >
<
if test=
"username != null and username != ''" >
and username
like
</
if >
</
where >
</
select >
將where條件抽取出來,同時我們也可將要查詢的字段抽取出來。
<sql
id =
"find_user_list_where" >
<
where >
<
if test=
"id!=null" >
and id =
</
if >
<
if test=
"username != null and username != ''" >
and username like '%${username}%'
</
if >
</
where >
</sql>
<sql
id =
"user_field_list" >
id ,username,birthday,sex,address
</sql>
使用include引用:
<
select id=
"findUserList" parameterType=
"user" resultType=
"user" >
select <include refid=
"user_field_list" />
from user
<include refid=
"find_user_list_where" />
</
select >
注意:如果引用其它mapper.xml映射文件的sql片段,則在引用時需要加上namespace,如下:
<
include refid=
"namespace.sql片段" />
<link href="https://csdnimg.cn/release/phoenix/mdeditor/markdown_views-778f64ae39.css" rel="stylesheet">
</div>