前言
除了SqlMapConfig.xml作为MyBatis的核心配置文件,映射文件也是mybatis中比较重要的,其中,关于输出和输入参数的映射,动态sql的实现以及多表关联查询,都需要我们去掌握.
正文
(一)参数映射
●parameterType(输入类型)
简单数据类型
当我们想要输入简单数据类型时,直接使用即可,如int等,可以参考前面博文中的表格来实现.传递pojo对象
可以使用parameterType="com.mybatis.po.User
的方式来指定入参为一个java对象,#{}
和${}
中的值为对象的属性.传递pojo包装对象
在一般的开发中,查询条件是通过pojo对象来传递的,比如这个条件中不仅仅包括用户信息,还有其他的查询条件,这个时候可以使用包装对象来传递输入参数.
比如现在要根据用户名查询用户信息,但是查询的结果要包含在一个QueryVo对象中.
首先创建一个QueryVo对象:
package com.mybatis.po;
public class QueryVo {
private User user;
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
接着在UserMapper接口中添加一个方法:
public List<User> findUserByQueryVo(QueryVo queryVo);
在UserMapper.xml中添加对应的方法:
<select id="findUserByQueryVo" parameterType="com.mybatis.po.QueryVo" resultType="com.mybatis.po.User">
select * from user where username like '%${user.username}%'
</select>
这里需要注意,如果参数是一个包装poji属性对象的属性,就像上面这样的,就要使用"."的方式来传值
下面来对这个方法进行测试:
@Test
public void testFindUserByQueryVo() {
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
QueryVo queryVo = new QueryVo();
User user = new User();
user.setUsername("张");
queryVo.setUser(user);
List<User> list = mapper.findUserByQueryVo(queryVo);
for (User resultUser : list) {
System.out.println(resultUser);
}
session.close();
}
查询结果如下:
可以看到,我们查出了两条数据.
●resultType(输出类型)
①简单数据类型
输出简单数据类型必须保证查询的结果只有一条记录,最终会将第一个字段转换为输出类型
<!-- 统计用户数量 -->
<select id="countUserNum" resultType="int">
select count(1) from user
</select>
public int countUserNum();
测试方法:
@Test
public void testcountUserNum() {
SqlSession session = sqlSessionFactory.openSession();
UserMapper mapper = session.getMapper(UserMapper.class);
int count = mapper.countUserNum();
System.out.println("总共有:" + count + "个用户!");
session.close();
}
查询结果如下:
②输出pojo对象
输出数据类型为java的pojo对象时,只需要查询结果的字段和pojo对象的属性名相对应即可.
●resultMap
resultType指定java对象将查询结果映射为pojo,但是需要pojo和查询的列名一致才能映射成功.如果sql查询字段名和pojo的属性名不一致,可以通过resultMap
将字段名和属性名做对应关系,实际上还是需要将查询结果映射到pojo对象中.resultMap可以实现将查询结果映射为复杂类型的pojo.
如果我们的user类的主键属性是id,而user表的主键字段是uid,那么如果直接使用resultType的话,需要加别名,或者修改User类,在这里,我们可以使用resultMap
来建立两者的映射关系:
<resultMap type="com.mybatis.po.User" id="user_table">
<id column="uid" property="id"/>
<result column="username" property="username"/>
<result column="password" property="password"/>
</resultMap>
<!-- 测试resultMap映射pojo信息 -->
<select id="textResultMap" parameterType="int" resultMap="user_table">
select * from user where uid = #{id}
</select>
在mapper中新建一个textResultMap
方法:
public User textResultMap(int id);
最后测试顺利的查询出了用户的信息.
在这里,有必要对resultMap
标签中的属性做个说明:
<id/>
表示结果集的唯一标识.
property
表示对应java对象的属性
column
表示sql查询出来结果的字段名,和property放在一起,表示将sql查询结果映射到指定的pojo类的属性上.
<result/>
除主键外的其他的属性可以使用该标签来建立映射.
(二)动态sql
- if
当我们的查询条件是多个,且个数不确定的时候,可以使用if标签动态生成sql:
<!-- 传递pojo综合查询用户信息 -->
<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 '%${username}%'
</if>
</select>
标签中的test代表条件判断.
- where
改造上面的sql,去掉where后面的1=1,可以使用<where/>
标签来去除第一个and
<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 '%${username}%'
</if>
</where>
</select>
- foreach
向sql传递List或者数组的时候,我们可以使用mybatis提供的foreach
标签进行解析.比如,传入多个用户的id,查出这些id所属的用户信息.
<select id="findUserByIds" parameterType="QueryVo" resultType="com.mybatis.po.User">
SELECT * FROM user
<where>
<!-- 相当于 and id in (1,10,20,30) -->
<foreach collection="ids" item="id" open="and id in (" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
collection
代表QueryVo中的数组ids
item
代表遍历的每个变量,也就是每一个用户id
open
代表拼装sql语句的开始部分
close
代表sql语句的结尾部分
separator
代表间隔符
- sql片段
将sql语句中重复的sql提取出来,在使用的时候可以使用include
引用:
<!-- 传递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条件:
<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>
引用:
<select id="findUserList" parameterType="user" resultType="user">
select * from user
<where>
<include refid="query_user_where"/>
</where>
</select>
需要注意的是,如果引用了其他mapper.xml的sql片段,需要在引用的时候加上namespace,比如:
<include refid="namespace.sql片段”/>
(三)关联查询
有的需求需要对数据库中的多张表就行关联查询,来看看对于关联查询,mybatis是怎么处理的呢?
- 数据模型:商品&订单
我们再创建一个订单表,订单表中的user_id作为外键,指向user表中的主键id:
首先,从订单这边来看,一个订单对于一个用户,属于一对一;从用户这边来看,一个用户对应多个订单,属于一对多,下面我们使用mybatis来实现这两种情况下的数据查询. - 一对一查询
需求:查询所有订单信息,关联查询订单所属的用户信息.
也就是要查询出下面这样的数据:
这里我们可以有两种方法来实现:
1. 使用resultType自定义一个po类,该类包含查询结果的所有字段
package com.mybatis.po;
public class OrderUser extends Orders {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
接着在mapper接口中添加一个方法:
public List<OrderUser> findOrderList();
在mapper.xml文件中添加对应的sql:
<select id="findOrderList" resultType="com.mybatis.po.OrderUser">
select
o.id,
o.user_id userId,
o.number,
o.createtime,
o.note,
u.username,
u.password
from orders o LEFT JOIN `user` u ON o.user_id = u.id;
</select>
这样我们就可以使用和这个方法来查询到需要的数据:
@Test
public void testFindOrderList() {
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<OrderUser> list = mapper.findOrderList();
for (OrderUser orderUser : list) {
System.out.println(orderUser);
}
sqlSession.close();
2. 使用resultMap,专门针对查询结果定义resultMap来接收查询结果
首先我们在Orders类中添加一个属性User对象:
public class Orders {
......
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
然后写对应的sql语句,并创建resultMap:
<resultMap type="com.mybatis.po.Orders" id="OrderUser_ResultMap">
<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"/>
<!-- 配置一对一的用户关联映射条件 -->
<association property="user" javaType="com.mybatis.po.User">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
</association>
</resultMap>
<select id="findOrderList_ResultMap" resultMap="OrderUser_ResultMap">
select
o.id,
o.user_id ,
o.number,
o.createtime,
o.note,
u.username,
u.password
from orders o LEFT JOIN `user` u ON o.user_id = u.id;
</select>
association
表示进行关联查询单条记录
property
表示关联结果储存在com.mybatis.po.User
对象中
javaType
表示关联查询的结果类型
Mapper接口中添加方法:
public List<Orders> findOrderList_ResultMap();
测试:
@Test
public void testFindOrderList_ResultMap(){
SqlSession sqlSession = sqlSessionFactory.openSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<Orders> list_ResultMap = mapper.findOrderList_ResultMap();
for (Orders orders : list_ResultMap) {
System.out.println(orders);
}
sqlSession.close();
}
- 一对多查询
需求:查询所有的用户信息以及关联的订单信息.
在这个需求中,用户和订单是一对多的关系,我们可以使用resultMap来实现:
首先,在User类中添加一个List属性:
public class User {
private Integer id;
private String username;
private String password;
private List<Orders> orders;
public List<Orders> getOrders() {
return orders;
}
public void setOrders(List<Orders> orders) {
this.orders = orders;
}
......
编写sql语句:
<resultMap type="com.mybatis.po.User" id="user_order_resultmap">
<id property="id" column="id"/>
<result property="username" column="username"/>
<result property="password" column="password"/>
<!-- 配置一对多的关系映射 -->
<collection property="orders" ofType="com.mybatis.po.Orders">
<!-- 这里的id对应的是orders的主键属性 -->
<id property="id" column="id"/>
<result property="number" column="number"/>
<result property="createtime" column="createtime"/>
<result property="note" column="note"/>
</collection>
</resultMap>
<select id="getUserWithOrders" resultMap="user_order_resultmap">
select
u.id,
u.username,
u.password,
o.id oid,
o.number,
o.createtime,
o.note
from
`user` u
left join orders o on u.id = o.user_id
</select>
注意:
collection
部分定义了用户关联的订单信息,表示关联查询结果集
property="orders"
表示关联查询的结果集存储在User对象的orders属性上
ofType="com.mybatis.po.Orders"
表示关联查询结果集中的数据类型,即List中的对象类型,此处可以使用别名,也可以使用全限定名.
总结
关于mybatis的使用,到这里大概就差不多了,在后期随着项目经验的不断增加,我也会陆续的更新系列文章,做到温故知新!!