Mybatis 框架使用指南(进阶)

简介: Mybatis 框架使用指南(进阶)

Mybatis 映射文件深入


动态sql


if 标签

if 标签:


判断语句(单条件分支)。必须结合 test 属性联合使用。


常用场景:


   在 WHERE 条件中使用 if 标签。根据条件判断动态拼接查询条件。

   在 UPDATE 更新列中使用 if 标签。只更新有变化的字段, 空值不更新。

   在 INSERT 动态插入中使用 if 标签。只有非空属性才插入。

   在 SELECT 动态查询字段使用 if 标签。根据条件动态确定查询字段。


mapper接口方法:

public List<User> findByIdAndUsernameIf(User user);


xml文件:

<select id="findByIdAndUsernameIf" parameterType="user" resultType="user">
    select * from user 
    <!-- where 1=1 是多条件拼接时的小技巧,后面的条件查询就可以都用and了 -->
    <!-- where 1 = 1 -->
    <!-- where 标签:相当于 where 1=1 功能,
     当if条件都不满足时,where 将不会拼接在sql语句中
     当if有条件满足时,where 将会拼接在sql语句中,且去掉第一个成立的 if 标签下的 and | or 等  -->
    <where>
        <if test="id != null">
            and id = #{id}
        </if>
        <if test="username != null">
            and username like concat('%',#{username}),'%')
        </if>
    </where>
</select>


choose 标签

choose when otherwise 标签可以帮我们实现 if else 的逻辑(或 java 中的 switch 语句)。

一个 choose 标签至少有一个 when,最多一个otherwise。


mapper接口方法:

public List<User> findByIdAndUsernameChoose(User user);
• 1

xml文件:

<!--
        choose标签 相当于 switch语句
        when标签 相当于 case+break语句
        otherwise 相当于 default语句
-->
<select id="findByIdAndUsernameChoose" parameterType="user" resultType="user">
    select * from user
    <where>
        <choose>
            <when test="id != null">
                and id = #{id}
            </when>
            <when test="username != null">
                 and username like concat(concat('%',#{username}),'%')
            </when>
            <otherwise>
                and 1 = 1
            </otherwise>
        </choose>
    </where>
</select>



set 标签

可以去掉 set 标签中的最后一个条件的 逗号

mapper接口方法:

public void updateIf(User user);



xml方法:

<update id="updateIf" parameterType="user">
    update user 
    <set>
        <if test="username != null">
            username=#{username},
        </if>
        <if test="birthday != null">
            birthday=#{birthday},
        </if>
        <if test="sex != null">
            sex = #{sex},
        </if>
        <if test="address != null">
            address = #{address},
        </if>
    </set>
    where id = #{id}
</update>



foreach 标签

做数据的循环遍历

* 例如:
  select * from user where id in (1,2,3)
  在这样的语句中,传入的参数部分必须依靠 foreach遍历才能实现。


foreach 标签中的属性:


   collection:必填, 被遍历的集合(list)/数组(array)/Map的名称

   item:变量名。即从迭代的对象中取出的每一个值

   index:索引的属性名。当迭代的对象为 Map 时, 该值为 Map 中的 Key.

   open:遍历前拼接的字符串

   close:遍历后拼接的字符串

   separator:分隔符



where 中使用 foreach

mapper接口方法:

// foreach标签 遍历
public List<User> findByList(List<Integer> ids);
public List<User> findByArray(Integer[] ids);
// 传递引用数据类型 list属性或者array属性
public List<User> findByPojo(QueryVo queryVo);


xml文件:

<!-- 传递 普通类型list集合   collection=""   取值:collection、list -->
<select id="findByList" parameterType="list" resultType="user">
    select * from user where
    <foreach collection="list" open="id in (" close=")" item="id" separator=",">
        #{id}
    </foreach>
</select>
<!-- 传递 普通类型array数组   collection=""   取值:array -->
<select id="findByArray" parameterType="int[]" resultType="user">
    select * from user where
    <foreach collection="array" open="id in (" close=")" item="id" separator=",">
        #{id}
    </foreach>
</select>
<!-- 传递 引用数据类型list集合属性   collection="" 取值   集合或数组的 属性名 -->
<select id="findByPojo" parameterType="QueryVo" resultType="user">
    select * from user where
    <foreach collection="ids" open="id in (" close=")" item="id" separator=",">
        #{id}
    </foreach>
</select>


foreach 实现批量插入

mapper接口方法:

// 批量插入学生
    int insertList(List<Student> students);


xml文件:

    <insert id="insertList">
        insert into student(name, phone, email, sex, locked)
        values
        <foreach collection="list" item="student" separator=",">
            (
            #{student.name}, #{student.phone},#{student.email},
            #{student.sex},#{student.locked}
            )
        </foreach>
    </insert>


trim 标签

trim 标签的属性


   prefix: 当 trim 元素包含有内容时, 增加 prefix 所指定的前缀


   prefixOverrides: 当 trim 元素包含有内容时, 去除 prefixOverrides 指定的前缀


   suffix: 当 trim 元素包含有内容时, 增加 suffix 所指定的后缀


   suffixOverrides:当 trim 元素包含有内容时, 去除 suffixOverrides 指定的后缀、

set 和 where 其实都是 trim 标签的一种类型, 该两种功能都可以使用 trim 标签进行实现。



trim 标签来实现 where 标签

当 trim 标签中含有内容时,添加 where,且第一个为 and 或 or 时,会将其去掉;而如果没有内容,则不添加 where


<trim prefix="where" prefixOverrides="AND |OR">
</trim>


trim 标签来实现 set 标签

当 trim 标签中含有内容时,添加 set,且最后的内容为 , 时,会将其去掉;而没有内容,不添加 set

<trim prefix="SET" suffixOverrides=",">
</trim>


bind 标签

bind 元素允许在 OGNL 表达式以外创建一个变量,并将其绑定到当前的上下文。

如在 selectByStudentSelective 方法中,有如下

<if test="name != null and name !=''">
      and name like concat('%', #{name}, '%')
</if>


在 MySQL 中,concat 函数支持多参数,但在 Oracle 中只支持两个参数。通过使用 bind 来让该 SQL 达到支持两个数据库的作用

<if test="name != null and name !=''">
     <bind name="nameLike" value="'%'+name+'%'"/>
     and name like #{nameLike}
</if>


include 标签(引入sql片段)

<!-- 可以将公共部分进行抽取 -->
<sql id="userSelect">
    select * from user
</sql>
<!-- 引入sql片段 -->
<select id="findByArray" parameterType="int[]" resultType="user">
    <include refid="userSelect"></include> 
    where 
    <foreach collection="array" open="id in (" close=")" item="id" separator=",">
        #{id}
    </foreach>
</select>
<select id="findByPojo" parameterType="QueryVo" resultType="user">
    <include refid="userSelect"></include> 
    where 
    <foreach collection="ids" open="id in (" close=")" item="id" separator=",">
        #{id}
    </foreach>
</select>



生成并返回主键

往数据库中插入记录时,生成主键并将主键返回到原实体对象中


   方式1:<selectKey>【复杂,但通用】

   既支持主键自增类型,也支持 UUID 类型的主键的生成与返回


   方式2:useGeneratedKeys【简单,但不通用】

   注意:这种方式仅支持主键自增类型的数据库,如 MySQL 和 sqlServer,oracle不支持


xml文件:


<!--
  方式1:<selectKey>
    keyColumn     数据库表的主键字段
    keyProperty   指定实体的主键属性名。selectKey语句结果应该被设置的目标属性
    resultType    指定实体主键的类型。
            可以不写,Mybatis通常可以推算出来。Mybatis允许任何简单类型作为主键的类型,包括字符串。
    order="AFTER"  selectKey的sql语句是在insert执行之前(执行),还是之后(执行)
      AFTER   之后执行。适合返回自增id的情况(主键是自增列,插入之后才能获知)。SELECT LAST_INSERT_ID() FROM DUAL
      BEFORE  之前执行。适合返回UUID的情况(主键不是自增列,需要预先生成)。SELECT UUID() FROM DUAL
    -->
<insert id="save2" parameterType="user">
    <selectKey keyColumn="id" keyProperty="id" resultType="int" order="AFTER">
        SELECT LAST_INSERT_ID() FROM DUAL
    </selectKey>
    insert into user(username, birthday, sex, address) values(#{username}, #{birthday}, #{sex}, #{address})
</insert>
<!--
  方式2:useGeneratedKeys
        useGeneratedKeys="true" 开启返回主键功能
    keyColumn         数据库表的主键字段
    keyProperty       指定实体的主键属性名
    -->
<insert id="save1" parameterType="user" useGeneratedKeys="true" keyColumn="id" keyProperty="id">
    insert into user(username,birthday,sex,address) values(#{username},#{birthday},#{sex},#{address})
</insert>




多表查询


表关系及xml标签配置介绍

一对一     订单与用户。查询站在订单角度:一个订单只能属于一个用户
一对多     用户和订单。查询站在用户角度:一个用户可以拥有多个订单
多对一   订单和用户。多个订单,可以被一个用户拥有
多对多     用户和角色。  - 站在用户角度:一个用户可以拥有多个角色
            - 站在角色角度:一个角色可以被多个用户拥有
mybatis:一个表是一个实体的映射(user  orders)
实体: 实体属性、集合属性
1 v 1: 实体属性
1 v N: 1的一方有多的一方的集合属性  多的一方有1的一方的实体对象
* 一对一配置:使用<resultMap>+<association>做配置
  association:
      property:关联的实体属性名
      javaType:关联的实体类型(使用别名)
* 一对多配置:使用<resultMap>+<collection>做配置
  collection:
    property:关联的集合属性名
    ofType:关联的集合泛型类型(使用别名)
* 多对多配置:使用<resultMap>+<collection>做配置
  collection:
    property:关联的集合属性名
    ofType:关联的集合泛型类型(别名)
* 多对多的配置跟一对多很相似,区别在于SQL语句的编写。



多表查询和嵌套查询的实体类

Orders(订单)实体类

@Data
public class Orders {
    private Integer id;
    private Date ordertime;
    private Double money;
    // 订单所属的用户
    private User user;
}


User(用户)实体类

@Data
public class User {
    private Integer id;
    private String username;
    private Date birthday;
    private String sex;
    private String address;
    // 一个用户有多个角色
    private List<Role> roleList;
    // 一个用户有多个订单
    private List<Orders> orders;
}


Role(角色)实体类

@Data
public class Role {
    private Integer id;
    private String roleName;
    private String roleDesc;
}



一对一(多对一)

一对一查询的实例:


需求:查询一个订单,与此同时查询出该订单所属的用户(1 v 1)

OrdersMapper.xml映射文件(一对一映射关系)

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.test.dao.OrdersDao">
    <!--手动封装-->
    <resultMap id="findOrderswithUserResultMap" type="orders">
            <!--订单orders-->
            <id column="iid" property="id"></id>
            <result column="ordertime" property="ordertime"></result>
            <result column="money" property="money"></result>
            <!--订单中的用户User(一对一的封装)
                    association标签
                      property:订单实体类中的用户属性名
                        javaType:要封装数据的属性属于什么类型。不写则自动映射
            -->
            <association property="user" javaType="cn.test.domain.User">
                    <id column="uid" property="id"></id>
                    <result column="username" property="username"></result>
                    <result column="birthday" property="birthday"></result>
                    <result column="sex" property="sex"></result>
                    <result column="address" property="address"></result>
            </association>
    </resultMap>
    <!-- 查询当前订单以及所属用户的信息 -->
    <select id="findOrderswithUser" parameterType="int" resultMap="findOrderswithUserResultMap">
        select *, o.id iid from orders o left join user u on o.uid=u.id where o.id=#{id}
    </select>
</mapper>



一对多

一对多查询的实例:


需求:查询一个用户,与此同时查询出该用户具有的所有订单(1 v N)

UserMapper.xml映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.test.dao.UserDao">
    <!--手动封装-->
    <resultMap id="findUserwithOrdersResultMap" type="user">
        <!--封装user数据-->
        <id column="id" property="id"></id>
        <result column="username" property="username"></result>
        <result column="birthday" property="birthday"></result>
        <result column="sex" property="sex"></result>
        <result column="address" property="address"></result>
        <!--封装user的list集合属性(一对多)
              collection标签
                  property:用户的订单集合属性名
                    ofType:要封装的list集合中的泛型类型
        -->
        <collection property="list" ofType="orders">
            <id column="iid" property="id"></id>
            <result column="ordertime" property="ordertime"></result>
            <result column="money" property="money"></result>
        </collection>
    </resultMap>
    <!-- 查询一个用户及订单的信息 -->
    <select id="findUserwithOrders" parameterType="int" resultMap="findUserwithOrdersResultMap">
        select *, o.id as iid from user u left join orders o on u.id=o.uid where u.id=#{id}
    </select>
</mapper>



多对多(二个一对多)

多对多的查询的实例:


需求: 查询某个用户的所有角色或者是某个角色的所有用户


  • 站在用户角度,一个用户可以拥有多个角色
  • 站在角色角度,一个角色可以被多个用户拥有
  • 所以 mybatis框架多对多的实现,跟一对多的步骤是一样的,区别点在于sql语句

UserMapper.xml映射文件

<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.test.dao.UserDao">
  <resultMap id="findUserwithRoleResult" type="user">
            <!--用户数据-->
            <id column="id" property="id"></id>
            <result column="username" property="username"></result>
            <result column="birthday" property="birthday"></result>
            <result column="sex" property="sex"></result>
            <result column="address" property="address"></result>
            <!--用户的角色集合(一对多)
                  collection标签
                      property:用户的角色集合属性名
                        oftype:要封装的类型
            -->
            <collection property="roleList"  ofType="Role">
                    <id column="rid" property="id"></id>
                    <result column="role_name" property="roleName"></result>
                   <result column="role_desc" property="roleDesc"></result>
            </collection>
    </resultMap>
    <!-- 查询某个用户及角色信息 -->
    <select id="findUserwithRole" parameterType="int" resultMap="findUserwithRoleResult">
        select * from user u 
        left join user_role ur on u.id=ur.uid  
        left join role r on r.id=ur.rid 
        where u.id=#{id}
    </select>
</mapper>


相关文章
|
12天前
|
SQL Java 数据库连接
持久层框架MyBatisPlus
持久层框架MyBatisPlus
30 1
持久层框架MyBatisPlus
|
26天前
|
缓存 Cloud Native 安全
探索阿里巴巴新型ORM框架:超越MybatisPlus?
【10月更文挑战第9天】在Java开发领域,Mybatis及其增强工具MybatisPlus长期占据着ORM(对象关系映射)技术的主导地位。然而,随着技术的发展,阿里巴巴集团推出了一种新型ORM框架,旨在提供更高效、更简洁的开发体验。本文将对这一新型ORM框架进行探索,分析其特性,并与MybatisPlus进行比较。
28 0
|
3月前
|
Java 数据库连接 Spring
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
文章是关于Spring、SpringMVC、Mybatis三个后端框架的超详细入门教程,包括基础知识讲解、代码案例及SSM框架整合的实战应用,旨在帮助读者全面理解并掌握这些框架的使用。
后端框架入门超详细 三部曲 Spring 、SpringMVC、Mybatis、SSM框架整合案例 【爆肝整理五万字】
|
3月前
|
Java 数据库连接 mybatis
mybatis框架图
文章介绍了MyBatis框架的起源、发展和其作为持久层框架的功能,提供了MyBatis的框架图以帮助理解其结构和组件。
mybatis框架图
|
3月前
|
Java 数据库连接 mybatis
后端框架的学习----mybatis框架(9、多对一处理和一对多处理)
这篇文章介绍了在MyBatis框架中如何处理多对一和一对多的关联查询,通过定义`<resultMap>`和使用`<association>`与`<collection>`元素来实现对象间的关联映射。
|
3月前
|
Java 数据库连接 测试技术
后端框架的学习----mybatis框架(8、lombok)
这篇文章介绍了如何在MyBatis框架中使用lombok库来简化Java实体类的编写,包括在IDEA中安装Lombok插件、在项目中导入lombok依赖以及在实体类上使用Lombok提供的注解。
|
3月前
|
SQL Java 数据库连接
【Java 第十三篇章】MyBatis 框架介绍
MyBatis 原名 iBATIS,2001 年由 Clinton Begin 创建,以其简易灵活著称。2010 年更名以重塑品牌形象。MyBatis 通过 SQL 映射文件将 SQL 语句与 Java 代码分离,支持编写原生 SQL 并与方法映射。具备对象关系映射功能,简化数据库记录处理。支持动态 SQL 构建,灵活应对不同查询条件。内置缓存机制,提升查询效率。相比全功能 ORM,MyBatis 提供更高 SQL 控制度和更好的维护性,并易于与 Spring 等框架集成,广泛应用于 Java 数据访问层。
37 0
|
3月前
|
druid Java 数据库连接
SpringBoot项目整合MybatisPlus持久层框架+Druid数据库连接池,以及实现增删改查功能
SpringBoot项目整合MybatisPlus和Druid数据库连接池,实现基本的增删改查功能。
333 0
|
3月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(5、分页)
这篇文章介绍了如何在MyBatis框架中实现分页功能,包括使用SQL的`limit`语句进行分页和利用MyBatis的`RowBounds`对象进行分页的方法。
|
3月前
|
SQL Java 数据库连接
后端框架的学习----mybatis框架(7、使用注解开发)
这篇文章讲述了如何使用MyBatis框架的注解方式进行开发,包括在接口上使用注解定义SQL语句,并通过动态代理实现对数据库的增删改查操作,同时强调了接口需要在核心配置文件中注册绑定。