当前位置: 首页 > news >正文

MyBatis:让 SQL 与代码和谐共处的持久层框架

目录

开篇:从 "复制粘贴工程师" 到 "SQL 架构师"

一、MyBatis 核心架构:框架界的 "精密仪器"

二、MyBatis 实战指南:从配置到 CRUD

2.1 环境搭建:给框架安个家

2.2 核心配置:MyBatis 的 "家规"

2.3 核心组件实现

2.4 执行流程:让 MyBatis 跑起来

2.5 动态 SQL:MyBatis 的 "智能拼图"

三、常见错误及解决方案:踩坑指南

3.1 配置错误:框架的 "启动失败"

3.2 映射错误:属性与字段的 "沟通障碍"

3.3 事务问题:数据的 "来去匆匆"

3.4 缓存问题:数据的 "时空错乱"

四、MyBatis 的优缺点:框架界的 "性格分析"

优点:

缺点:

五、MyBatis 与 Spring Boot 集成:现代开发标配

结语:为什么 MyBatis 能成为持久层框架的常青树


开篇:从 "复制粘贴工程师" 到 "SQL 架构师"

曾经有个程序员,每天的工作就是复制粘贴 JDBC 代码:加载驱动、获取连接、创建 Statement、处理 ResultSet... 直到有一天,他发现自己写的重复代码能绕地球三圈。当他濒临崩溃时,前辈扔给他一个 MyBatis 教程,从此他的世界清净了 —— 这不是神话,而是无数 Java 开发者的真实经历。

MyBatis 就像持久层开发的 "翻译官",让 Java 对象和数据库表能顺畅沟通,同时又不剥夺开发者对 SQL 的控制权。今天我们就来系统学习这个框架,保证专业术语一个不少,段子也管够。

一、MyBatis 核心架构:框架界的 "精密仪器"

MyBatis 的架构设计堪称教科书级,每个组件都有明确职责,如同精密手表的齿轮般协同工作:

  • SqlSessionFactory:会话工厂,基于配置文件构建,整个应用生命周期中只需要一个实例。你可以把它理解为数据库连接的 "总调度中心",负责生产 SqlSession。

  • SqlSession:数据库会话对象,相当于 JDBC 中的 Connection,但功能更强大。它是线程不安全的,就像一次性手套,用完就得扔(关闭)。

  • Executor:执行器,MyBatis 的 "心脏",负责 SQL 语句的执行和缓存管理。默认提供三种实现:SimpleExecutor(简单执行器)、ReuseExecutor(重用预处理语句)、BatchExecutor(批量执行器)。

  • StatementHandler:语句处理器,负责与 JDBC 的 Statement 交互,设置参数、执行 SQL、处理结果集。

  • ParameterHandler:参数处理器,将 Java 参数转换为 SQL 语句中的参数,就像给 SQL"填空" 的工具。

  • ResultSetHandler:结果集处理器,将 JDBC 的 ResultSet 转换为 Java 对象,完成 ORM 的核心映射工作。

  • Mapper 接口:数据访问接口,定义 CRUD 方法,无需实现类 —— 这大概是所有程序员梦寐以求的 "只说不做" 模式。

  • Mapper 映射器:将 Mapper 接口方法与 SQL 语句关联的组件,可通过 XML 或注解实现。

这些组件的协作流程就像医院看病:SqlSessionFactory 是挂号处,SqlSession 是导诊护士,Executor 是主治医生,StatementHandler 是检查仪器,ParameterHandler 是病历填写员,ResultSetHandler 是化验结果解读员,Mapper 接口则是就诊科室。

二、MyBatis 实战指南:从配置到 CRUD

2.1 环境搭建:给框架安个家

Maven 依赖配置

xml

<dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.10</version>
</dependency>
<dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.30</version>
</dependency>

就像盖房子要先打地基,使用 MyBatis 第一步就是把必要的依赖加进来。

2.2 核心配置:MyBatis 的 "家规"

全局配置文件 (mybatis-config.xml)

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><!-- 引入外部属性文件,实现配置解耦 --><properties resource="db.properties"/><!-- 全局设置,MyBatis的"总开关" --><settings><setting name="mapUnderscoreToCamelCase" value="true"/> <!-- 下划线转驼峰命名 --><setting name="cacheEnabled" value="true"/> <!-- 开启二级缓存 --><setting name="lazyLoadingEnabled" value="true"/> <!-- 开启延迟加载 --><setting name="aggressiveLazyLoading" value="false"/> <!-- 关闭积极加载 --></settings><!-- 类型别名,简化类名书写 --><typeAliases><package name="com.example.entity"/> <!-- 批量扫描,别名为类名小写 --></typeAliases><!-- 类型处理器,处理Java类型与JDBC类型映射 --><typeHandlers><package name="com.example.handler"/></typeHandlers><!-- 数据库环境配置 --><environments default="development"><environment id="development"><transactionManager type="JDBC"/> <!-- JDBC事务管理 --><dataSource type="POOLED"> <!-- 池化数据源 --><property name="driver" value="${jdbc.driver}"/><property name="url" value="${jdbc.url}"/><property name="username" value="${jdbc.username}"/><property name="password" value="${jdbc.password}"/></dataSource></environment></environments><!-- 注册映射器 --><mappers><package name="com.example.mapper"/></mappers>
</configuration>

这个配置文件就像 MyBatis 的 "使用说明书",告诉框架如何连接数据库、如何处理映射关系。

2.3 核心组件实现

1. 实体类 (User.java)

public class User {private Integer id;private String userName;private Integer age;private LocalDateTime createTime;// 构造方法、getter、setter、toString
}

实体类是 Java 世界与数据库世界的 "翻译官",每个属性对应数据库表的一个字段。

2. Mapper 接口 (UserMapper.java)

public interface UserMapper {/*** 根据ID查询用户* @param id 用户ID* @return 用户对象*/User selectById(Integer id);/*** 查询所有用户* @return 用户列表*/List<User> selectAll();/*** 新增用户* @param user 用户对象* @return 影响行数*/int insert(User user);/*** 更新用户* @param user 用户对象* @return 影响行数*/int update(User user);/*** 删除用户* @param id 用户ID* @return 影响行数*/int delete(Integer id);
}

Mapper 接口定义了数据访问的 "契约",明确了可以对数据库做哪些操作。

3. Mapper 映射文件 (UserMapper.xml)

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.mapper.UserMapper"><!-- 结果映射,处理复杂映射关系 --><resultMap id="UserResultMap" type="User"><id column="id" property="id"/><result column="user_name" property="userName"/><result column="age" property="age"/><result column="create_time" property="createTime"/></resultMap><select id="selectById" parameterType="int" resultMap="UserResultMap">SELECT id, user_name, age, create_time FROM user WHERE id = #{id}</select><select id="selectAll" resultMap="UserResultMap">SELECT id, user_name, age, create_time FROM user</select><insert id="insert" parameterType="User" useGeneratedKeys="true" keyProperty="id">INSERT INTO user(user_name, age, create_time)VALUES(#{userName}, #{age}, #{createTime})</insert><update id="update" parameterType="User">UPDATE userSET user_name = #{userName},age = #{age},create_time = #{createTime}WHERE id = #{id}</update><delete id="delete" parameterType="int">DELETE FROM user WHERE id = #{id}</delete>
</mapper>

映射文件是 SQL 语句的 "栖息地",通过 namespace 和 id 与 Mapper 接口方法绑定,实现了 SQL 与 Java 代码的解耦。

2.4 执行流程:让 MyBatis 跑起来

public class MyBatisExecutor {private static SqlSessionFactory sqlSessionFactory;static {try {// 1. 读取配置文件InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");// 2. 创建SqlSessionFactorysqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);} catch (IOException e) {e.printStackTrace();}}public static void main(String[] args) {// 3. 获取SqlSessiontry (SqlSession session = sqlSessionFactory.openSession()) {// 4. 获取Mapper代理对象UserMapper userMapper = session.getMapper(UserMapper.class);// 5. 执行查询操作User user = userMapper.selectById(1);System.out.println("查询结果: " + user);// 6. 执行插入操作User newUser = new User();newUser.setUserName("test");newUser.setAge(25);newUser.setCreateTime(LocalDateTime.now());int insertCount = userMapper.insert(newUser);System.out.println("插入行数: " + insertCount);// 7. 提交事务session.commit();}}
}

这个流程就像开车:读取配置文件是检查车辆,创建 SqlSessionFactory 是启动发动机,获取 SqlSession 是挂挡,获取 Mapper 是握紧方向盘,执行操作是踩油门,提交事务是到达目的地。

2.5 动态 SQL:MyBatis 的 "智能拼图"

动态 SQL 是 MyBatis 的 "杀手锏",能根据条件自动拼接 SQL 语句,避免了手动拼接的繁琐和错误:

xml

<select id="selectByCondition" parameterType="map" resultMap="UserResultMap">SELECT id, user_name, age, create_time FROM user<where><if test="userName != null and userName != ''">AND user_name LIKE CONCAT('%', #{userName}, '%')</if><if test="age != null">AND age = #{age}</if><if test="startTime != null">AND create_time >= #{startTime}</if><if test="endTime != null">AND create_time <= #{endTime}</if></where><choose><when test="orderBy != null">ORDER BY ${orderBy}</when><otherwise>ORDER BY create_time DESC</otherwise></choose>
</select>

这段代码展示了动态 SQL 的常用标签:<if>用于条件判断,<where>自动处理 AND/OR 前缀,<choose>实现分支选择。有了这些标签,再也不用写 "WHERE 1=1" 这样的蹩脚代码了。

三、常见错误及解决方案:踩坑指南

3.1 配置错误:框架的 "启动失败"

错误 1:org.apache.ibatis.binding.BindingException: Type interface com.example.mapper.UserMapper is not known to the MapperRegistry.

这就像你去餐厅吃饭,服务员说 "没这个菜单",典型的 Mapper 未注册问题。

解决方案

  • 检查 mybatis-config.xml 的<mappers>配置,确保 Mapper 被正确注册
  • 确认 Mapper 接口与 XML 文件在同一包下且名称相同
  • Spring Boot 环境下,在接口上添加@Mapper注解或在启动类添加@MapperScan

错误 2:java.io.IOException: Could not find resource mybatis-config.xml

配置文件玩 "捉迷藏",框架找不到它。

解决方案

  • 确认配置文件放在 src/main/resources 目录下
  • 检查文件名是否拼写正确(大小写敏感)
  • Maven 项目需确保资源文件被正确打包,可在 pom.xml 中添加:

xml

<build><resources><resource><directory>src/main/resources</directory><includes><include>**/*.xml</include><include>**/*.properties</include></includes></resource></resources>
</build>

3.2 映射错误:属性与字段的 "沟通障碍"

错误 3:org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'userName' in 'class java.lang.String'

参数名与映射文件中的表达式不匹配,就像你叫 "张三",别人却喊 "李四"。

解决方案

  • 单参数时使用@Param注解指定参数名:

User selectByUserName(@Param("userName") String name);

  • 将参数封装到 Map 或实体类中传递

错误 4:Column 'user_name' not found

数据库字段与 Java 属性名称不匹配,典型的 "鸡同鸭讲" 问题。

解决方案

  • 开启下划线转驼峰自动映射:

xml

<setting name="mapUnderscoreToCamelCase" value="true"/>

  • 使用<resultMap>手动配置映射关系:

xml

<resultMap id="UserResultMap" type="User"><result column="user_name" property="userName"/>
</resultMap>

3.3 事务问题:数据的 "来去匆匆"

错误 5:执行 insert 后数据库无记录,但无异常抛出

这就像你在 ATM 取了钱,卡上扣了但钱没出来 —— 典型的事务未提交问题。

解决方案

  • 手动提交事务:session.commit()
  • 打开自动提交:sqlSessionFactory.openSession(true)
  • Spring 环境下使用@Transactional注解管理事务

3.4 缓存问题:数据的 "时空错乱"

错误 6:更新数据后,查询结果仍为旧数据

一级缓存在作祟,就像你看的还是昨天的报纸。

解决方案

  • 执行增删改操作后,一级缓存会自动失效
  • 手动清除缓存:session.clearCache()
  • 对于需要实时数据的查询,可使用flushCache="true"强制刷新缓存:

xml

<select id="selectById" flushCache="true" ...>

四、MyBatis 的优缺点:框架界的 "性格分析"

优点:

  1. SQL 可控性高:允许手写 SQL,便于优化性能,适合复杂查询场景 —— 就像手动挡汽车,给你完全的驾驶控制权
  2. 灵活性强:动态 SQL 能根据条件灵活生成 SQL,应对多变的业务需求
  3. 学习成本低:相比 Hibernate,MyBatis 更简单直观,上手快
  4. 轻量级:核心 jar 包小巧,对项目侵入性低,容易集成
  5. 缓存机制:提供一级缓存和二级缓存,减少数据库访问,提高性能
  6. 支持存储过程:对存储过程有良好支持,适合复杂业务逻辑

缺点:

  1. SQL 编写工作量大:相比全自动 ORM 框架,需要手动编写大量 SQL
  2. 数据库移植性差:SQL 语句与具体数据库绑定,更换数据库时需修改 SQL
  3. 代码维护成本高:当表结构变更时,需要同步修改实体类和映射文件
  4. 缺少自动化 DDL 支持:不提供自动生成表结构的功能,需手动维护

五、MyBatis 与 Spring Boot 集成:现代开发标配

在实际开发中,MyBatis 常与 Spring Boot 结合使用,大幅简化配置:

1. 添加依赖

xml

<dependency><groupId>org.mybatis.spring.boot</groupId><artifactId>mybatis-spring-boot-starter</artifactId><version>2.3.0</version>
</dependency>
<dependency><groupId>com.mysql</groupId><artifactId>mysql-connector-j</artifactId>
</dependency>

2. 配置 application.yml

yaml

spring:datasource:driver-class-name: com.mysql.cj.jdbc.Driverurl: jdbc:mysql://localhost:3306/testusername: rootpassword: rootmybatis:mapper-locations: classpath:mappers/*.xmltype-aliases-package: com.example.entityconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印SQL日志

3. 使用 Mapper

@Service
public class UserService {@Autowiredprivate UserMapper userMapper;public User getUserById(Integer id) {return userMapper.selectById(id);}
}

这种集成方式就像给 MyBatis 装上了 "自动驾驶系统",让开发效率飙升。

结语:为什么 MyBatis 能成为持久层框架的常青树

MyBatis 的成功并非偶然,它在 "全自动 ORM" 和 "原生 JDBC" 之间找到了完美平衡点 —— 既消除了 JDBC 的冗余代码,又保留了开发者对 SQL 的控制权。这种 "半自动" 的特性,让它在需要精细优化 SQL 的场景中大放异彩。

随着 MyBatis-Plus 等增强工具的出现,MyBatis 的开发效率短板也得到了弥补。它就像一把锋利的瑞士军刀,既可以应对简单的日常任务,也能处理复杂的专业场景。

对于 Java 开发者而言,掌握 MyBatis 不仅是一项基本技能,更是理解 ORM 思想和数据库优化的重要途径。毕竟,能优雅地操作数据库,是每个后端开发者的必备素养。


文章转载自:

http://gllzX1JO.nrqnj.cn
http://K0UY81rm.nrqnj.cn
http://CgoAbytu.nrqnj.cn
http://884XEKRo.nrqnj.cn
http://ioVXFmEW.nrqnj.cn
http://i9vc62O1.nrqnj.cn
http://jUlAtrMW.nrqnj.cn
http://BoKloV9p.nrqnj.cn
http://aRBQ67x1.nrqnj.cn
http://7tb60iLO.nrqnj.cn
http://xLCuowaD.nrqnj.cn
http://okHwJxO2.nrqnj.cn
http://jRkasE3K.nrqnj.cn
http://14l89DH9.nrqnj.cn
http://AJpfAo7k.nrqnj.cn
http://UJId5Upf.nrqnj.cn
http://swglR6tN.nrqnj.cn
http://CghsRMXq.nrqnj.cn
http://pjC4Lg1Y.nrqnj.cn
http://SOe2djmg.nrqnj.cn
http://0lXBUXDg.nrqnj.cn
http://PjH65SLF.nrqnj.cn
http://2AEbP2c5.nrqnj.cn
http://MP1AMGkh.nrqnj.cn
http://UMdpYLlX.nrqnj.cn
http://oiIK2x3v.nrqnj.cn
http://1S9EvMhB.nrqnj.cn
http://dWKSk6Ch.nrqnj.cn
http://HSGv1t5b.nrqnj.cn
http://Cdfdcv24.nrqnj.cn
http://www.dtcms.com/a/362697.html

相关文章:

  • React学习教程,从入门到精通, React 入门指南:React JSX 语法知识点详解及案例代码(8)
  • React 学习笔记4 Diffing/脚手架
  • go命令行工具:如何在现有的工程里加入使用cobra
  • 01 - 网页和web标准
  • AI文档产品与传统OCR软件的根本区别是什么?
  • Java集合源码解析之LinkedList
  • HTTPS如何保证数据传输过程中的安全性?
  • mapbox高阶,结合threejs(threebox)添加管道,实现管道流动效果
  • 红楼梦 HTML 分析 - 娇杏为何侥幸
  • ES6和CommonJS模块区别
  • Linux系统强大的命令行工具之fuser
  • 江协科技-1-1软件开发与2-1新建工程
  • C语言精选100道编程题(附有图解和源码)
  • 控制系统仿真之PID参数整定的Z-N法(弯曲切线法)(十)
  • K6 html压力测试报告中参数详解以及常见问题解析
  • 算法题打卡力扣第3题:无重复字符的最长子串(mid)
  • 在线拍卖|基于Springboot+vue的在线拍卖管理系统(源码+数据库+文档)
  • F5发布后量子API安全解决方案,以AI驱动全面防护应对量子计算威胁
  • 面阵 vs 线阵相机:怎么选不踩坑?选型公式直接套用
  • HTML第二课:块级元素
  • 【实时Linux实战系列】采用实时Linux构建无人机控制系统
  • Vue基础知识-Vue中v-cloak、v-text、v-html、v-once、v-pre指令详解
  • 【Doris入门】Doris数据表模型:聚合模型(Aggregate Key Model)详解
  • 数论常见公式定理大全
  • C++学习——继承
  • 无线通信网络是互联网边缘的重要组成,同时也是局域联网的主要方式
  • RT-Thread SMP相关问题分析
  • 01-html css
  • 【论文阅读】Jet-Nemotron: 高效语言模型与后神经网络架构搜索
  • 11.《简单的路由重分布基础知识探秘》