MyBatis从入门到实战:简化JDBC开发的持久层框架详解
在Java后端开发中,持久层框架是连接应用程序与数据库的关键桥梁。JDBC作为Java操作数据库的基础,虽功能强大但配置繁琐、代码冗余,而MyBatis的出现彻底解决了这一痛点。本文将从MyBatis的核心概念出发,结合SpringBoot实战,带大家快速掌握MyBatis的使用技巧,轻松替代传统JDBC开发。
一、MyBatis简介:一款"懂SQL"的持久层框架
1. 框架背景与定位
MyBatis最初是Apache的开源项目iBatis,2010年这个项目由Apache迁移到Google Code,并且改名为MyBatis。2013年11月迁移到Github。它是一款半自动持久层框架,核心目标是简化JDBC开发,让开发者专注于SQL语句本身,而非连接管理、结果集处理等重复工作。
📌 官方说明:MyBatis是"一个优秀的持久层框架,它支持定制化SQL、存储过程以及高级映射。MyBatis避免了几乎所有的JDBC代码和手动设置参数以及获取结果集。"(摘自MyBatis官网)
2. 核心优势
- 简化开发:无需硬编码SQL、参数和结果集映射,支持注解和XML两种配置方式
- 自动管理连接:集成数据库连接池,自动管理数据库连接(获取/释放)
- 灵活SQL:支持动态SQL、存储过程调用
- 轻量级:学习成本低,与SpringBoot无缝集成
3. 官方资源
官网地址:mybatis.org/mybatis-3/z…,提供完整的文档和示例,是学习的最佳参考。
二、SpringBoot+MyBatis入门:查询所有用户数据
下面通过"查询所有用户"的实战案例,带大家快速上手MyBatis的完整流程。
1. 准备工作
(1)创建SpringBoot工程并引入依赖
通过Spring Initializr创建工程,勾选以下核心依赖:
- Spring Web(可选,用于Web项目)
- MyBatis Framework(MyBatis核心依赖)
- MySQL Driver(数据库驱动)
- Lombok(简化实体类编写,推荐使用)
(2)准备数据库表与实体类
创建用户表:
create table user(
id int unsigned primary key auto_increment comment 'ID,主键',
username varchar(20) comment '用户名',
password varchar(32) comment '密码',
name varchar(10) comment '姓名',
age tinyint unsigned comment '年龄'
) comment '用户表';
-- 插入测试数据
insert into user(id, username, password, name, age) values
(1, 'daqiao', '123456', '大乔', 22),
(2, 'xiaoqiao', '123456', '小乔', 18),
(3, 'diaochan', '123456', '貂蝉', 24),
(4, 'lvbu', '123456', '吕布', 28),
(5, 'zhaoyun', '12345678', '赵云', 27);
创建实体类User(使用Lombok简化):
package com.wmh.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class User {
private Integer id;
private String username;
private String password;
private String name;
private Integer age;
}
(3)配置数据库连接与MyBatis
在application.properties中添加配置:
# 应用名称
spring.application.name=springboot-mybatis-quickstart
# 数据库连接信息
spring.datasource.url=jdbc:mysql://localhost:3306/web01?serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.username=root
spring.datasource.password=root
# MyBatis日志配置(打印SQL语句,便于调试)
mybatis.configuration.log-impl=org.apache.ibatis.logging.stdout.StdOutImpl
# 指定XML映射文件位置(若使用XML配置SQL)
mybatis.mapper-locations=classpath:mapper/*.xml
💡 注意:MySQL 8.0+ 需要指定
serverTimezone参数,否则可能连接失败。
2. 编写MyBatis核心:Mapper接口
MyBatis的持久层接口命名规范为XxxMapper,也称为Mapper接口。
创建UserMapper接口:
package com.wmh.mapper;
import com.wmh.pojo.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Select;
import java.util.List;
@Mapper // 标识该接口为MyBatis的Mapper接口
public interface UserMapper {
// 查询所有用户
@Select("select id, username, password, name, age from user")
List<User> findAll();
}
3. 单元测试验证
关键点:测试类包名必须与引导类包名相同或为子包,SpringBoot单元测试类需添加@SpringBootTest注解。
package com.wmh;
import com.wmh.mapper.UserMapper;
import com.wmh.pojo.User;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.List;
@SpringBootTest // 加载SpringBoot环境,自动注入IOC容器中的Bean
class SpringbootMybatisQuickstartApplicationTests {
@Autowired
private UserMapper userMapper;
@Test
public void testFindAll() {
List<User> userList = userMapper.findAll();
userList.forEach(System.out::println);
}
}
🛠 小技巧:运行测试方法时,控制台会打印SQL执行日志和查询结果,验证MyBatis配置是否正确。
三、JDBC VS MyBatis:为什么MyBatis更高效?
1. 传统JDBC开发痛点
- 连接管理:手动加载驱动、创建连接、关闭连接,易导致资源泄露
- SQL编写:硬编码在Java代码中,维护困难
- 参数传递:需手动设置PreparedStatement参数
- 结果处理:需手动遍历ResultSet,封装实体类
2. MyBatis解决方案
| 对比维度 | JDBC | MyBatis | 优势 |
|---|---|---|---|
| 连接管理 | 手动管理,易泄露 | 自动管理,集成连接池 | 避免资源泄露 |
| SQL编写 | 硬编码在Java中 | 注解/XML分离SQL | 易于维护 |
| 参数传递 | 手动设置 | 自动映射(#{}) | 代码简洁 |
| 结果处理 | 手动遍历ResultSet | 自动映射为实体类 | 开发效率提升 |
3. 代码对比
JDBC代码示例(繁琐) :
Class.forName("com.mysql.cj.jdbc.Driver");
Connection conn = DriverManager.getConnection(url, "root", "1234");
PreparedStatement ps = conn.prepareStatement("select * from user");
ResultSet rs = ps.executeQuery();
List<User> users = new ArrayList<>();
while (rs.next()) {
User user = new User();
user.setId(rs.getInt("id"));
user.setUsername(rs.getString("username"));
// ... 手动设置所有字段
users.add(user);
}
rs.close(); ps.close(); conn.close();
MyBatis代码示例(简洁) :
@Select("select * from user")
List<User> findAll();
// 测试调用
List<User> users = userMapper.findAll();
💡 效果:MyBatis将代码量减少80%以上,专注于业务逻辑而非数据访问细节。
四、核心知识点:数据库连接池
1. 什么是数据库连接池?
数据库连接池是管理数据库连接(Connection)的容器,核心作用是:
- 资源重用:避免频繁创建和关闭连接
- 提升响应速度:连接池提前初始化连接,请求时直接获取
- 避免泄露:自动释放空闲超时的连接
2. 核心接口与常见产品
-
标准接口:
javax.sql.DataSource(Sun官方定义) -
常见产品:
- HikariCP(SpringBoot默认连接池,性能最优)
- Druid(阿里巴巴开源,功能强大,支持监控)
- C3P0、DBCP(传统连接池,功能完善但性能略逊)
3. 切换为Druid连接池(实战)
(1)引入Druid依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-starter</artifactId>
<version>1.2.19</version>
</dependency>
(2)修改配置文件
# 指定连接池类型为Druid
spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
📌 注意:使用Druid后,可添加额外配置进行监控:
spring.datasource.druid.stat-view-servlet.enabled=true spring.datasource.druid.stat-view-servlet.url-pattern=/druid/*
五、MyBatis CRUD实战:完整操作示例
1. 删除用户(delete)
需求:根据ID删除用户
Mapper接口:
@Delete("delete from user where id = #{id}")
int deleteById(Integer id); // 返回值:影响的记录数
单元测试:
@Test
public void testDeleteById() {
int affectedRows = userMapper.deleteById(4);
System.out.println("删除成功,影响行数:" + affectedRows); // 输出1
}
💡 关键点:DML语句执行完毕的返回值,表示该语句影响的记录数。
2. 新增用户(insert)
需求:添加一个新用户
Mapper接口:
@Insert("insert into user(username, password, name, age) values(#{username}, #{password}, #{name}, #{age})")
void insert(User user);
单元测试:
@Test
public void testInsert() {
User user = new User(null, "zhouyu", "123456", "周瑜", 20);
userMapper.insert(user);
}
3. 修改用户(update)
需求:根据ID更新用户信息
Mapper接口:
@Update("update user set username = #{username}, password = #{password}, name = #{name}, age = #{age} where id = #{id}")
int update(User user);
单元测试:
@Test
public void testUpdate() {
User user = new User(1, "zhouyu", "666888", "周瑜", 20);
int affectedRows = userMapper.update(user);
System.out.println("更新成功,影响行数:" + affectedRows);
}
4. 条件查询(select)
需求:根据用户名和密码查询用户
Mapper接口:
// 方式1:使用@Param注解(推荐,兼容所有场景)
@Select("select * from user where username = #{uname} and password = #{pwd}")
User findByUsernameAndPassword(@Param("uname") String username, @Param("pwd") String password);
// 方式2:SpringBoot官方骨架下可省略@Param(保留方法形参名)
@Select("select * from user where username = #{username} and password = #{password}")
User findByUsernameAndPassword(String username, String password);
单元测试:
@Test
public void testFindByUsernameAndPassword() {
User user = userMapper.findByUsernameAndPassword("zhouyu", "666888");
System.out.println("查询结果:" + user);
}
💡 @Param注解作用:为接口方法形参起名字,用于在SQL中引用。在SpringBoot官方骨架下,该注解可省略。
六、关键面试点:#{}与${}的区别
这是MyBatis高频面试题,核心差异在于参数传递方式:
| 特性 | #{} | ${} |
|---|---|---|
| 本质 | 占位符(PreparedStatement) | 字符串拼接 |
| SQL生成 | 替换为?,预编译SQL | 直接拼接参数值 |
| 安全性 | 防SQL注入(推荐使用) | 存在SQL注入风险(慎用) |
| 适用场景 | 普通参数传递(如ID、用户名) | 动态表名、字段名(如排序字段) |
示例对比:
// #{}:生成预编译SQL:select * from user where id = ?
@Select("select * from user where id = #{id}")
User findById(Integer id);
// ${}:拼接SQL:select * from user order by age(若sortField=age)
@Select("select * from user order by ${sortField}")
List<User> findAllOrderBy(@Param("sortField") String sortField);
⚠️ 重要提醒:除非必要,否则永远不要使用${} ,避免SQL注入风险。
七、XML映射配置:复杂SQL的最佳选择
1. XML映射文件规则
- 文件命名:XML文件名与Mapper接口名一致(如
UserMapper.xml) - 文件位置:与Mapper接口放在相同包下(或通过
mybatis.mapper-locations指定路径) - namespace:XML的
namespace属性等于Mapper接口全限定名 - SQL标签:SQL标签的
id等于Mapper接口方法名
2. XML配置示例
创建resources/mapper/UserMapper.xml:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.wmh.mapper.UserMapper">
<select id="findAll" resultType="com.wmh.pojo.User">
select id, username, password, name, age from user
</select>
</mapper>
Mapper接口(无需注解,依赖XML):
@Mapper
public interface UserMapper {
List<User> findAll(); // 方法名与XML中select标签的id一致
}
3. 开发效率插件:MyBatisX
推荐使用IDEA插件MyBatisX,支持:
- Mapper接口与XML文件相互跳转
- XML标签自动提示、语法校验
- 快速生成CRUD代码,大幅提升开发效率
安装方式:IDEA → Settings → Plugins → 搜索MyBatisX → 安装重启。
八、总结:MyBatis核心要点回顾
1. 核心概念
- Mapper接口命名规范:
XxxMapper(如UserMapper) - 单元测试注解:
@SpringBootTest(加载SpringBoot环境) - 测试类包名:必须与引导类包名相同或为子包
2. 核心技巧
- #{} vs ${} :永远优先使用#{},避免SQL注入
- XML配置:简单SQL用注解,复杂SQL用XML
- 连接池:默认HikariCP,可切换为Druid(功能更强大)
3. 最佳实践
- 项目初始化:使用Spring Initializr创建项目,引入必要依赖
- 配置管理:在
application.properties中配置数据库和MyBatis - 接口规范:按照
XxxMapper命名规范创建接口 - SQL管理:简单SQL用注解,复杂SQL用XML
- 安全第一:永远避免使用${},防止SQL注入
📌 最后建议:从简单查询开始,逐步掌握MyBatis的CRUD操作,再深入学习动态SQL、缓存机制、多表关联查询等高级特性。
通过本文的实践指导,你已经掌握了MyBatis的核心用法。现在,你可以尝试在实际项目中应用这些知识,让MyBatis成为你后端开发的"得力助手"!