MyBatis学习笔记:进阶知识2

news2024/12/15 14:34:33

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. 注意事项
    • 生成的代码可能需要根据实际需求进行适当调整,如添加自定义的方法、修改注释等。
    • 当数据库表结构发生变化时,需要及时重新生成代码,以确保代码与数据库的一致性。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2259976.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringCloud微服务实战系列:01让SpringCloud项目在你机器上运行起来

目录 项目选型 项目安装-本地运行起来 软件安装&#xff1a; 项目启动&#xff1a; 总结&答疑 项目选型 软件开发&#xff0c;基本上都不会从0开始&#xff0c;一般都是在其他项目或者组件的基础上进行整合优化迭代&#xff0c;站在巨人肩膀上才能看得更远&#xff0c…

Python鼠标轨迹算法(游戏防检测)

一.简介 鼠标轨迹算法是一种模拟人类鼠标操作的程序&#xff0c;它能够模拟出自然而真实的鼠标移动路径。 鼠标轨迹算法的底层实现采用C/C语言&#xff0c;原因在于C/C提供了高性能的执行能力和直接访问操作系统底层资源的能力。 鼠标轨迹算法具有以下优势&#xff1a; 模拟…

npm error Error: Command failed: F:\360Downloads\Software\nodejs\node.exe

前言&#xff1a; 电脑环境&#xff1a;win7 node版本&#xff1a;18.20.0 npm版本&#xff1a;10.9.2 情景再现&#xff1a;电脑上是存在的vuevite的项目且可以正常运行。想着摸鱼的时间复习一下ts语法&#xff0c;所以想创建一个demo。按照 开始 | Vite 官方中文文档 官网创建…

软件工程 设计的复杂性

复杂性代表事件或事物的状态&#xff0c;它们具有多个相互关联的链接和高度复杂的结构。在软件编程中&#xff0c;随着软件设计的实现&#xff0c;元素的数量以及它们之间的相互联系逐渐变得庞大&#xff0c;一下子变得难以理解。 如果不使用复杂性指标和度量&#xff0c;软件…

大屏开源项目go-view二次开发3----象形柱图控件(C#)

环境搭建参考&#xff1a; 大屏开源项目go-view二次开发1----环境搭建(C#)-CSDN博客 要做的象形柱图控件最终效果如下图&#xff1a; 其实这个控件我前面的文章也介绍过&#xff0c;不过是用wpf做的&#xff0c;链接如下&#xff1a; wpf利用Microsoft.Web.WebView2显示html…

ORB-SLAM3源码学习:G2oTypes.cc: void EdgeInertial::computeError 计算预积分残差

前言 这部分函数涉及了g2o的内容以及IMU相关的推导内容&#xff0c;需要你先去进行这部分的学习。 1.函数声明 void EdgeInertial::computeError() 2.函数定义 涉及到的IMU的公式&#xff1a; {// TODO Maybe Reintegrate inertial measurments when difference between …

Kafka - 消息乱序问题的常见解决方案和实现

文章目录 概述一、MQ消息乱序问题分析1.1 相同topic内的消息乱序1.2 不同topic的消息乱序 二、解决方案方案一&#xff1a; 顺序消息Kafka1. Kafka 顺序消息的实现1.1 生产者&#xff1a;确保同一业务主键的消息发送到同一个分区1.2 消费者&#xff1a;顺序消费消息 2. Kafka 顺…

[MoeCTF 2021]unserialize

[广东强网杯 2021 团队组]欢迎参加强网杯 这题简单&#xff0c;flag直接写在脸上 NSSCTF {Wec10m3_to_QwbCtF} [MoeCTF 2021]unserialize <?phpclass entrance {public $start;function __construct($start){// 构造函数初始化 $start 属性$this->start $start;}fun…

舌头分割数据集labelme格式2557张1类别

数据集格式&#xff1a;labelme格式(不包含mask文件&#xff0c;仅仅包含jpg图片和对应的json文件) 图片数量(jpg文件个数)&#xff1a;2557 标注数量(json文件个数)&#xff1a;2557 标注类别数&#xff1a;1 标注类别名称:["tongue"] 每个类别标注的框数&#xff1…

回归预测 | Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习回归预测

目录 效果一览基本介绍模型设计程序设计参考资料效果一览 基本介绍 回归预测 | Matlab实现基于BiLSTM-Adaboost双向长短期记忆神经网络结合Adaboost集成学习回归预测 模型设计 基于BiLSTM-Adaboost的回归预测模型结合了双向长短期记忆神经网络(BiLSTM)和Adaboost集成学习的…

Unity学习笔记(二)如何制作角色动画

前言 本文为Udemy课程The Ultimate Guide to Creating an RPG Game in Unity学习笔记 创建一个角色 我们的目的是创建一个可移动、跳跃、冲刺等动作的角色 需要的组件&#xff1a;Rigidbody&#xff08;用于创建物理规则&#xff09;、Collider&#xff08;用于检测碰撞&am…

嵌入式入门Day30

IO Day5 线程相关函数pthread_createpthread_selfpthread_exitpthread_join\pthread_detachpthread_cancelpthread_setcancelstatepthread_setcanceltype 作业 线程 线程是轻量化的进程&#xff0c;一个进程内可以有多个线程&#xff0c;至少包含一个线程&#xff08;主线程&a…

【Ubuntu】双硬盘安装双系统 Windows 和 Ubuntu

【Ubuntu】双硬盘安装双系统 Windows 和 Ubuntu 1 安装顺序2 Ubutnu 20.042.1 准备工作2.2 自定义分区2.3 遇到的一些问题 1 安装顺序 我选择先在一块 SSD 上安装 Windows 再在另一块 SSD 上安装 Ubuntu&#xff0c;建议先安装 Windows 2 Ubutnu 20.04 2.1 准备工作 制作启…

【Qt】QWidget中的常见属性及其功能(一)

目录 一、 enabled 例子&#xff1a; 二、geometry 例子&#xff1a; window fram 例子 &#xff1a; 四、windowTiltle 五、windowIcon 例子&#xff1a; qrc机制 创建qrc文件 例子&#xff1a; qt中的很多内置类都是继承自QWidget的&#xff0c;因此熟悉QWidget的…

iOS swift开发系列 -- tabbar问题总结

1.单视图如何改为tabbar&#xff0c;以便显示2个标签页 右上角➕&#xff0c;输入tabbar 找到控件&#xff0c;然后选中&#xff0c;把entrypoint移动到tabbar控件 2.改成tabbar&#xff0c;生成两个item&#xff0c;配置各自视图后&#xff0c;启动发现报错 Thread 1: “-[p…

Muduo网络库解析--网络模块(2)

前文 重写Muduo库实现核心模块的Git仓库 注&#xff1a;本文将重点剖析 Muduo 网络库的核心框架&#xff0c;深入探讨作者精妙的代码设计思路&#xff0c;并针对核心代码部分进行重写&#xff0c;将原本依赖 boost 的实现替换为原生的 C11 语法。需要说明的是&#xff0c;本文…

电脑怎么设置通电自动开机(工控机)

操作系统&#xff1a;win10 第一步&#xff0c;电脑开机时按del键进入bios页面。 第二步&#xff0c;选择advanced下的IT8712 Super IO Configuration 第三步&#xff0c;找到Auto Power On&#xff0c;将其从Power off设置为Power On 第四步&#xff0c;F10保存&#xff0c;大…

如何对小型固定翼无人机进行最优的路径跟随控制?

控制架构 文章继续采用的是 ULTRA-Extra无人机&#xff0c;相关参数如下&#xff1a; 这里用于guidance law的无人机运动学模型为&#xff1a; { x ˙ p V a cos ⁡ γ cos ⁡ χ V w cos ⁡ γ w cos ⁡ χ w y ˙ p V a cos ⁡ γ sin ⁡ χ V w cos ⁡ γ w sin ⁡ χ…

基于Redis实现令牌桶算法

基于Redis实现令牌桶算法 令牌桶算法算法流程图优点缺点 实现其它限流算法 令牌桶算法 令牌桶是一种用于分组交换和电信网络的算法。它可用于检查数据包形式的数据传输是否符合定义的带宽和突发性限制&#xff08;流量不均匀或变化的衡量标准&#xff09;。它还可以用作调度算…

学习threejs,局部纹理刷新,实现图片分块加载

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️Texture 贴图 二、&#x1…