MyBatis学习笔记:进阶知识2

MyBatis 作为一款优秀的持久层框架,在 Java 开发中占据着重要地位。它简化了数据库操作,提供了灵活且高效的数据访问方式。本文将深入探讨 MyBatis 的核心功能,包括分页查询、联表查询、动态 SQL 以及代码自动生成,并结合实际案例进行详细分析,帮助读者更好地理解和应用这些功能。

一、MyBatis 框架回顾

在深入学习 MyBatis 的高级特性之前,我们先来回顾一下 MyBatis 框架的基础知识。MyBatis 框架主要用于数据库访问,它通过将 SQL 语句与 Java 代码分离,实现了数据持久化层的解耦。以下是 MyBatis 框架的一些关键知识点:

(一)注解方式实现单表操作

MyBatis 提供了一系列注解,如@Select@Insert@Delete@Update,用于在接口方法上直接编写 SQL 语句,实现对单表的增删改查操作。这种方式简单直观,适用于简单的数据库操作场景。

(二)MyBatis 的优化策略

  1. 日志添加
    • 引入log4jjar包,并添加log4j.properties配置文件,以便在开发过程中更好地跟踪和调试 MyBatis 的执行过程,帮助开发者快速定位问题。
  2. 实体类别名设置
    • 为实体类起别名,在编写 SQL 语句时可以直接使用别名代替完整的类名,使 SQL 语句更加简洁易读,提高代码的可维护性。
  3. 数据源信息抽取
    • 将数据源的信息抽取到属性文件中,通过${key}的方式引用属性值。这样,在切换数据源或修改数据库连接信息时,无需修改代码,只需调整属性文件即可,增强了程序的灵活性和可配置性。

(三)其他常用功能

  1. 获取递增 ID 值
    • 在执行插入操作时,通过设置<insert useGeneratorKey="true" keyProperty="属性">,可以方便地获取数据库自动生成的递增 ID 值,并将其赋值给实体类的相应属性。
  2. 多参处理
    • 使用@Param("名称")注解为方法参数命名,然后在 SQL 语句中通过#{名称}引用参数,解决了多参数传递的问题,使 SQL 语句与方法参数的对应关系更加清晰。
  3. 特殊符号处理
    • 当 SQL 语句中包含特殊符号时,可以使用转义符或者<![CDATA[sql]]>的方式进行处理,避免因特殊符号导致的 SQL 语法错误。
  4. 模糊查询实现
    • 通过concat("%",#{},"%")函数,在查询条件中实现模糊查询,方便根据关键字搜索相关数据。
  5. 属性名与列名不一致处理
    • 提供了两种解决方案。一是为查询的列起别名,使其与属性名一致;二是通过ResultMap标签建立列名和属性名的映射关系,确保数据的正确封装。

二、分页查询

在实际应用中,分页查询是常见的需求。MyBatis 本身没有提供分页功能,但可以通过集成分页插件来实现。以 PageHelper 插件为例,详细介绍分页查询的实现步骤。

(一)引入 PageHelper 依赖

在项目的pom.xml文件中添加 PageHelper 的依赖:

XML 复制代码
<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>6.0.0</version>
</dependency>

(二)配置 MyBatis

在 MyBatis 的配置文件中,添加如下插件配置:

XML 复制代码
<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="param1" value="value1"/>
    </plugin>
</plugins>
XML 复制代码
<select id="selectAll" resultType="java.util.Map">
    select * from tbl_emp e join tbl_dept d on e.did = d.dept_id
</select>
  1. 使用 association 标签(第二种方案)
    • 优点:通过定义实体类之间的关联关系,使代码结构更加清晰,属性调用更加直观。
    • 缺点:需要创建额外的实体类和映射配置。
    • 示例代码:
java 复制代码
public List<Emp> selectAll01();
XML 复制代码
<resultMap id="EmpMapper" type="org.example.entity.Emp">
    <id column="emp_id" property="id"/>
    <result column="emp_name" property="name"/>
    <result column="emp_job" property="job"/>
    <result column="emp_salary" property="salary"/>
    <result column="did" property="di"/>
    <!-- association:表示多对一的标签 property: 该类中实体类的属性名 javaType:该属性所属于的类型 -->
    <association property="dept" javaType="org.example.entity.Dept">
        <id column="dept_id" property="id"/>
        <result column="dept_name" property="name"/>
        <result column="dept_loc" property="loc"/>
    </association>
</resultMap>
<select id="selectAll01" resultMap="EmpMapper">
    select * from tbl_emp e join tbl_dept d on e.did = d.dept_id
</select>

(二)一对多关系查询

  1. 使用 Map 类(第一种方案,省略)

    • 与多对一关系中使用 Map 集合类类似,但在一对多场景下,使用 Map 可能会导致数据结构不够清晰,维护困难。
  2. 使用 Collection 标签(第二种方案)

    • 优点:能够清晰地表达一对多的关系,通过配置Collection标签,可以方便地获取关联的多个对象集合。
    • 缺点:配置相对复杂,需要仔细定义映射关系。
    • 示例代码(查询部门信息并携带部门对应的员工信息):
java 复制代码
public Dept selectById(int id);
public List<Dept> selectAll();
XML 复制代码
<resultMap id="DeptMapper" type="org.example.entity.Dept">
    <id column="dept_id" property="id" />
    <result column="dept_name" property="name"/>
    <result column="dept_loc" property="loc"/>
    <!-- collection:表示一对多的标签 property:集合对应的属性名 ofType:该属性集合的泛型类型 -->
    <collection property="emp" ofType="org.example.entity.Emp">
        <id column="emp_id" property="id"/>
        <result column="emp_name" property="name"/>
        <result column="emp_job" property="job"/>
        <result column="emp_salary" property="salary"/>
        <result column="did" property="did"/>
    </collection>
</resultMap>
<select id="selectById" resultMap="DeptMapper">
    select * from tbl_emp e join tbl_dept d on e.did = d.dept_id where dept_id = #{id}
</select>
<select id="selectAll" resultMap="DeptMapper">
    select * from tbl_emp e join tbl_dept d on e.did = d.dept_id
</select>

(三)联表查询的 SQL 优化

  1. 合理选择连接方式
    • 根据业务需求和数据特点,选择合适的连接方式(如INNER JOINLEFT JOINRIGHT JOIN),避免不必要的数据冗余和查询性能问题。
  2. 建立合适的索引
    • 对关联字段建立索引,可以提高联表查询的效率。例如,在员工表的did字段和部门表的dept_id字段上建立索引。

四、动态 SQL 标签

在实际应用中,查询条件往往是动态变化的。MyBatis 提供了动态 SQL 标签,用于根据不同的条件动态拼接 SQL 语句,提高代码的灵活性和可维护性。

(一)动态 SQL 标签介绍

  1. <trim>标签
    • 通过修剪 SQL 语句的开头和结尾来动态生成 SQL 片段。可以去除不必要的 SQL 关键字或条件语句,并根据属性定义修剪规则。
  2. <where>标签
    • 用于在生成的 SQL 语句中添加WHERE子句。它能自动处理条件语句的前缀,在有条件语句存在时添加WHERE关键字,并去除 SQL 中的第一个AND标签。
  3. <set>标签
    • 用于在生成的 SQL 语句中添加SET子句,主要用于更新操作,根据条件动态生成需要更新的列。
  4. <foreach>标签
    • 用于在 SQL 语句中进行循环操作,可遍历集合或数组,并根据指定模板将元素插入到 SQL 语句中,常用于批量删除和批量添加操作。
  5. <if>标签
    • 根据指定条件决定是否包含某个 SQL 语句片段,实现条件判断。
  6. <choose><when><otherwise>标签
    • 类似于 Java 中的switch语句,<choose>根据条件选择执行不同的 SQL 语句片段,<when>定义条件分支,<otherwise>在所有<when>条件不匹配时执行的 SQL 语句片段。

(二)示例代码

  1. 使用<if>标签实现多条件查询
java 复制代码
public List<Emp> selectByCondition01(@Param("name") String name, @Param("job") String job, @Param("salary") Double salary);
XML 复制代码
<select id="selectByCondition01" resultMap="EmpMapper">
    select * from tbl_emp
    <where>
        <if test="name!=null and name!=''">
            and emp_name like concat('%',#{name},'%')
        </if>
        <if test="job!=null and job!=''">
            and emp_job=#{job}
        </if>
        <if test="salary!=null">
            and emp_salary=#{salary}
        </if>
    </where>
</select>
  1. 使用<choose><when><otherwise>标签实现条件分支查询
XML 复制代码
<select id="selectByCondition02" resultMap="EmpMapper">
    select * from tbl_emp
    <where>
        <choose>
            <when test="name!=null and name!=''">
                and emp_name like concat('%', #{name}, '%')
            </when>
            <when test="job!=null and job!=''">
                and emp_job=#{job}
            </when>
            <when test="salary!=null">
                and emp_salary=#{salary}
            </when>
        </choose>
    </where>
</select>
  1. 使用<foreach>标签实现批量删除和批量添加
    • 批量删除示例:
java 复制代码
public int batchDelete(@Param("ids") Integer[] ids);
XML 复制代码
<delete id="batchDelete">
    delete from tbl_emp where id in
    <foreach collection="ids" item="i" open="(" close=")" separator=", ">
        #{id}
    </foreach>
</delete>
  • 批量添加示例:
java 复制代码
public int batchInsert(@Param("emps") List<Emp> emps);
XML 复制代码
<insert id="batchInsert">
    insert into tbl_emp(emp_name,emp_job,emp_salary,did) values
    <foreach collection="emps" item="e" separator=",">
        (#{e.name},#{e.job},#{e.salary},#{e.did})
    </foreach>
</insert>

(三)动态 SQL 的应用场景

  1. 多条件组合查询
    • 根据用户输入的不同查询条件,动态生成包含相应条件的 SQL 语句,如电商平台中的商品搜索功能,根据品牌、价格范围、规格等多个条件进行筛选查询。
  2. 动态更新操作
    • 根据业务规则,只更新部分字段。例如,用户信息修改功能,仅更新用户修改的字段,而不是全部字段。
  3. 批量操作
    • 如批量删除选中的记录或批量插入多条数据,提高操作效率,减少数据库交互次数。

五、MyBatis 代码自动生成

随着项目的不断发展,编写大量的 MyBatis 映射文件和实体类会变得繁琐且容易出错。MyBatis 提供了代码自动生成工具,可以根据数据库表结构快速生成实体类、映射文件和 DAO 接口等代码,提高开发效率。

(一)使用 MyBatis Generator 工具

  1. 配置文件编写
    • 创建一个generatorConfig.xml配置文件,指定数据库连接信息、生成代码的目标路径、实体类包名、映射文件包名等参数。例如:
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<generatorConfiguration>
    <context id="DB2Tables" targetRuntime="MyBatis3">
        <jdbcConnection driverClass="com.mysql.cj.jdbc.Driver"
                        connectionURL="jdbc:mysql://localhost:3306/mydb?serverTimezone=UTC"
                        userId="root"
                        password="123456">
        </jdbcConnection>
        <javaModelGenerator targetPackage="com.example.entity" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <sqlMapGenerator targetPackage="com.example.mapper" targetProject="src/main/resources">
            <property name="enableSubPackages" value="true"/>
        </sqlMapGenerator>
        <javaClientGenerator type="XMLMAPPER" targetPackage="com.example.dao" targetProject="src/main/java">
            <property name="enableSubPackages" value="true"/>
        </javaClientGenerator>
        <table tableName="tbl_emp" domainObjectName="Emp"/>
        <table tableName="tbl_dept" domainObjectName="Dept"/>
    </context>
</generatorConfiguration>
  1. 执行生成命令
    • 在命令行中执行 MyBatis Generator 的命令,或者在项目中通过 Maven 插件执行。执行后,将根据配置生成相应的实体类、映射文件和 DAO 接口。

(二)代码生成器的优势与注意事项

  1. 优势
    • 大大提高开发效率,减少手动编写代码的工作量,降低出错率。
    • 保证代码结构的一致性,便于团队协作和项目维护。
  2. 注意事项
    • 生成的代码可能需要根据实际需求进行适当调整,如添加自定义的方法、修改注释等。
    • 当数据库表结构发生变化时,需要及时重新生成代码,以确保代码与数据库的一致性。
相关推荐
Chen-Edward40 分钟前
有了Spring为什么还有要Spring Boot?
java·spring boot·spring
陈小桔2 小时前
idea中重新加载所有maven项目失败,但maven compile成功
java·maven
小学鸡!2 小时前
Spring Boot实现日志链路追踪
java·spring boot·后端
xiaogg36782 小时前
阿里云k8s1.33部署yaml和dockerfile配置文件
java·linux·kubernetes
逆光的July2 小时前
Hikari连接池
java
微风粼粼2 小时前
eclipse 导入javaweb项目,以及配置教程(傻瓜式教学)
java·ide·eclipse
番茄Salad2 小时前
Spring Boot临时解决循环依赖注入问题
java·spring boot·spring cloud
天若有情6732 小时前
Spring MVC文件上传与下载全面详解:从原理到实战
java·spring·mvc·springmvc·javaee·multipart
祈祷苍天赐我java之术3 小时前
Redis 数据类型与使用场景
java·开发语言·前端·redis·分布式·spring·bootstrap
Olrookie4 小时前
若依前后端分离版学习笔记(二十)——实现滑块验证码(vue3)
java·前端·笔记·后端·学习·vue·ruoyi