MyBatis学习笔记:进阶知识2

发布于:2024-12-18 ⋅ 阅读:(10) ⋅ 点赞:(0)

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 的依赖:

<dependency>
    <groupId>com.github.pagehelper</groupId>
    <artifactId>pagehelper</artifactId>
    <version>6.0.0</version>
</dependency>

(二)配置 MyBatis

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

<plugins>
    <!-- com.github.pagehelper为PageHelper类所在包名 -->
    <plugin interceptor="com.github.pagehelper.PageInterceptor">
        <property name="param1" value="value1"/>
    </plugin>
</plugins>
<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 标签(第二种方案)
    • 优点:通过定义实体类之间的关联关系,使代码结构更加清晰,属性调用更加直观。
    • 缺点:需要创建额外的实体类和映射配置。
    • 示例代码:
public List<Emp> selectAll01();
<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标签,可以方便地获取关联的多个对象集合。
    • 缺点:配置相对复杂,需要仔细定义映射关系。
    • 示例代码(查询部门信息并携带部门对应的员工信息):
public Dept selectById(int id);
public List<Dept> selectAll();
<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>标签实现多条件查询
public List<Emp> selectByCondition01(@Param("name") String name, @Param("job") String job, @Param("salary") Double salary);
<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>标签实现条件分支查询
<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>标签实现批量删除和批量添加
    • 批量删除示例:
public int batchDelete(@Param("ids") Integer[] ids);
<delete id="batchDelete">
    delete from tbl_emp where id in
    <foreach collection="ids" item="i" open="(" close=")" separator=", ">
        #{id}
    </foreach>
</delete>
  • 批量添加示例:
public int batchInsert(@Param("emps") List<Emp> emps);
<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 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. 注意事项
    • 生成的代码可能需要根据实际需求进行适当调整,如添加自定义的方法、修改注释等。
    • 当数据库表结构发生变化时,需要及时重新生成代码,以确保代码与数据库的一致性。