3、输入和输出映射(mybatis笔记)

一、输入映射

  • 通过parameterType指定输入参数的类型,类型可以是简单类型、HashMappojo的包装类型。

  • 对于HashMap类型:

<select id="findUserByHashmap" parameterType="hashmap" resultType="User">
select * from user where id=#{id} and username like '%${username}%'
</select>

这里我们主要说明一下pojo包装类型的使用情况。

  • 需求:完整一个用户信息的综合查询,需要传入很多的查询条件,可能会包含用户信息,甚至一些其他的信息,比如商品、订单。针对这里的需求我们建议使用自定义的包装类型的pojo
    pojo中将复杂的条件包装进去。(工程mybatis04

UserQueryVo.java

package cn.itcast.pojo;

//包装类型
public class UserQueryVo {
    //包装所需要的查询条件
    private UserCustom userCustom ;
    //还可以包装其他的查询条件,订单、商品。

    public UserCustom getUserCustom() {
        return userCustom;
    }

    public void setUserCustom(UserCustom userCustom) {
        this.userCustom = userCustom;
    }
}

注意:这里我们使用的UserCustom.java类是User.java类的一个增强类,当然其实这里这个类和User.java是一样的,这里主要是为了说明以后如果发现某个pojo的属性不够用,需要增强时不要直接在类中进行添加,而应该编写一个其增强类。
UserCustom.java

package cn.itcast.pojo;

//用户类的扩展类
public class UserCustom extends User{
    //可以来扩展用户的信息
}
  • 定义映射文件mapper.xml
    UserMapper.xml中定义用户信息的综合查询(查询条件复杂)。
    <!-- 用户信息综合查询
    #{userCustom.sex}:取出包装类型中性别的值
    ${userCustom.username}:取出包装类型中用户的名字 -->
    <select id="findUserList" parameterType="UserQueryVo" resultType="UserCustom">
        select * fromuser where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
    </select>
  • 测试

UserMapperTest.java

    //用户信息综合查询测试
    @Test
    public void findUserList(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
        //创建包装对象,设置查询条件
        UserQueryVo userQueryVo = new UserQueryVo();
        UserCustom userCustom = new UserCustom();
        userCustom.setSex("1");
        userCustom.setUsername("小明");
        userQueryVo.setUserCustom(userCustom);
        
        List<UserCustom> list = userMapper.findUserList(userQueryVo);
        
        for(UserCustom user : list){
            System.out.println(user.getUsername());
        }
        sqlSession.close();
    }

二、输出映射

2.1 resultType

当我们使用这样sql时:

select * from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'

我们测试发现可以映射成功,但是如果这样:

SELECT id id_, username username_, sex, birthday FROM USER 
WHERE user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'

这里凡是使用了别名的,在测试时发现都不能映射成功,但是我们在数据库中是能够使用别名的。
总结:如果使用resultType进行输出的映射,只有查询出来的列名和pojo中的属性名一致,该列才可以映射成功,如果全部不一致,则不会创建pojo对象,只要查询出的列名有一个一致,就会创建pojo对象。

  • 有一种需求:用户信息的综合查询列表总数,通过查询总数和上面用户综合查询列表才可以实现分页。也就是输出简单类型。
    <!-- 用户信息综合查询总数 -->
    <select id="findUserCount" parameterType="UserQueryVo" resultType="int">
        select count(*) from user where user.sex = #{userCustom.sex} and user.username like '%${userCustom.username}%'
    </select>

说明:查询出来的结果集只有一行且一列,才可以使用简单类型进行输出映射。

  • 输出pojo对象和pojo列表
    不管是输出的单个对象还是输出的对象列表,resultType指定的类型是一样的,不一样的是在接口中指定方法的返回值不一样,一个是User,一个是List<User>

  • 输出HashMap
    输出pojo对象可以该用HashMap输出类型,将输出的字段名作为Mapkeyvalue为字段值。

2.2 resultMap

  • mybatis中可以使用resultMap完成高级输出结果映射,这里我们讲入门使用。

  • 如果查询出来的列名和pojo的属性名不一致,通过定义一个resultMap对列名和属性名之间做一个映射。

  • 使用方法

    • 定义resultMap
    • 使用resultMap作为statement的输出映射类型
  • 需求:将下面的sql使用UserCutom完成映射

SELECT id id_, username username_ FROM USER WHERE id = #{value}

这里User类中属性名和sql中查询列名不一致。注意:resultMap的值就是下面定义的resultMapid

  • 定义resultMap
    <!-- 定义resultMap,将SELECT id id_, username username_ FROM USER和User类中属性做一个映射
    type:resultMap最终映射的java对象类型,可以使用别名
    id:对resultMap的一个唯一标识 -->
    <resultMap type="User" id="userResultMap">
        <!-- id:表示查询结果集中唯一标识,column表示查询出来的列名,property表示type指定的pojo类型中的属性名
        最终resultMap对column和property作一个映射关系(对应关系) -->
        <id column="id_" property="id"></id>
        
        <!-- result表示对普通名映射定义。column表示查询出来的列名,property表示type指定的pojo类型中的属性名 
        最终resultMap对column和property作一个映射关系(对应关系)-->
        <result column="username_" property="username"/>
    </resultMap>

说明:这里注意唯一标识和普通属性的区别,唯一标识一般是主键。

  • 使用resultMap作为statement的输出映射类型
    <!-- 使用resultMap进行输出的映射,注意:如果上面定义的resultMap在其他mapper文件中,请加上namespace -->
    <select id="findUserByIdResultMap" parameterType="UserQueryVo" resultMap="userResultMap">
        SELECT id id_, username username_ FROM USER WHERE id = #{value}
    </select>
  • 接口
public User findUserByIdResultMap(int id );
  • 测试
    //用户信息综合查询总数测试
    @Test
    public void findUserByIdResultMap(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
        //创建包装对象,设置查询条件
        UserQueryVo userQueryVo = new UserQueryVo();
        UserCustom userCustom = new UserCustom();
        userCustom.setSex("1");
        userCustom.setUsername("小明");
        userQueryVo.setUserCustom(userCustom);
        
        User user  = userMapper.findUserByIdResultMap(1);
        System.out.println(user.getUsername());
        sqlSession.close();
        
    }

三、动态sql

mybatis的核心:对sql语句进行灵活的操作,通过表达式sql来进行判断,对sql进行灵活的拼接、组装。

3.1 需求(工程mybatis05

用户信息综合查询列表和用户信息查询列表总数这两个statement的定义使用动态sql

  • 对查询条件进行判断,如果如果输入参数不为空才进行查询条件的拼接。
    <!-- 用户信息综合查询总数 -->
    <select id="findUserCount" parameterType="UserQueryVo" resultType="int">
        select count(*) from 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>
        </where>
    </select>
    
    <!-- 用户信息综合查询-->
    <select id="findUserList" parameterType="UserQueryVo" resultType="UserCustom">
        select * from user
        <!-- where可以自动的去掉条件中的第一个and -->
        <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>
        </where>
    </select>

说明:这里我们就对这两个查询进行了改造。更多的标签请参考文档。

  • 测试
    //用户信息综合查询测试
    @Test
    public void findUserList(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
        //创建包装对象,设置查询条件
        UserQueryVo userQueryVo = new UserQueryVo();
        UserCustom userCustom = new UserCustom();
        //由于这里使用了动态sql,如果不设置值,条件就不会拼接到sql中
        //userCustom.setSex("1");
        //userCustom.setUsername("小明");
        userQueryVo.setUserCustom(userCustom);
        
        List<UserCustom> list = userMapper.findUserList(userQueryVo);
        
        for(UserCustom user : list){
            System.out.println(user.getUsername());
        }
        sqlSession.close();
        
    }

3.2 需求(工程mybatis06

将上面实现sql动态判断的代码抽取出来,组成一个sql片段。其他的statement中就可以引用此sql片段。

  • 定义sql片段
    <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>
    </sql>

说明:

  • id : 表示sql片段的唯一标识。

  • 经验:一般定义sql片段都是基于单表定义,这样的话这个sql片段的可重用性才会很高。在sql片段中不要包括where,便于在以后进行任意组装。

  • 引用sql片段

    <!-- 用户信息综合查询总数 -->
    <select id="findUserCount" parameterType="UserQueryVo" resultType="int">
        select count(*) from user
        <where>
            <!-- 引用sql片段。如果指定的id不在本mapper文件中,需要在前面加上namespace,当然我们可能会引用多个sql片段 -->
            <include refid="query_user_where"></include>
        </where>
    </select>
    
    <!-- 用户信息综合查询-->
    <select id="findUserList" parameterType="UserQueryVo" resultType="UserCustom">
        select * from user
        <!-- where可以自动的去掉条件中的第一个and -->
        <where>
            <include refid="query_user_where"></include>
        </where>
    </select>
  • 测试
    测试方法和之前的一样,这里不再多说。

3.3 foreach标签

如果现在向sql中传递了一个List(或数组等),mybatis使用foreach解析

  • 需求(工程mybatis07
    在用户查询列表和查询总数的statement中增加多个id输入查询。这里给出sql语句:
(1)SELECT * FROM USER WHERE ... and (id = 1 OR id = 10 OR id = 16);
(2)SELECT * FROM USER WHERE ... and id IN(1, 10, 16)

这里两个sql的功能是一样的。当然sql中可能会有多个条件。

  • 在输出的参数类型中添加List<Integer> ids来传入多个id

UserQueryVo.java

package cn.itcast.pojo;
import java.util.List;

//包装类型
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;
    }
    
}
  • 修改配置
    需要修改sql片段
    <!-- 定义一个sql片段-->
    <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>
        <if test="ids != null">
            <!-- 这里我们要将:and ( id = 1 or id = 10 or id = 16)拼接进去 -->
            <!-- 使用ForEach遍历传入的ids
             collection:指定输入对象中集合属性
             item:每次遍历生成的对象名
             open:开始遍历时所要拼接的sql串
             close:结束遍历时所要拼接的sql串
             separator:遍历的两个对象中需要拼接的sql串-->
            <foreach collection="ids" item="id" open="and (" close=")" separator="or">
                <!-- 每次遍历要拼接的sql串,下面#{id}中的id和item一致 -->
                id = #{id}
            </foreach>
        </if>
    </sql>
  • 测试
    //用户信息综合查询测试
    @Test
    public void findUserList(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
        
        //创建包装对象,设置查询条件
        UserQueryVo userQueryVo = new UserQueryVo();
        UserCustom userCustom = new UserCustom();
        //由于这里使用了动态sql,如果不设置值,条件就不会拼接到sql中
        userCustom.setSex("1");
        //传入多个id
        List<Integer> ids = new ArrayList<Integer>();
        ids.add(1);
        ids.add(10);
        ids.add(16);
        userQueryVo.setIds(ids);
        userQueryVo.setUserCustom(userCustom);
        List<UserCustom> list = userMapper.findUserList(userQueryVo);
        
        for(UserCustom user : list){
            System.out.println(user.getUsername());
        }
        sqlSession.close();
        
    }
  • 如果我们使用第二条sql则可以这样写
<!-- 对 and id in(1, 10, 16)的拼接 -->
<foreach collection="ids" item="id" open="and id in(" close=")" separator=",">
<!-- 每次遍历要拼接的sql串,下面#{id}中的id和item一致 -->
    #{id}
</foreach>
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,482评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,377评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 152,762评论 0 342
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,273评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,289评论 5 373
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,046评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,351评论 3 400
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,988评论 0 259
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,476评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,948评论 2 324
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,064评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,712评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,261评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,264评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,486评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,511评论 2 354
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,802评论 2 345

推荐阅读更多精彩内容

  • 1. 简介 1.1 什么是 MyBatis ? MyBatis 是支持定制化 SQL、存储过程以及高级映射的优秀的...
    笨鸟慢飞阅读 5,429评论 0 4
  • 每个线程都应该有它自己的SqlSession实例。SqlSession的实例不能共享使用,它是线程不安全的 配置文...
    蕊er阅读 468评论 0 0
  • Mapper.xml映射文件 Mapper.xml映射文件定义了操作数据库的sql,每个sql是一个stateme...
    暗物质阅读 8,613评论 0 2
  • 主要内容: 开发中数据模型的分析流程 一对一查询 一对多查询 一、开发中数据模型的分析流程 一般在开发中我们会直接...
    yjaal阅读 2,156评论 5 8
  • 官方文档 简介 入门 XML配置 XML映射文件 动态SQL Java API SQL语句构建器 日志 一、 JD...
    拾壹北阅读 3,541评论 0 52