(转)MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql
http://blog.csdn.net/yerenyuan_pku/article/details/71893689
前面对MyBatis框架的学习中,我们对Mapper.xml映射文件多少有些了解。本文将对Mapper.xml映射文件作更加细致的梳理,首先从Mapper.xml文件中的输入和输出映射开始。本文案例代码的编写是建立在前文MyBatis框架的学习(三)——Dao层开发方法案例基础之上的!
输入映射和输出映射
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 getUserByQueryVo(QueryVo queryVo);
最后在UserMapperTest单元测试类编写如下测试方法:
@Test
public void testGetUserByQueryVo() {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获得mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 创建一个QueryVo对象
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映射文件中添加如下配置信息:
<!-- 传递HashMap综合查询用户信息 -->
<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();
// 获得mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 构造查询条件Hashmap对象
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();
// 获得mapper代理对象
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 sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder();
// 第二步,加载配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
// 第三步,创建SqlSessionFactory对象
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是pojo中主键的属性,column是返回结果中主键的列 -->
<id property="id" column="id" />
<!-- 普通列使用result映射 -->
<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();
- 1
- 1
最后在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) {
- 1
- 1
然后以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 '%${username}%'
</if>
</select>
注意:
- username要做不等于空字符串的校验。
- User类中id属性的类型要改为Integer包装类型,因为int类型的id是不可能为null的!
然后在UserMapper接口添加如下方法:
List<User> findUserList(User user);
- 1
- 1
最后在UserMapperTest单元测试类中添加如下测试方法:
@Test
public void testFindUserList() {
SqlSession sqlSession = sqlSessionFactory.openSession();
// 获得mapper代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 设置查询条件
User user = new User();
// user.setId(10);
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 '%${username}%'
</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 '%${username}%'
</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>
元素:
<!-- 动态sql foreach测试 -->
<select id="findUserByIds" parameterType="queryvo" resultType="user">
SELECT * FROM `user`
<where>
<!-- and id IN(1,10,20,21,31) -->
<foreach collection="ids" item="id" open="and id in(" close=")" separator=",">
#{id}
</foreach>
</where>
</select>
向sql中传递数组或List,mybatis将使用foreach解析。
接着在UserMapper接口添加如下方法:
List<User> findUserByIds(QueryVo queryVo);
最后在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 '%${username}%'
</if>
</where>
</select>
将where条件抽取出来,同时我们也可将要查询的字段抽取出来。
<sql id="find_user_list_where">
<where>
<if test="id!=null">
and id=#{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片段"/>
(转)MyBatis框架的学习(四)——Mapper.xml文件中的输入和输出映射以及动态sql的更多相关文章
- JAVAEE——Mybatis第二天:输入和输出映射、动态sql、关联查询、Mybatis整合spring、Mybatis逆向工程
1. 学习计划 1.输入映射和输出映射 a) 输入参数映射 b) 返回值映射 2.动态sql a) If标签 b) Where标签 c) Sql片段 d) Foreach标签 3.关联查询 a) 一对 ...
- MyBatis Mapper.xml文件中 $和#的区别
MyBatis Mapper.xml文件中 $和#的区别 网上有很多,总之,简略的写一下,作为备忘.例子中假设参数名为 paramName,类型为 VARCHAR . 1.优先使用#{paramN ...
- mapper.xml文件中传入list参数报错 ‘ ’附近有语法错误
mapper.xml文件中传入list参数,使用foreach循环遍历值,但是在遍历的过程中出错了,具体代码如下所示 mapper.xml <select id="selectByCo ...
- Java数据持久层框架 MyBatis之API学习四(xml配置文件详解)
摘录网址: http://blog.csdn.net/u010107350/article/details/51292500 对于MyBatis的学习而言,最好去MyBatis的官方文档:http:/ ...
- (转)MyBatis框架的学习(五)——一对一关联映射和一对多关联映射
http://blog.csdn.net/yerenyuan_pku/article/details/71894172 在实际开发中我们不可能只是对单表进行操作,必然要操作多表,本文就来讲解多表操作中 ...
- maven 结合mybaits整合框架,打包时mapper.xml文件,mapper目录打不进war包去问题
首先,来看下MAVENx项目标准的目录结构: 一般情况下,我们用到的资源文件(各种xml,properites,xsd文件等)都放在src/main/resources下面,利用maven打包时,ma ...
- mapper.xml文件中标签没有提示的解决
1.首先我们来看看mapper.xml的头文件 <?xml version="1.0" encoding="UTF-8" ?> <!DOCTY ...
- mybatis框架的核心配置Mapper.xml
映射管理器resultMap:映射管理器,是Mybatis中最强大的工具,使用其可以进行实体类之间的关系,并管理结果和实体类间的映射关系 需要配置的属性:<resultMap id=" ...
- Mybatis学习(4)输入映射、输出映射、动态sql
一.输入映射: 通过parameterType指定输入参数的类型,类型可以是简单类型.hashmap.pojo的包装类型 1) 传递pojo的包装对象 需求是:完成用户信息的综合查询,传入的查询条件复 ...
随机推荐
- LeetCode: 463 Island Perimeter(easy)
题目: You are given a map in form of a two-dimensional integer grid where 1 represents land and 0 repr ...
- Appium + junit 的简单实例
import static junit.framework.Assert.assertTrue; import static org.junit.Assert.*; import org.junit. ...
- Docker 网络模型之 macvlan 详解,图解,实验完整
本文首发于我的公众号 Linux云计算网络(id: cloud_dev),专注于干货分享,号内有 10T 书籍和视频资源,后台回复「1024」即可领取,欢迎大家关注,二维码文末可以扫. 上一篇文章我们 ...
- 洛谷 - P2568 - GCD - 欧拉函数
https://www.luogu.org/problemnew/show/P2568 统计n以内gcd为质数的数的个数. 求 \(\sum\limits_p \sum\limits_{i=1}^{n ...
- 小程序隐藏或自定义 scroll-view滚动条
css 隐藏滚动条 ::-webkit-scrollbar { width:; height:; color: transparent; } 自定义滚动条样式 ::-webkit-scrollbar ...
- bootstrap添加多个模态对话框支持
bootstrap添加多个模态对话框支持 (2015-03-04 21:05:35) 转载▼ 标签: 房产 因为项目需要,在页面交互上要弹出多个dialog窗口,而bootstrap的modal支 ...
- hdu 6299 Balanced Sequence( 2018 Multi-University Training Contest 1 )
#include <stdio.h> #include <iostream> #include <cstdlib> #include <cmath> # ...
- 子div块中设置margin-top时影响父div块位置的解决办法及其原因
解决办法①: 若子DIV块中使用margin-top,则在父DIV块中添加:overflow:hidden; 解决办法②: 在子DIV块中用padding-top代替margin-top. 有个叫 b ...
- 在 Java 的多线程中,如何去判断给定的一个类是否是线程安全的(另外:synchronized 同步是否就一定能保证该类是线程安全的。)
同步代码块和同步方法的区别:同步代码块可以传入任意对象,同步方法中 如果多个线程检查的都是一个新的对象,不同的同步锁对不同的线程不具有排他性,不能实现线程同步的效果,这时候线程同步就失效了. 两者的区 ...
- vi/vim 中批量在行插入或删除指定字符
1. 在每行的行首行尾插入指定字符 行首::%s/^/insert_word/ 行尾::%s/$/insert_word/ 2. 在某些行的行进行替换 在2~50行首添加//号 ...