Mybatis学习(4)输入映射、输出映射、动态sql
一、输入映射:
通过parameterType指定输入参数的类型,类型可以是简单类型、hashmap、pojo的包装类型
1) 传递pojo的包装对象
需求是:完成用户信息的综合查询,传入的查询条件复杂;(包括用户信息、其他信息等);
定义包装类型:
用户扩展类:
package com.cy.po; /** *用户的扩展类 * @author chengyu * */ public class UserCustom extends User{ }
视图层面的用户包装类型:
1 package com.cy.po; 2 3 /** 4 * 用户的包装类型 5 * @author chengyu 6 * 7 */ 8 public class UserQueryVo { 9 //在这里包装所需要的查询条件 10 11 //用户查询条件 12 private UserCustom userCustom; 13 14 //可以包装其它的查询条件,订单、商品 15 //.... 16 17 public UserCustom getUserCustom() { 18 return userCustom; 19 } 20 21 public void setUserCustom(UserCustom userCustom) { 22 this.userCustom = userCustom; 23 } 24 }
mapper.xml:
<!-- 用户信息综合查询 #{userCustom.sex}:取出pojo包装对象中性别值 ${userCustom.username}:取出pojo包装对象中用户名称 --> <select id="findUserList" parameterType="com.cy.po.UserQueryVo" resultType="com.cy.po.UserCustom"> SELECT * FROM USER where sex = #{userCustom.sex} and username like '%${userCustom.username}%' </select>
mapper.接口:
public interface UserMapper { //用户信息综合查询 public List<UserCustom> findUserList(UserQueryVo userQueryVo) throws Exception;
测试代码:
1 @Test 2 public void testFindUserList() throws Exception { 3 SqlSession sqlSession = sqlSessionFactory.openSession(); 4 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 5 6 //创建包装对象,设置查询条件 7 UserQueryVo userQueryVo = new UserQueryVo(); 8 UserCustom userCustom = new UserCustom(); 9 userCustom.setSex("1"); 10 userCustom.setUsername("张三丰"); 11 userQueryVo.setUserCustom(userCustom); 12 //调用userMapper的方法 13 14 List<UserCustom> list = userMapper.findUserList(userQueryVo); 15 16 System.out.println(list); 17 }
二、输出映射、
1、resultType:
使用resultType进行输出映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功。
如果查询出来的列名和pojo中的属性名全部不一致,没有创建pojo对象。
只要查询出来的列名和pojo中的属性有一个一致,就会创建pojo对象。
1) 输出简单类型: ----》》查询出来的结果集只有一行且一列,可以使用简单类型进行输出映射。
需求是,用户信息的综合查询列表总数,通过查询总数和上边用户综合查询列表才可以实现分页。
mapper.xml:
1 <!-- 用户信息综合查询总数 2 parameterType:指定输入类型和findUserList一样 3 resultType:输出结果类型 4 --> 5 <select id="findUserCount" parameterType="com.cy.po.UserQueryVo" resultType="int"> 6 SELECT count(*) FROM USER where sex = #{userCustom.sex} and username like '%${userCustom.username}%' 7 </select>
mapper.java接口:
//用户信息综合查询总数 public int findUserCount(UserQueryVo userQueryVo) throws Exception;
juit测试代码:
1 //测试查询用户数 2 @Test 3 public void testFindUserCount() throws Exception { 4 SqlSession sqlSession = sqlSessionFactory.openSession(); 5 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 6 7 //创建包装对象,设置查询条件 8 UserQueryVo userQueryVo = new UserQueryVo(); 9 UserCustom userCustom = new UserCustom(); 10 userCustom.setSex("1"); 11 userCustom.setUsername("张三丰"); 12 userQueryVo.setUserCustom(userCustom); 13 int count = userMapper.findUserCount(userQueryVo); 14 System.out.println(count); 15 }
2)输出pojo对象,和pojo对象列表:
不管是输出的pojo单个对象还是一个列表,在mapper.xml中resultType指定的类型是一样的。在mapper.java指定的方法返回值类型不一样;
输出单个pojo,返回值是这个pojo对象类型
输出pojo列表,返回值是List<pojo>
2.resultMap
mybatis中使用resultMap完成高级输出结果映射。如果查询出来的列名和pojo的属性名不一致,可以通过定义一个resultMap对列名和pojo属性名之间作一个映射关系。
使用方法啊:
1)定义resultMap
2)使用resultMap作为statement的输出映射类型
mapper.xml:
1 <!--使用mapper代理方法开发,namespace有特殊重要的作用,namespace等于mapper接口地址--> 2 <mapper namespace="com.cy.mapper.UserMapper"> 3 4 <!-- 定义resultMap 将SELECT id id_,username username_ FROM USER 和User类中的属性作一个映射关系 5 type:resultMap最终映射的java对象类型,可以使用别名 6 id:对resultMap的唯一标识 7 --> 8 <resultMap type="com.cy.po.User" id="userResultMap"> 9 <!-- id表示查询结果集中唯一标识 column:查询出来的列名 property:type指定的pojo类型中的属性名--> 10 <id column="id_" property="id"/> 11 12 <!-- result:对普通名映射定义 column:查询出来的列名 property:type指定的pojo类型中的属性名 --> 13 <result column="username_" property="username"/> 14 </resultMap> 15 16 <!-- 使用resultMap进行输出映射 17 resultMap:指定定义的resultMap的id,如果这个resultMap在其它的mapper文件,前边需要加namespace 18 --> 19 <select id="findUserByIdResultMap" parameterType="int" resultMap="userResultMap"> 20 SELECT id id_,username username_ FROM USER WHERE id=#{value} 21 </select> 22 </mapper>
mapper接口:
//根据id查询用户信息,使用resultMap输出 public User findUserByIdResultMap(int id) throws Exception;
juittest代码:
@Test public void testFindUserByIdResultMap() throws Exception { SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); User user = userMapper.findUserByIdResultMap(1); System.out.println(user); }
3.自己做的实验,输入类型和传出类型都为java.util.Map:
<!-- 查看resultMap的使用 java.util.Map 传入参数为hashmap id和username都为map的key --> <select id="findUserByIdDefaultMap" parameterType="java.util.Map" resultType="java.util.Map"> SELECT * FROM USER where id=#{id} and username like '%${username}%' </select>
并且java.util.Map在mybatis中的别名是hashmap,写成这样,效果一样的:
<select id="findUserByIdDefaultMap" parameterType="hashmap" resultType="hashmap"> SELECT * FROM USER where id=#{id} and username like '%${username}%' </select>
mapper接口:
//find user parameterMap and resultMap both are java.uti.Map public Map<String, String> findUserByIdDefaultMap(Map<String, String> parmas) throws Exception;
测试代码:
@Test public void testfindUserByIdDefaultMap() throws Exception{ SqlSession sqlSession = sqlSessionFactory.openSession(); UserMapper userMapper = sqlSession.getMapper(UserMapper.class); Map<String ,String> params = new HashMap<String, String>(); params.put("id", "25"); params.put("username", "小明"); Map<String, String> user = userMapper.findUserByIdDefaultMap(params); System.out.println(user); }
打印结果:
DEBUG [main] - ==> Preparing: SELECT * FROM USER where id=? and username like '%小明%' DEBUG [main] - ==> Parameters: 25(String) DEBUG [main] - <== Total: 1 {id=25, sex=1, username=陈小明, address=河南郑州}
三、动态sql
mybatis核心 对sql语句进行灵活操作,通过表达式进行判断,对sql进行灵活拼接、组装。
例子1:
需求: 对上面程序中的 用户信息综合查询列表这个statement使用动态sql,对查询条件进行判断,如果输入参数不为空才进行查询条件拼接。
mapper.xml:
<!-- 用户信息综合查询 #{userCustom.sex}:取出pojo包装对象中性别值 ${userCustom.username}:取出pojo包装对象中用户名称 --> <select id="findUserList" parameterType="com.cy.po.UserQueryVo" resultType="com.cy.po.UserCustom"> SELECT * FROM USER <!-- where可以自动去掉条件中的第一个and --> <where> <if test="userCustom!=null"> <if test="userCustom.sex!=null and userCustom.sex!=''"> and sex = #{userCustom.sex} </if> <if test="userCustom.username!=null and userCustom.username!=''"> and username like '%${userCustom.username}%' </if> </if> </where> </select>
测试代码:
1 @Test 2 public void testFindUserList() throws Exception { 3 SqlSession sqlSession = sqlSessionFactory.openSession(); 4 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 5 6 //创建包装对象,设置查询条件 7 UserQueryVo userQueryVo = new UserQueryVo(); 8 UserCustom userCustom = new UserCustom(); 9 10 //动态sql的存在,不设置某个值,条件不会拼接在sql中 11 //userCustom.setSex("1"); 12 userCustom.setUsername("小明"); 13 userQueryVo.setUserCustom(userCustom); 14 15 List<UserCustom> list = userMapper.findUserList(userQueryVo); 16 System.out.println(list); 17 }
打印:
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE username like '%小明%'
DEBUG [main] - ==> Parameters:
DEBUG [main] - <== Total: 3
[------->> User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州], ------->> User [id=22, username=陈小明, sex=1, birthday=null, address=河南郑州], ------->> User [id=25, username=陈小明, sex=1, birthday=null, address=河南郑州]]
2)sql片段:
将上边实现的动态sql判断代码块抽取出来,组成一个sql片段。其它的statement中就可以引用sql片段。
mapper.xml:----定义sql片段、引用sql片段:
<mapper namespace="com.cy.mapper.UserMapper"> <!-- 定义sql片段id:sql片段的唯 一标识 经验:是基于单表来定义sql片段,这样话这个sql片段可重用性才高;在sql片段中不要包括 where --> <sql id="query_user_where"> <if test="userCustom!=null"> <if test="userCustom.sex!=null and userCustom.sex!=''"> and sex = #{userCustom.sex} </if> <if test="userCustom.username!=null and userCustom.username!=''"> and username like '%${userCustom.username}%' </if> </if> </sql> <!-- 用户信息综合查询 #{userCustom.sex}:取出pojo包装对象中性别值 ${userCustom.username}:取出pojo包装对象中用户名称 --> <select id="findUserList" parameterType="com.cy.po.UserQueryVo" resultType="com.cy.po.UserCustom"> SELECT * FROM USER <where> <!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace --> <include refid="query_user_where"></include> </where> </select> </mapper>
3)使用foreach标签:
向sql传递数组或List,mybatis使用foreach解析;
需求:在用户查询列表的statement中增加多个id输入查询。
输入参数类型UserQueryVo中添加ids List,根据这个list查:
1 package com.cy.po; 2 3 import java.util.List; 4 5 /** 6 * 用户的包装类型 7 * @author chengyu 8 * 9 */ 10 public class UserQueryVo { 11 //在这里包装所需要的查询条件 12 13 private List<Integer> ids; 14 15 //用户查询条件 16 private UserCustom userCustom; 17 18 //可以包装其它的查询条件,订单、商品 19 //.... 20 21 public List<Integer> getIds() { 22 return ids; 23 } 24 public void setIds(List<Integer> ids) { 25 this.ids = ids; 26 } 27 public UserCustom getUserCustom() { 28 return userCustom; 29 } 30 public void setUserCustom(UserCustom userCustom) { 31 this.userCustom = userCustom; 32 } 33 }
mapper.xml:
<sql id="query_user_where"> <if test="userCustom!=null"> <if test="userCustom.sex!=null and userCustom.sex!=''"> and sex = #{userCustom.sex} </if> <if test="userCustom.username!=null and userCustom.username!=''"> and username like '%${userCustom.username}%' </if> <if test="ids!=null"> <!-- 使用 foreach遍历传入ids collection:指定输入 对象中集合属性 item:每个遍历生成对象中 open:开始遍历时拼接的串 close:结束遍历时拼接的串 separator:遍历的两个对象中需要拼接的串 --> <!-- AND (id=1 OR id=10 OR id=16)--> <foreach collection="ids" item="user_id" open="and (" close=")" separator="or"> id=#{user_id} </foreach> <!-- and id IN(1,10,16) --> <!-- <foreach collection="ids" item="user_id" open="and id in(" close=")" separator=","> #{user_id} </foreach> --> </if> </if> </sql> <!-- 用户信息综合查询 #{userCustom.sex}:取出pojo包装对象中性别值 ${userCustom.username}:取出pojo包装对象中用户名称 --> <select id="findUserList" parameterType="com.cy.po.UserQueryVo" resultType="com.cy.po.UserCustom"> SELECT * FROM USER <where> <!-- 引用sql片段 的id,如果refid指定的id不在本mapper文件中,需要前边加namespace --> <include refid="query_user_where"></include> </where> </select>
测试代码:
1 @Test 2 public void testFindUserList() throws Exception { 3 SqlSession sqlSession = sqlSessionFactory.openSession(); 4 UserMapper userMapper = sqlSession.getMapper(UserMapper.class); 5 6 //创建包装对象,设置查询条件 7 UserQueryVo userQueryVo = new UserQueryVo(); 8 UserCustom userCustom = new UserCustom(); 9 10 //动态sql的存在,不设置某个值,条件不会拼接在sql中 11 //userCustom.setSex("1"); 12 userCustom.setUsername("小明"); 13 14 //传入多个id 15 List<Integer> ids = new ArrayList<Integer>(); 16 ids.add(1); 17 ids.add(10); 18 ids.add(16); 19 userQueryVo.setIds(ids); 20 userQueryVo.setUserCustom(userCustom); 21 22 List<UserCustom> list = userMapper.findUserList(userQueryVo); 23 System.out.println(list); 24 }
可以看打印结果拼接的sql:
DEBUG [main] - ==> Preparing: SELECT * FROM USER WHERE username like '%小明%' and ( id=? or id=? or id=? )
DEBUG [main] - ==> Parameters: 1(Integer), 10(Integer), 16(Integer)
DEBUG [main] - <== Total: 1
[------->> User [id=16, username=张小明, sex=1, birthday=null, address=河南郑州]]