本文将对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); }通过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,如下:
