MyBatis学习系列(五)--------参数映射、动态sql、关联查询

前言

    除了SqlMapConfig.xml作为MyBatis的核心配置文件,映射文件也是mybatis中比较重要的,其中,关于输出和输入参数的映射,动态sql的实现以及多表关联查询,都需要我们去掌握.

正文

(一)参数映射

●parameterType(输入类型)

  1. 简单数据类型
    当我们想要输入简单数据类型时,直接使用即可,如int等,可以参考前面博文中的表格来实现.

  2. 传递pojo对象
    可以使用parameterType="com.mybatis.po.User的方式来指定入参为一个java对象,#{}${}中的值为对象的属性.

  3. 传递pojo包装对象
    在一般的开发中,查询条件是通过pojo对象来传递的,比如这个条件中不仅仅包括用户信息,还有其他的查询条件,这个时候可以使用包装对象来传递输入参数.
    比如现在要根据用户名查询用户信息,但是查询的结果要包含在一个QueryVo对象中.
    首先创建一个QueryVo对象:

package com.mybatis.po;

public class QueryVo {

    private User user;

    public User getUser() {
        return user;
    }

    public void setUser(User user) {
        this.user = user;
    }   
}

接着在UserMapper接口中添加一个方法:
public List<User> findUserByQueryVo(QueryVo queryVo);
在UserMapper.xml中添加对应的方法:

    <select id="findUserByQueryVo" parameterType="com.mybatis.po.QueryVo" resultType="com.mybatis.po.User">
        select * from user where username like '%${user.username}%'
    </select>

这里需要注意,如果参数是一个包装poji属性对象的属性,就像上面这样的,就要使用"."的方式来传值
下面来对这个方法进行测试:

    @Test
    public void testFindUserByQueryVo() {
        SqlSession session = sqlSessionFactory.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        QueryVo queryVo = new QueryVo();
        User user = new User();
        user.setUsername("张");
        queryVo.setUser(user);
        List<User> list = mapper.findUserByQueryVo(queryVo);
        for (User resultUser : list) {
            System.out.println(resultUser);
        }
        session.close();
    }

查询结果如下:
这里写图片描述
可以看到,我们查出了两条数据.

●resultType(输出类型)

①简单数据类型

输出简单数据类型必须保证查询的结果只有一条记录,最终会将第一个字段转换为输出类型

扫描二维码关注公众号,回复: 3533169 查看本文章
    <!-- 统计用户数量 -->
    <select id="countUserNum"  resultType="int">
        select count(1) from user
    </select>

public int countUserNum();
测试方法:

    @Test
    public void testcountUserNum() {
        SqlSession session = sqlSessionFactory.openSession();
        UserMapper mapper = session.getMapper(UserMapper.class);
        int count = mapper.countUserNum();
        System.out.println("总共有:" + count + "个用户!");
        session.close();
    }

查询结果如下:
这里写图片描述

②输出pojo对象
输出数据类型为java的pojo对象时,只需要查询结果的字段和pojo对象的属性名相对应即可.

●resultMap
    resultType指定java对象将查询结果映射为pojo,但是需要pojo和查询的列名一致才能映射成功.如果sql查询字段名和pojo的属性名不一致,可以通过resultMap将字段名和属性名做对应关系,实际上还是需要将查询结果映射到pojo对象中.resultMap可以实现将查询结果映射为复杂类型的pojo.

如果我们的user类的主键属性是id,而user表的主键字段是uid,那么如果直接使用resultType的话,需要加别名,或者修改User类,在这里,我们可以使用resultMap来建立两者的映射关系:

    <resultMap type="com.mybatis.po.User" id="user_table">
        <id column="uid" property="id"/>
        <result column="username" property="username"/>
        <result column="password" property="password"/>
    </resultMap>
    <!-- 测试resultMap映射pojo信息 -->
    <select id="textResultMap" parameterType="int" resultMap="user_table">
        select * from user where uid = #{id}
    </select>

在mapper中新建一个textResultMap方法:
public User textResultMap(int id);
最后测试顺利的查询出了用户的信息.
在这里,有必要对resultMap标签中的属性做个说明:
<id/>表示结果集的唯一标识.
property表示对应java对象的属性
column表示sql查询出来结果的字段名,和property放在一起,表示将sql查询结果映射到指定的pojo类的属性上.
<result/>除主键外的其他的属性可以使用该标签来建立映射.

(二)动态sql
  • if
    当我们的查询条件是多个,且个数不确定的时候,可以使用if标签动态生成sql:
<!-- 传递pojo综合查询用户信息 -->
    <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>

标签中的test代表条件判断.

  • where
    改造上面的sql,去掉where后面的1=1,可以使用<where/>标签来去除第一个and
    <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>
  • foreach
    向sql传递List或者数组的时候,我们可以使用mybatis提供的foreach标签进行解析.比如,传入多个用户的id,查出这些id所属的用户信息.
    <select id="findUserByIds" parameterType="QueryVo" resultType="com.mybatis.po.User">
        SELECT * FROM user
        <where>
            <!-- 相当于 and id in (1,10,20,30) --> 
            <foreach collection="ids" item="id" open="and id in (" close=")" separator=",">
                #{id}
            </foreach>
        </where>
    </select>

collection代表QueryVo中的数组ids
item代表遍历的每个变量,也就是每一个用户id
open代表拼装sql语句的开始部分
close代表sql语句的结尾部分
separator代表间隔符

  • sql片段
    将sql语句中重复的sql提取出来,在使用的时候可以使用include引用:
<!-- 传递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条件:

<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>

引用:

<select id="findUserList" parameterType="user" resultType="user">
        select * from user 
        <where>
        <include refid="query_user_where"/>
        </where>
    </select>

需要注意的是,如果引用了其他mapper.xml的sql片段,需要在引用的时候加上namespace,比如:
<include refid="namespace.sql片段”/>

(三)关联查询

    有的需求需要对数据库中的多张表就行关联查询,来看看对于关联查询,mybatis是怎么处理的呢?

  • 数据模型:商品&订单
    我们再创建一个订单表,订单表中的user_id作为外键,指向user表中的主键id:
    这里写图片描述
    首先,从订单这边来看,一个订单对于一个用户,属于一对一;从用户这边来看,一个用户对应多个订单,属于一对多,下面我们使用mybatis来实现这两种情况下的数据查询.
  • 一对一查询
    需求:查询所有订单信息,关联查询订单所属的用户信息.
    也就是要查询出下面这样的数据:
    这里写图片描述

这里我们可以有两种方法来实现:
1. 使用resultType自定义一个po类,该类包含查询结果的所有字段

package com.mybatis.po;

public class OrderUser extends Orders {

    private String username;

    private String password;

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

接着在mapper接口中添加一个方法:

public List<OrderUser> findOrderList();

在mapper.xml文件中添加对应的sql:

    <select id="findOrderList" resultType="com.mybatis.po.OrderUser">
        select 
            o.id,
            o.user_id userId,
            o.number,
            o.createtime,
            o.note,
            u.username,
            u.password
        from orders o LEFT JOIN `user` u ON o.user_id = u.id; 
    </select>

这样我们就可以使用和这个方法来查询到需要的数据:

    @Test
    public void testFindOrderList() {
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<OrderUser> list = mapper.findOrderList();
        for (OrderUser orderUser : list) {
            System.out.println(orderUser);
        }
        sqlSession.close();

2. 使用resultMap,专门针对查询结果定义resultMap来接收查询结果
首先我们在Orders类中添加一个属性User对象:

    public class Orders {
        ......
        public User getUser() {
            return user;
        }

        public void setUser(User user) {
            this.user = user;
        }
    }

然后写对应的sql语句,并创建resultMap:

    <resultMap type="com.mybatis.po.Orders" id="OrderUser_ResultMap">
        <id property="id" column="id"/>
        <result property="userId" column="user_id"/>
        <result property="number" column="number"/>
        <result property="createtime" column="createtime"/>
        <result property="note" column="note"/>
        <!-- 配置一对一的用户关联映射条件 -->
        <association property="user" javaType="com.mybatis.po.User">
            <id property="id" column="id"/> 
            <result property="username" column="username"/>
            <result property="password" column="password"/>
        </association>
    </resultMap>

    <select id="findOrderList_ResultMap" resultMap="OrderUser_ResultMap">
        select 
            o.id,
            o.user_id ,
            o.number,
            o.createtime,
            o.note,
            u.username,
            u.password
        from orders o LEFT JOIN `user` u ON o.user_id = u.id; 
    </select>

association表示进行关联查询单条记录
property表示关联结果储存在com.mybatis.po.User对象中
javaType表示关联查询的结果类型

Mapper接口中添加方法:
public List<Orders> findOrderList_ResultMap();

测试:

    @Test
    public void testFindOrderList_ResultMap(){
        SqlSession sqlSession = sqlSessionFactory.openSession();
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        List<Orders> list_ResultMap = mapper.findOrderList_ResultMap();
        for (Orders orders : list_ResultMap) {
            System.out.println(orders);
        }
        sqlSession.close();
    }
  • 一对多查询

需求:查询所有的用户信息以及关联的订单信息.
在这个需求中,用户和订单是一对多的关系,我们可以使用resultMap来实现:
首先,在User类中添加一个List属性:

public class User {

    private Integer id;

    private String username;

    private String password;

    private List<Orders> orders;


    public List<Orders> getOrders() {
        return orders;
    }

    public void setOrders(List<Orders> orders) {
        this.orders = orders;
    }
    ......

编写sql语句:

    <resultMap type="com.mybatis.po.User" id="user_order_resultmap">
        <id property="id" column="id"/>
        <result property="username" column="username"/>
        <result property="password" column="password"/>
        <!-- 配置一对多的关系映射 -->
        <collection property="orders" ofType="com.mybatis.po.Orders">
            <!-- 这里的id对应的是orders的主键属性 -->
            <id property="id" column="id"/>
            <result property="number" column="number"/>
            <result property="createtime" column="createtime"/>     
            <result property="note" column="note"/>
        </collection>
    </resultMap>
    <select id="getUserWithOrders" resultMap="user_order_resultmap">
        select
            u.id,
            u.username,
            u.password,
            o.id oid,
            o.number,
            o.createtime,
            o.note
        from
            `user` u
        left join orders o on u.id = o.user_id
    </select>

注意:
collection部分定义了用户关联的订单信息,表示关联查询结果集
property="orders"表示关联查询的结果集存储在User对象的orders属性上
ofType="com.mybatis.po.Orders"表示关联查询结果集中的数据类型,即List中的对象类型,此处可以使用别名,也可以使用全限定名.

总结

    关于mybatis的使用,到这里大概就差不多了,在后期随着项目经验的不断增加,我也会陆续的更新系列文章,做到温故知新!!

猜你喜欢

转载自blog.csdn.net/xiaoyao2246/article/details/81171180
今日推荐