MyBatis深度解析:XML/注解配置与动态SQL编写实战
引言
在现代Java企业级应用开发中,MyBatis作为一款优秀的持久层框架,因其灵活性和易用性广受开发者喜爱。相比Hibernate等全自动ORM框架,MyBatis提供了更接近SQL的开发体验,同时又不失面向对象的优雅。本文将深入探讨MyBatis的核心配置方式(XML与注解)以及强大的动态SQL功能,帮助开发者掌握MyBatis的精髓。
一、MyBatis配置方式详解
1. XML配置方式
XML配置是MyBatis最传统也是最强大的配置方式,提供了完整的配置能力和清晰的层次结构。
1.1 全局配置文件(mybatis-config.xml)
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration><!-- 环境配置 --><environments default="development"><environment id="development"><transactionManager type="JDBC"/><dataSource type="POOLED"><property name="driver" value="com.mysql.jdbc.Driver"/><property name="url" value="jdbc:mysql://localhost:3306/mybatis_db"/><property name="username" value="root"/><property name="password" value="123456"/></dataSource></environment></environments><!-- 映射文件配置 --><mappers><mapper resource="mapper/UserMapper.xml"/></mappers>
</configuration>
1.2 Mapper XML文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapperPUBLIC "-//mybatis.org//DTD Mapper 3.0//EN""http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.example.dao.UserMapper"><!-- 结果映射 --><resultMap id="userResultMap" type="User"><id property="id" column="user_id"/><result property="username" column="user_name"/><result property="email" column="user_email"/></resultMap><!-- 查询语句 --><select id="selectUserById" resultMap="userResultMap">SELECT * FROM users WHERE user_id = #{id}</select><!-- 插入语句 --><insert id="insertUser" useGeneratedKeys="true" keyProperty="id">INSERT INTO users(user_name, user_email) VALUES(#{username}, #{email})</insert>
</mapper>
XML配置的优势:
-
集中管理SQL,便于维护
-
支持复杂的SQL和结果映射
-
提供完整的DTD验证,减少错误
-
支持动态SQL(后文详细介绍)
2. 注解配置方式
MyBatis 3.x开始提供了基于注解的配置方式,适合简单的CRUD操作。
2.1 常用注解
public interface UserMapper {@Select("SELECT * FROM users WHERE user_id = #{id}")@Results(id = "userResult", value = {@Result(property = "id", column = "user_id", id = true),@Result(property = "username", column = "user_name"),@Result(property = "email", column = "user_email")})User selectUserById(Long id);@Insert("INSERT INTO users(user_name, user_email) VALUES(#{username}, #{email})")@Options(useGeneratedKeys = true, keyProperty = "id")int insertUser(User user);@Update("UPDATE users SET user_name=#{username}, user_email=#{email} WHERE user_id=#{id}")int updateUser(User user);@Delete("DELETE FROM users WHERE user_id=#{id}")int deleteUser(Long id);
}
注解配置的优势:
-
代码与SQL在一起,直观明了
-
减少XML文件数量,简化项目结构
-
适合简单的SQL操作
注解与XML的选择建议:
-
简单CRUD:使用注解
-
复杂SQL、动态SQL:使用XML
-
大型项目:推荐以XML为主,注解为辅
二、动态SQL编写技巧
MyBatis最强大的特性之一就是动态SQL,它允许我们根据不同条件构建不同的SQL语句。
1. if元素
<select id="findUsers" resultType="User">SELECT * FROM usersWHERE 1=1<if test="username != null">AND user_name LIKE #{username}</if><if test="email != null">AND user_email = #{email}</if>
</select>
2. choose/when/otherwise元素
<select id="findActiveUsers" resultType="User">SELECT * FROM usersWHERE status = 'ACTIVE'<choose><when test="searchBy == 'name'">AND user_name LIKE #{keyword}</when><when test="searchBy == 'email'">AND user_email LIKE #{keyword}</when><otherwise>AND (user_name LIKE #{keyword} OR user_email LIKE #{keyword})</otherwise></choose>
</select>
3. where元素
where
元素会智能处理WHERE子句,避免出现WHERE AND
这样的语法错误。
<select id="findUsers" resultType="User">SELECT * FROM users<where><if test="username != null">user_name LIKE #{username}</if><if test="email != null">AND user_email = #{email}</if></where>
</select>
4. set元素
set
元素用于UPDATE语句,智能处理逗号问题。
<update id="updateUser">UPDATE users<set><if test="username != null">user_name=#{username},</if><if test="email != null">user_email=#{email},</if></set>WHERE user_id=#{id}
</update>
5. foreach元素
处理集合遍历,常用于IN条件。
<select id="findUsersByIds" resultType="User">SELECT * FROM usersWHERE user_id IN<foreach item="id" collection="ids" open="(" separator="," close=")">#{id}</foreach>
</select>
6. bind元素
创建变量并绑定到上下文,可用于模糊查询等场景。
<select id="searchUsers" resultType="User"><bind name="pattern" value="'%' + keyword + '%'" />SELECT * FROM usersWHERE user_name LIKE #{pattern}OR user_email LIKE #{pattern}
</select>
7. 动态SQL的最佳实践
-
避免过度复杂:动态SQL虽然强大,但过度使用会使SQL难以维护
-
性能考虑:复杂的动态SQL可能影响执行计划,需关注性能
-
测试覆盖:确保测试所有可能的条件分支
-
注释说明:为复杂的动态SQL添加注释
三、高级技巧与性能优化
1. 结果映射的高级用法
<resultMap id="detailedUserResultMap" type="User"><constructor><idArg column="user_id" javaType="long"/><arg column="user_name" javaType="String"/></constructor><result property="email" column="user_email"/><association property="department" javaType="Department"><id property="id" column="dept_id"/><result property="name" column="dept_name"/></association><collection property="roles" ofType="Role"><id property="id" column="role_id"/><result property="name" column="role_name"/></collection>
</resultMap>
2. 缓存配置
<cacheeviction="FIFO"flushInterval="60000"size="512"readOnly="true"/>
3. 批量操作优化
// 使用BatchExecutor
SqlSession sqlSession = sqlSessionFactory.openSession(ExecutorType.BATCH);
try {UserMapper mapper = sqlSession.getMapper(UserMapper.class);for (User user : users) {mapper.insertUser(user);}sqlSession.commit();
} finally {sqlSession.close();
}
四、常见问题与解决方案
1. 参数映射问题
-
问题:参数名不匹配
-
解决:使用
@Param
注解明确指定参数名
2. N+1查询问题
-
问题:关联查询导致多次查询
-
解决:使用
<association>
和<collection>
的fetchType或全局配置
3. 动态SQL中的空格问题
-
问题:动态拼接SQL可能导致多余空格
-
解决:使用
trim
元素或确保SQL片段正确
结语
MyBatis作为一款"半自动化"的ORM框架,在灵活性和易用性之间取得了很好的平衡。通过本文的介绍,相信您已经掌握了MyBatis的核心配置方式和动态SQL编写技巧。在实际项目中,建议根据具体场景选择合适的配置方式,并合理运用动态SQL来构建高效、可维护的数据访问层。
最佳实践建议:
-
大型项目以XML配置为主,简单CRUD可使用注解
-
动态SQL保持简洁,避免过度复杂
-
合理使用缓存提升性能
-
编写单元测试覆盖各种SQL分支
希望本文能帮助您更好地使用MyBatis,如果有任何问题欢迎在评论区留言讨论!
相关文章:
MyBatis深度解析:XML/注解配置与动态SQL编写实战
引言 在现代Java企业级应用开发中,MyBatis作为一款优秀的持久层框架,因其灵活性和易用性广受开发者喜爱。相比Hibernate等全自动ORM框架,MyBatis提供了更接近SQL的开发体验,同时又不失面向对象的优雅。本文将深入探讨MyBatis的核…...
面试经验 对常用 LLM 工具链(如 LlamaFactory)的熟悉程度和实践经验
面试场景: 你正在面试一个大型语言模型(LLM)工程师或研究员的职位,面试官想了解你对常用 LLM 工具链(如 LlamaFactory)的熟悉程度和实践经验。 面试经验分享:LlamaFactory-CLI 工具实践 面试官…...

【conda配置深度学习环境】
好的!我们从头开始配置一个基于Conda的虚拟环境,覆盖深度学习(如PyTorch)和传统机器学习(如XGBoost),并适配你的显卡(假设为NVIDIA,若为AMD请告知)。以下是完…...

力扣4.寻找两个正序数组的中位数
文章目录 题目介绍题解 题目介绍 题解 题解链接:题解 核心思路:通过二分查找的确定分割点使左右两部分元素数量相等。 class Solution {public double findMedianSortedArrays(int[] nums1, int[] nums2) {int n1 nums1.length;int n2 nums2.length…...

【相机基础知识与物体检测】更新中
参考: 黑马机器人 | 相机标定&物体检测https://robot.czxy.com/docs/camera/ 01-相机基础 相机基础概述 相机是机器视觉的基础,相机直接产生了相机数据。所有视觉算法都是作用在相机数据上的。相机数据的好坏,或者对相机数据的理解方式…...

【前端】性能优化和分类
本页知识点参考:https://zhuanlan.zhihu.com/p/514222781 1. 加载性能优化 1.1 网站性能优化 content方法: 1)减少HTTP请求:合并文件,CSS精灵,inline Image 2)减少DNS查询:DNS缓存&…...

PPO和GRPO算法
verl 是现在非常火的 rl 框架,而且已经支持了多个 rl 算法(ppo、grpo 等等)。 过去对 rl 的理解很粗浅(只知道有好多个角色,有的更新权重,有的不更新),也曾硬着头皮看了一些论文和知…...
ceph 对象存储用户限额满导致无法上传文件
查看日志 kl logs -f rook-ceph-rgw-my-store-a-5cc4c4d5b5-26n6j|grep -i error|head -1Defaulted container "rgw" out of: rgw, log-collector, chown-container-data-dir (init) debug 2025-05-30T19:44:11.573+0000 7fa7b7a6d700...

rk3588 上运行smolvlm-realtime-webcam,将视频转为文字描述
smolvlm-realtime-webcam 是一个开源项目,结合了轻量级多模态模型 SmolVLM 和本地推理引擎 llama.cpp,能够在本地实时处理摄像头视频流,生成自然语言描述, 开源项目地址 https://github.com/ngxson/smolvlm-realtime-webcamhttps…...
某航参数逆向及设备指纹分析
文章目录 1. 写在前面2. 接口分析3. 加密分析4. 算法还原5. 设备指纹风控分析与绕过【🏠作者主页】:吴秋霖 【💼作者介绍】:擅长爬虫与JS加密逆向分析!Python领域优质创作者、CSDN博客专家、阿里云博客专家、华为云享专家。一路走来长期坚守并致力于Python与爬虫领域研究…...
SQL思路解析:窗口滑动的应用
目录 🎯 问题目标 第一步:从数据中我们能直接得到什么? 第二步:我们想要的“7天窗口”长什么样? 第三步:SQL 怎么表达“某一天的前六天”? 🔍JOIN 比窗口函数更灵活 第四步&am…...

Rust 学习笔记:Box<T>
Rust 学习笔记:Box Rust 学习笔记:Box<T\>Box\<T> 简介使用 Box\<T\> 在堆上存储数据启用带有 box 的递归类型关于 cons 列表的介绍计算非递归类型的大小使用 Box\<T\> 获取大小已知的递归类型 Rust 学习笔记:Box<…...
C# 从 ConcurrentDictionary 中取出并移除第一个元素
C# 从 ConcurrentDictionary 中取出并移除第一个元素 要从 ConcurrentDictionary<byte, int> 中取出并移除第一个元素,需要结合 遍历 和 原子移除操作。由于 ConcurrentDictionary 是无序集合,"第一个元素" 通常是指最早添加的元素&…...

操作系统学习(十三)——Linux
一、Linux Linux 是一种类 Unix 的自由开源操作系统内核,由芬兰人 Linus Torvalds 于 1991 年首次发布。如今它广泛应用于服务器、桌面、嵌入式设备、移动设备(如 Android)等领域。 设计思想: 原则描述模块化与可移植性Linux 内…...

NLP学习路线图(二十二): 循环神经网络(RNN)
在自然语言处理(NLP)的广阔天地中,序列数据是绝对的核心——无论是流淌的文本、连续的语音还是跳跃的时间序列,都蕴含着前后紧密关联的信息。传统神经网络如同面对一幅打散的拼图,无法理解词语间的顺序关系,…...

每日一C(1)C语言的内存分布
目录 代码区 常量区 全局/静态区 初始化数据段(.data) 未初始化数据段(.bss) 堆区 栈区 总结 今天我们学习的是C语言的内存分布,以及这些分区所存储的内容和其特点。今天的思维导图如下。 C语言作为一款直接处…...

Photoshop使用钢笔绘制图形
1、绘制脸部路径 选择钢笔工具,再选择“路径”。 基于两个点绘制一个弯曲的曲线 使用Alt键移动单个点,该点决定了后续的曲线方向 继续绘制第3个点 最后一个点首尾是同一个点,使用钢笔保证是闭合回路。 以同样的方式绘制2个眼睛外框。 使用椭…...

应用层协议:HTTP
目录 HTTP:超文本传输协议 1.1 HTTP报文 1.1.1 请求报文 1.1.2 响应报文 1.2 HTTP请求过程和原理 1.2.1 请求过程 1、域名(DNS)解析 2、建立TCP连接(三次握手) 3、发送HTTP请求 4、服务器处理请求 5、返回H…...

复习——C++
1、scanf和scanf_s区别 2、取地址,输出 char ba; char* p&b; cout<<*p; cout<<p; p(char*)"abc"; cout<<*p; cout<<p; cout<<(void*)p; 取地址,把b的地址给p 输出*p,是输出p的空间内的值…...

SPI通信协议(软件SPI读取W25Q64)
SPI通信协议 文章目录 SPI通信协议1.SPI通信2.SPI硬件和软件规定2.1SPI硬件电路2.2移位示意图2.3SPI基本时序单元2.3.1起始和终止条件2.3.2交换一个字节(模式1) 2.4SPI波形分析(辅助理解)2.4.1发送指令2.4.2指定地址写2.4.3指定地…...
PostgreSQL-基于PgSQL17和11版本导出所有的超表建表语句
最新版本更新 https://code.jiangjiesheng.cn/article/368?fromcsdn 推荐 《高并发 & 微服务 & 性能调优实战案例100讲 源码下载》 1. 基于pgsql 17.4 研究 查询psql版本:SELECT version(); 查看已知1条建表语句和db中数据关系 SELECT create_hypert…...

JavaWeb:前后端分离开发-部门管理
今日内容 前后端分离开发 准备工作 页面布局 整体布局-头部布局 Container 布局容器 左侧布局 资料\04. 基础文件\layout/index.vue <script setup lang"ts"></script><template><div class"common-layout"><el-containe…...
ArcGIS计算多个栅格数据的平均栅格
3种方法计算多个栅格数据的平均栅格 1->使用“ 栅格计算器”工具 原理就是把多幅影像数据相加,然后除以个数,就能得到平均栅格。 2-> 使用“像元统计数据”工具,如果是ArcGIS pro,则是“像元统计”工具。使用这个工具可以…...

字节开源FlowGram:AI时代可视化工作流新利器
字节终于开源“扣子”同款引擎了!FlowGram:AI 时代的可视化工作流利器 字节FlowGram创新性地融合图神经网络与多模态交互技术,构建了支持动态拓扑重构的可视化流程引擎。该系统通过引入 f ( G ) ( V ′ , E ′ ) f(\mathcal{G})…...
如何选择合适的分库分表策略
选择合适的分库分表策略需要综合考虑业务特点、数据规模、访问模式、技术成本等多方面因素。以下是系统性的选择思路和关键决策点: 一、核心决策因素 业务需求分析 数据规模:当前数据量(如亿级)、增长速度(如每日新增百…...

(LeetCode 每日一题)3403. 从盒子中找出字典序最大的字符串 I (贪心+枚举)
题目:3403. 从盒子中找出字典序最大的字符串 I 题目:贪心枚举字符串,时间复杂度0(n)。 最优解的长度一定是在[1,n-numFriends]之间。 字符串在前缀都相同的情况下,长度越长越大。 C版本: class Solution { public:st…...

GPIO的内部结构与功能解析
一、GPIO总体结构 总体构成 1.APB2(外设总线) APB2总线是微控制器内部连接CPU与外设(如GPIO)的总线,负责CPU对GPIO寄存器的读写访问,支持低速外设通信 2.寄存器 控制GPIO的配置(输入/输出模式、上拉/下拉等&#x…...
Python训练打卡Day42
Grad-CAM与Hook函数 知识点回顾 回调函数lambda函数hook函数的模块钩子和张量钩子Grad-CAM的示例 在深度学习中,我们经常需要查看或修改模型中间层的输出或梯度。然而,标准的前向传播和反向传播过程通常是一个黑盒,我们很难直接访问中间层的信…...
深度学习中的负采样
深度学习中的负采样 负采样(Negative Sampling) 是一种在训练大型分类或概率模型(尤其是在输出类别很多时)中,用来加速训练、降低计算量的方法。 它常用于: 词向量训练(如 Word2Vecÿ…...

php7+mysql5.6单用户中医处方管理系统V1.0
php7mysql5.6中医处方管理系统说明文档 一、系统简介 ----------- 本系统是一款专为中医诊所设计的处方管理系统,基于PHPMySQL开发,不依赖第三方框架,采用原生HTML5CSS3AJAX技术,适配手机和电脑访问。 系统支持药品管理、处方开…...