本文将对Mapper.xml映射文件作更加细致的梳理

Mapper.xml映射文件中定义了操作数据库的sql,每个sql是一个statement,映射文件是mybatis的核心。

mybatis核心:

  • mybatis输入映射(掌握)
  • mybatis输出映射(掌握)

mybatis的动态sql(掌握)

一、 输入映射

通过parameterType指定输入参数的类型,类型可以是简单类型,pojo对象,pojo的包装类型,hashmap

parameterType(输入类型):

1. 传递简单类型

java mybatis读取大量数据 mybatis读取blob字段为输入流_java mybatis读取大量数据


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,如下: