Mybatis高级应用(上)

首先声明。该Mybatis系列的博客是我学习性博客,整个系列的博客是需要连贯起来看的。总结也是片段性总结的。如果觉得有些思维跳跃,或不连贯请参考代码。

本项目所有代码及文档都托管在 Github地址:https://github.com/JYG0723/mybatispractice

如果觉得不错的话,欢迎给个 star , 如果你想完善这个项目的话,你也可以 fork 后修改然后推送给我。


动态 SQL

通过mybatis提供的各种标签方法实现动态拼接sql。

对查询条件进行判断,如果输入的参数不为空才进行查询条件拼接。

public class Customer {

    private int id;
    private String username;
    private String password;
    private User user;

}
public interface CustomerDao {

    public Customer findCustomerById(int id);

    public Customer findCustomerByCustomer(@Param(value = "customer") Customer customer);//指定传入到xml配置文件中的参数的使用名称

}
<select id="findCustomerByCustomer" parameterType="Customer" resultType="Customer">
        SELECT * FROM customer
        <where><!-- where 1=1 -->
            <if test="customer.user != null"><!--用到java属性进行判断的地方,全名称引用避免参数找不到错误-->
                <if test="customer.user.password != null and customer.user.password != ''">
                    AND password = #{customer.user.password}
                </if>
                <if test="customer.user.username !=null and customer.user.username !=''">
                    AND username LIKE '%${customer.user.username}%'<!--自动忽略第一个通过条件判断接入的sql语句的 'and' 拼接前缀。-->
                </if>
            </if>
        </where>
</select>

Sql 片段

通过上面的其实看到在 where sql语句中有很多重复代码,可以将其抽取出来,组成一个sql片段,其他的statement就可以引用这个sql片段,利于系统的开发。

这里我们就拿上边sql 中的where定义一个sq片段如下:

select * from user
        <where>
        <!--refid: 指定sql片段的id,如果是写在其他的mapper文件中,则需要在前面加上namespace-->
            <include refid="query_user_where"/>
        </where>

selectKey useGeneratedKeys

插入更新一条数据时,可以使用selectKey获取id操作。当做多条数据插入更新时,而selectKey只能使用一次,此时应该使用useGeneratedKeys操作。

selectKey:

<insert id="insert">
 <selectKey keyProperty="id" resultType="int" order="BEFORE">
  <if test="_databaseId == 'oracle'">
   select seq_users.nextval from dual
  </if>
  <if test="_databaseId == 'db2'">
   select nextval for seq_users from sysibm.sysdummy1"
  </if>
 </selectKey>
 insert into users values (#{id}, #{name})
</insert>

useGeneratedKeys:

<insert id="insertAuthor" useGeneratedKeys="true" keyProperty="id">
    insert into Author (username,password,email,bio)
    values (#{username},#{password},#{email},#{bio})
</insert>

typeAliases

 <typeAliases>
        <typeAlias alias="User" type="po.User"/>
        <typeAlias alias="Customer" type="po.Customer"/>
        <!--
             <package napobean"></package>     包下的所有类的别名为他们的类名
        -->
        <typeAlias type="po.Orders" alias="Orders"/>
        <typeAlias type="po.OrdersUser" alias="OrdersUser"/>
        <typeAlias type="po.Items" alias="Items"/>
        <typeAlias type="po.Orderdetail" alias="Orderdetail"/>
        <typeAlias type="hashMap" alias="java.util.HashMap"/>
    </typeAliases>

foreach

<if test="ids!=null">
<!-- 使用 foreach遍历传入ids
collection:指定输入 对象中集合属性
item:每个遍历实体的名称
open:开始遍历时拼接的串
close:结束遍历时拼接的串
separator:遍历的两个对象中需要拼接的串
-->

<!-- 使用实现下边的sql拼接:
       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>

要做foreach的对象,作为入参时,List

使用 resultType 和 resultMap 一对一查询小结

使用 resultMap 将查询结果中的订单信息映射到 Orders 对象中,在 orders 类中添加 User 属性,将关联查询出来的用户信息映射到 orders 对象中的 user 属性中。使用 resultMap 将查询结果中的订单信息映射到 Orders 对象中,在 orders 类中添加 User 属性,将关联查询出来的用户信息映射到 orders 对象中的 user 属性中。

使用 resultType 将查询结果中的订单信息映射到 OrdersUser 对象中,因为该OrdersUser对象继承了Orders实体类,所以订单信息便可以映射到OrdersUser对象中。同时为该OrdersUser对象添加User实体的特有属性,同时将查询到的User属性映射到该类中。

  • resultType:使用resultType实现较为简单,如果pojo中没有包括查询出来的列名,需要增加列名对应的属性,即可完成映射。如果没有查询结果的特殊要求建议使用resultType。
  • resultMap:需要单独定义resultMap,实现有点麻烦,如果对查询结果有特殊的要求,使用resultMap可以完成将关联查询映射pojo的属性中。resultMap可以实现延迟加载,resultType无法实现延迟加载。

一对多查询

mybatis使用resultMap的collection对关联查询的多条记录映射到一个list集合属性中。

使用resultType实现:将订单明细映射到orders中的orderdetails中,需要自己处理,使用双重循环遍历,去掉重复记录,将订单明细放在orderdetails中。

多对多查询总结

将查询用户购买的商品信息明细清单,(用户名、用户地址、购买商品名称、购买商品时间、购买商品数量)

针对上边的需求就使用resultType将查询到的记录映射到一个扩展的pojo中,很简单实现明细清单的功能。

一对多是多对多的特例,如下需求:

查询用户购买的商品信息,用户和商品的关系是多对多关系。

需求1:

查询字段:用户账号、用户名称、用户性别、商品名称、商品价格(最常见)
企业开发中常见明细列表,用户购买商品明细列表,
使用resultType将上边查询列映射到pojo输出。

需求2:

查询字段:用户账号、用户名称、购买商品数量、商品明细(鼠标移上显示明细)
使用resultMap将用户购买的商品明细列表映射到user对象中。

总结:

使用resultMap是针对那些对查询结果映射有特殊要求的功能,比如特殊要求映射成的list中包括多个list。查询多表字段,不易用resultType实现的时候使用。

ResultMap 总结

resultType:
作用:

将查询结果按照sql列名pojo属性名一致性映射到pojo中。
场合:常见一些明细记录的展示,比如用户购买商品明细,将关联查询信息全部展示在页面时,此时可直接使用resultType将每一条记录映射到pojo中,在前端页面遍历list(list中是pojo)即可。

resultMap:
作用:

使用association和collection完成一对一和一对多高级映射(对结果有特殊的映射要求)。

association:
作用:

将关联查询信息映射到一个pojo对象中。
场合:为了方便查询关联信息可以使用association将关联订单信息映射为用户对象的pojo属性中,比如:查询订单及关联用户信息。
使用resultType无法将查询结果映射到pojo对象的pojo属性中,根据对查询出的结果集查询并遍历匹配时的需要选择使用resultType还是resultMap。

collection:
作用:

将关联查询信息映射到一个list集合中。
场合:为了方便查询遍历关联信息可以使用collection将关联信息映射到list集合中,比如:查询用户权限范围模块及模块下的菜单,可使用collection将模块映射到模块list中,将菜单列表映射到模块对象的菜单list属性中,这样的作的目的也是方便对查询结果集进行遍历查询。如果使用resultType无法将查询结果映射到list集合中的时候。

猜你喜欢

转载自blog.csdn.net/jyg0723/article/details/71079811