本文将对Mapper.xml映射文件作更加细致的梳理
Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。
mybatis核心:
- mybatis输入映射(掌握)
- mybatis输出映射(掌握)
mybatis的动态sql(掌握)
一、 输入映射
通过parameterType指定输入参数的类型,类型可以是简单类型,pojo对象,pojo的包装类型,hashmap
parameterType(输入类型):
1. 传递简单类型
2. 传递pojo对象
Mybatis使用ognl表达式解析对象字段的值,如下例子:
<!—传递pojo对象综合查询用户信息 -->
<select id="findUserByUser" parameterType="user" resultType="user">
select * from user where id=#{id} and username like '%${username}%'
</select>
测试:
Public void testFindUserByUser()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//构造查询条件user对象
User user = new User();
user.setId(1);
user.setUsername("管理员");
//传递user对象查询用户列表
List<User>list = userMapper.findUserByUser(user);
//关闭session
session.close();
}
3.传递pojo包装对象(重要)
3.1需求
开发中通过pojo传递查询条件 ,查询条件是综合的查询条件,不仅包括用户查询条件还包括其它的查询条件(比如将用户购买商品信息也作为查询条件),这时可以使用包装对象传递输入参数。
3.2 定义包装类型pojo
针对需求,建议使用自定义包装类型的pojo
在包装类型的pojo中将复杂的查询条件包装进去。
在package cn.itcast.mybatis.pojo包下新建类UserQueryVo.java
//定义包装对象将查询条件(pojo)以类组合的方式包装起来。
public class UserQueryVo {
//传入多个id
private List<Integer> ids;
//在这里包装所需要的查询条件
//用户查询条件
private UserCustom userCustom;
public UserCustom getUserCustom() {
return userCustom;
}
public void setUserCustom(UserCustom userCustom) {
this.userCustom = userCustom;
}
public List<Integer> getIds() {
return ids;
}
public void setIds(List<Integer> ids) {
this.ids = ids;
}
//可以包装其它的查询条件,订单、商品
//....
}
3.3 mapper.xml映射文件
<!-- 用户信息综合查询 -->
<select id="findUserList" parameterType="cn.itcast.mybatis.pojo.UserQueryVo"
resultType="cn.itcast.mybatis.pojo.UserCustom">
SELECT*FROM USER WHERE user.sex=#{userCustom.sex}
AND user.username LIKE '%${userCustom.username}%'
</select>
3.4 测试代码
@Test
public void testFindUserList() throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//创建UserMapper接口的实例对象,是mybatis自动生成Usermapper代理对象(很重要!!!)
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo =new UserQueryVo();
UserCustom userCustom=new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("张三丰");
userQueryVo.setUserCustom(userCustom);
//调用userMapper 方法
List<UserCustom>list=userMapper.findUserList(userQueryVo);
System.out.println(list);
}
4.传递HashMap
在UserMapper.xml映射文件中添加如下配置信息:
<!-- 传递hashmap综合查询用户信息 -->
<select id="findUserByHashmap" parameterType="hashmap" resultType="user">
select * from user where id=#{id} and username like '%${username}%'
</select>
上面的id和username是HashMap的key。
接着在UserMapper接口中添加如下方法:
//传递hashmap 用户信息综合查询
public User findUserByHashmap(HashMap<String, Object>map)throws Exception;
最后在UserMapperTest单元测试类编写如下测试方法:
Public void testFindUserByHashmap()throws Exception{
//获取session
SqlSession session = sqlSessionFactory.openSession();
//获限mapper接口实例
UserMapper userMapper = session.getMapper(UserMapper.class);
//构造查询条件Hashmap对象
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("id", 1);
map.put("username", "管理员");
//传递Hashmap对象查询用户列表
List<User>list = userMapper.findUserByHashmap(map);
//关闭session
session.close();
}
二、输出映射
resultType(输出类型)
输出简单类型
特点:输出简单类型必须查询出来的结果集只有一条记录(一行一列),最终将第一个字段的值转换为输出类型。
需求:查询用户表中的记录数
第一步:在UserMapper.xml映射文件中添加如下配置信息:
<!-- 用户信息综合查询总数 -->
<select id="findUserCount" parameterType="cn.itcast.mybatis.pojo.UserQueryVo"
resultType="int">
SELECT count(*) FROM USER WHERE user.sex=#{userCustom.sex}
AND user.username LIKE '%${userCustom.username}%'
</select>
第二步:在UserMapper接口中添加如下方法:
//用户信息综合查询总数
public int findUserCount(UserQueryVo userQueryVo)throws Exception;
第三步:在UserMapperTest单元测试类编写如下测试方法:
//综合查询用户信息总数
@Test
public void testFindUserCount() throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//创建UserMapper接口的实例对象,是mybatis自动生成Usermapper代理对象(很重要!!!)
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo =new UserQueryVo();
UserCustom userCustom=new UserCustom();
userCustom.setSex("1");
userCustom.setUsername("张三");
userQueryVo.setUserCustom(userCustom);
//调用userMapper 方法
int count=userMapper.findUserCount(userQueryVo);
System.out.println(count);
}
输出pojo对象 和 输出pojo列表
不管是输出的pojo单个对象还是一个列表(list中包括pojo),在mapper.xml中resultType指定的类型是一样的。
在mapper.java指定的方法返回值类型不一样:
1、输出单个pojo对象,方法返回值是单个对象类型
2、输出pojo对象list,方法返回值是List
生成的动态代理对象中是根据mapper方法的返回值类型确定是调用selectOne(返回单个对象调用)还是selectList (返回集合对象调用 ).
对应UserMapper.xml文件如下:
<!--1、根据用户id(主键)查询用户信息 -->
<select id="findUserById" parameterType="int" resultType="user">
SELECT*FROM USER WHERE id=#{id}
</select>
<!--2、 根据用户名称模糊查询用户信息 -->
<select id="findUserByName" parameterType="java.lang.String" resultType="user">
SELECT * FROM USER WHERE USERNAME LIKE '%${value}%'
</select>
对应的UserMapper接口方法如下:
//根据id查询用户信息(输出是User对象)
public User findUserById(int id) throws Exception;
//根据用户名列查询用户列表(输出是List列表)
public List<User> findUserByName(String name) throws Exception;
resultMap(输出类型)
resultType可以指定pojo将查询结果映射为pojo,但需要pojo的属性名和sql查询的列名一致方可映射成功。
如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名作一个对应关系 ,resultMap实质上还需要将查询结果映射到pojo对象中。
resultMap可以实现将查询结果映射为复杂类型的pojo,比如在查询结果映射对象中包括pojo和list实现一对一查询和一对多查询。
第一步:在UserMapper.xml映射文件中添加如下元素:
<!--定义resultmap -->
<resultMap type="user" id="userResultMap" >
<id column="id_" property="id"/>
<result column="username_" property="username"/>
</resultMap>
<!-- 使用resultMap输出映射 -->
<select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap">
SELECT id id_,username username_ FROM USER WHERE id=#{value}
</select>
type:指resultMap要映射成的数据类型(返回结果映射的pojo,可以使用别名)。
id />:此属性表示查询结果集的唯一标识,非常重要。如果是多个字段为复合唯一约束则定义多个。
property:表示User类的属性。
column:表示sql查询出来的字段名。
column和property放在一块儿表示将sql查询出来的字段映射到指定的pojo类属性上。
result />:普通列使用result标签映射。
第二步:在UserMapper接口添加如下方法:
//resultMap查询
public User findUserByIdResultMap(int id) throws Exception;
第三步:在UserMapperTest单元测试类中添加如下测试方法:
@Test
public void testFindUserByIdResultMap() throws Exception {
SqlSession sqlSession=sqlSessionFactory.openSession();
//创建UserMapper接口的实例对象,是mybatis自动生成Usermapper代理对象(很重要!!!)
UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
//调用userMapper 方法
User user=userMapper.findUserByIdResultMap(1);
System.out.println(user);
}
三、动态sql
通过mybatis提供的各种标签方法实现动态拼接sql。
if
<!-- 传递pojo综合查询用户信息 -->
<select id="findUserList" parameterType="user" resultType="user">
select * from user
where 1=1
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</select>
- 注意要做不等于空字符串校验。
- User类中id属性的类型要改为Integer包装类型,因为int类型的id是不可能为null的!
Where
上边的sql也可以改为:
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</where>
</select>
其中 where />可以自动处理第一个and。
foreach
需求:传入多个id查询用户信息。
如若编写sql语句,可用下边两个sql实现:
SELECT * FROM USER WHERE username LIKE '%张%' AND (id =1 OR id =10 OR id=16)
SELECT * FROM USER WHERE username LIKE '%张%' id IN (1,10,16)
为了解决这个需求,首先在UserQueryVo类中定义List属性ids存储多个用户id,并添加getter/setter方法,如下:
//传入多个id
private List<Integer> ids;
然后在UserMapper.xml映射文件中添加如下select>元素:
!-- 动态sql foreach测试 -->
<sql id="query_user_where">
<if test="userCustom!=null">
<if test="userCustom.sex!=null and userCustom.sex!=' '">
and user.sex=#{userCustom.sex}
</if>
<if test="userCustom.username!=null and userCustom.username!=' '">
and user.username LIKE '%${userCustom.username}%'
</if>
<if test="ids!=null">
<!-- 使用 foreach遍历传入ids
collection:指定输入 对象中集合属性
item:每个遍历生成对象中
open:开始遍历时拼接的串
close:结束遍历时拼接的串
separator:遍历的两个对象中需要拼接的串
-->
<foreach collection="ids" item="user_id" open="AND (" close=")" separator="or">
<!-- 每个遍历需要拼接的串 -->
id=#{user_id}
</foreach>
</if>
</if>
</sql>
最后在UserMapperTest单元测试类中添加如下测试方法:
//用户信息的综合 查询
@Test
public void testFindUserList2() throws Exception {
SqlSession sqlSession = sqlSessionFactory.openSession();
//创建UserMapper对象,mybatis自动生成mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
//创建包装对象,设置查询条件
UserQueryVo userQueryVo = new UserQueryVo();
UserCustom userCustom = new UserCustom();
//由于这里使用动态sql,如果不设置某个值,条件不会拼接在sql中
// userCustom.setSex("1");
userCustom.setUsername("王明");
//传入多个id
List<Integer> ids = new ArrayList<Integer>();
ids.add(1);
ids.add(10);
ids.add(16);
//将ids通过userQueryVo传入statement中
userQueryVo.setIds(ids);
userQueryVo.setUserCustom(userCustom);
//调用userMapper的方法
List<UserCustom> list = userMapper.findUserList(userQueryVo);
System.out.println(list);
}
sql片段
sql中可将重复的sql提取出来,使用时用include引用即可,最终达到sql重用的目的,如下:
<!-- 传递pojo综合查询用户信息 -->
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</where>
</select>
将where条件抽取出来,并加上id:
<sql id="query_user_where">
<if test="id!=null and id!=''">
and id=#{id}
</if>
<if test="username!=null and username!=''">
and username like '%${username}%'
</if>
</sql>
使用include引用:
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<include refid="query_user_where"/>
</where>
</select>
注意:如果引用其它mapper.xml的sql片段,则在引用时需要加上namespace,如下: