Spring Boot + MyBatis:高效构建持久层的最佳实践
1. 概述
MyBatis是一个Java持久化框架,它通过XML描述符或注解把对象与存储过程或SQL语句关联起来,映射成数据库内对应的纪录。Spring Boot 是一个快速开发框架,能够简化 Spring 应用的初始搭建和开发过程。本文将介绍如何在 Spring Boot 项目中集成 MyBatis,并提供实例代码。
2. 环境准备
- JDK 1.8 或更高版本
- IDEA
- Maven 3.x 或更高版本
- Spring Boot 2.x
- MyBatis 3.x
3.为什么要在Spring Boot 项目中集成 MyBatis呢
Spring Boot 中集成 MyBatis 的好处
1. 简化数据库操作
- MyBatis 提供了强大的 SQL 映射功能,开发者可以直接编写 SQL 语句,并通过简单的配置将 SQL 与 Java 对象映射。
- 相比于纯 JDBC,MyBatis 减少了大量的样板代码(如手动处理 ResultSet、PreparedStatement 等)。
2. 灵活的 SQL 控制
- MyBatis 允许开发者完全控制 SQL 语句的编写,适合复杂查询或需要高度优化的场景。
- 支持动态 SQL(通过
、
等标签),能够根据条件动态生成 SQL。
3. 与 Spring Boot 无缝集成
- MyBatis 提供了
mybatis-spring-boot-starter
,可以快速集成到 Spring Boot 项目中。 - 通过注解或 XML 配置,开发者可以轻松管理数据库操作。
4. 易于调试和优化
- 由于 SQL 语句是显式编写的,开发者可以直观地看到执行的 SQL,便于调试和性能优化。
- 支持日志输出 SQL 语句,方便排查问题。
5. 支持多种数据库
- MyBatis 支持多种数据库(如 MySQL、PostgreSQL、Oracle 等),只需更换数据源配置即可。
6. 良好的扩展性
- MyBatis 支持插件机制,可以通过自定义插件实现分页、缓存、SQL 拦截等功能。
- 支持与第三方框架(如 PageHelper)集成,简化分页操作。
7. 降低学习成本
- MyBatis 的学习曲线相对较低,尤其是对于熟悉 SQL 的开发者。
- 相比于 JPA 的复杂抽象,MyBatis 更贴近传统数据库操作。
如果不集成 MyBatis 呢,我们使用其他的的替代方案
如果不集成 MyBatis,Spring Boot 项目仍然可以通过其他方式操作数据库,常见的替代方案包括:
1. 使用 Spring Data JPA
- 优点:
- 完全面向对象,无需编写 SQL 语句。
- 支持自动生成 SQL,适合简单的 CRUD 操作。
- 提供丰富的查询方法命名规则,减少代码量。
- 缺点:
- 对于复杂查询,SQL 生成可能不够灵活。
- 性能优化相对困难,尤其是需要手动优化 SQL 的场景。
2. 使用纯 JDBC
- 优点:
- 完全控制 SQL 语句,适合需要极致性能优化的场景。
- 不依赖任何 ORM 框架,轻量级。
- 缺点:
- 需要手动处理 ResultSet、PreparedStatement 等,代码量大且容易出错。
- 缺乏对象关系映射(ORM)功能,开发效率低。
3. 使用其他 ORM 框架
- 例如 Hibernate、JOOQ 等。
- 优点:
- Hibernate 提供了强大的 ORM 功能,适合复杂的对象关系映射。
- JOOQ 提供了类型安全的 SQL 构建方式。
- 缺点:
- 学习成本较高,尤其是 Hibernate 的复杂配置和缓存机制。
- 对于简单项目,可能显得过于重量级。
4. 使用 Spring JDBC Template
- 优点:
- 相比于纯 JDBC,Spring JDBC Template 简化了数据库操作。
- 提供了更好的异常处理和资源管理。
- 缺点:
- 仍然需要手动编写 SQL 语句,缺乏 ORM 功能。
- 对于复杂查询,代码量较大。
4. 创建 Spring Boot 项目
- 打开IDEA>新建项目>选择Spring Initializer,这里将服务器URL换成start.aliyun.com更快一点
- 接下来我们选择以下这三个依赖:然后点击创建
- Spring Web
- MyBatis Framework
- MySQL Driver
- 当我们创建好之后,找到我们项目目录下的pom.xml文件中,可以看到我们的依赖已经添加进来,
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>demo</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.6.13</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.2</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>${spring-boot.version}</version>
<configuration>
<mainClass>com.example.demo.DemoApplication</mainClass>
<skip>true</skip>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
5. 配置数据库连接
在 application.properties
或 application.yml
中配置数据库连接信息,端口自己随便设置即可,不要跟其他端口冲突就行:
server:
port: 8666 # 后端端口
spring:
banner:
charset: UTF-8
location: classpath:banner.txt
datasource:
url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai
username: root # MySQL 用户名
password: 你的密码 # MySQL 密码
driver-class-name: com.mysql.cj.jdbc.Driver
mybatis:
# mapper xml 文件路径
mapper-locations: classpath:mapper/*.xml
# 实体类包路径
type-aliases-package: com.example.demo.entity
configuration:
# 开启驼峰命名
map-underscore-to-camel-case: true
6. Model 层(实体层/POJO 层)
创建一个简单的实体类 User
:
作用:
定义与数据库表结构映射的 Java 对象(POJO),通常称为实体类(Entity)或数据模型(Model)。
每个字段对应数据库表中的一列,用于在层间传输数据(如 Service 到 Controller、Mapper 到 Service)
public class User {
private Long id;
private String name;
private String email;
// getters/setters
}
关键点:
- 使用
@Data
(Lombok)可简化代码。 - 可与 DTO(Data Transfer Object)区分,DTO 用于前后端数据传输,而 Model 直接映射数据库。
7.Mapper 层(DAO 层,数据访问层)
作用:
直接与数据库交互,负责执行 SQL 操作(增删改查)。
通过 MyBatis 的接口与 XML 配置文件(或注解)实现 ORM 映射,隔离数据库操作细节。
- 接口定义:
@Mapper // Spring 自动生成实现类
public interface UserMapper {
User selectById(Long id);
void insert(User user);
}
- XML 映射(
UserMapper.xml
):
<select id="selectById" resultType="com.example.model.User">
SELECT * FROM user WHERE id = #{id}
</select>
关键点:
- 使用
@Mapper
或@MapperScan
扫描接口,MyBatis 动态生成代理类。 - 方法名与 XML 中的
id
对应,参数通过#{field}
绑定。
8.Service 层(业务逻辑层)
作用:
封装业务逻辑,处理复杂的业务规则(如数据校验、事务管理、多表操作组合)。
作为 Controller 和 Mapper 之间的桥梁,确保业务操作的原子性。
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional // 事务管理
public void createUser(User user) {
if (user.getName() == null) throw new IllegalArgumentException("Name required");
userMapper.insert(user);
}
}
关键点:
- 使用
@Service
标记为 Spring 管理的 Bean。 - 通过
@Transactional
注解声明事务(如插入失败自动回滚)
9.Controller 层(表现层)
作用:
接收 HTTP 请求,解析参数,调用 Service 处理业务,返回响应(JSON/视图)。
负责处理路由、参数校验及响应格式。
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PostMapping
public ResponseEntity<String> createUser(@RequestBody User user) {
userService.createUser(user);
return ResponseEntity.ok("User created");
}
}
关键点:
- 使用
@RestController
或@Controller
标识。 - 通过
@GetMapping
/@PostMapping
映射请求路径。 - 参数校验可使用
@Valid
配合 Hibernate Validator。
其他辅助组件
- DTO(Data Transfer Object):
定制化传输对象(如屏蔽敏感字段、聚合多个 Model 数据),避免直接暴露 Model。 - Configuration 类:
配置数据源、MyBatis 等(Spring Boot 通过application.yml
简化):
spring:
datasource:
url: jdbc:mysql://localhost:3306/db
username: root
password: 123456
mybatis:
mapper-locations: classpath:mapper/*.xml
各层协作流程
- 请求入口 →
Controller
接收参数并校验格式。 - 业务处理 →
Controller
调用Service
方法。 - 数据操作 →
Service
调用Mapper
接口操作数据库。 - 结果返回 →
Controller
将处理结果封装为 HTTP 响应。
分层优势
- 解耦:修改数据库(如切换 MySQL 到 PostgreSQL)只需调整 Mapper 层,不影响业务逻辑。
- 复用性:Service 方法可被多个 Controller 调用。
- 可测试性:各层可独立测试(如 Mock Mapper 测试 Service)。
MyBatis 中的主要注解和作用
@Select
- 作用: 用于定义查询语句。
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(int id);
@Insert,@Update,@Delete
- 作用: 用于定义插入,更新,删除语句。
@Insert("INSERT INTO users(name, email) VALUES(#{name}, #{email})")
void insertUser(User user);
@Update("UPDATE users SET name = #{name}, email = #{email} WHERE id = #{id}")
void updateUser(User user);
@Delete("DELETE FROM users WHERE id = #{id}")
void deleteUser(int id);
@Param
- 作用: 用于给方法参数命名,以便在 SQL 语句中引用。
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "email", column = "email")
})
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(int id);
@Results
- 作用: 用于定义结果映射,将查询结果映射到 Java 对象。
@Results({
@Result(property = "id", column = "id"),
@Result(property = "name", column = "name"),
@Result(property = "email", column = "email")
})
@Select("SELECT * FROM users WHERE id = #{id}")
User getUserById(int id);
@Result
- 作用: 用于定义单个字段的映射关系,通常与
@Results
一起使用。
@Result(property = "id", column = "id")
@ResultMap
- 作用: 用于指定查询结果的映射规则,通常与 @Select 一起使用。
@Select("SELECT * FROM users WHERE id = #{id}")
@ResultMap("userResultMap")
User getUserById(@Param("id") Long id);
@Options
- 作用: 用于指定插入操作的选项,如是否使用自动生成的主键。
@Insert("INSERT INTO users(name, age) VALUES(#{name}, #{age})")
@Options(useGeneratedKeys = true, keyProperty = "id")
int insertUser(User user);
@MapKey
- 作用: 用于指定返回结果为 Map 时,Map 的键对应的属性。
@Select("SELECT * FROM users")
@MapKey("id")
Map<Long, User> getUsersMap();
这些注解使得 MyBatis 的使用更加简洁和直观,减少了 XML 配置的复杂性。
实践总结:
- 注解与 XML 混合使用: 在简单的 SQL 操作中,优先使用注解方式,提升开发效率;对于复杂的 SQL,使用 XML 文件进行管理,增强可维护性。
- 动态 SQL 的应用: 充分利用 MyBatis 的动态 SQL 功能,处理复杂查询条件,避免在代码中拼接 SQL 字符串,提升代码的可读性和安全性。
- 事务管理: 在需要保证数据一致性的操作中,使用 Spring 的事务管理机制,确保操作的原子性。
- 性能优化: 合理使用 MyBatis 的缓存机制,减少数据库访问次数;对于分页查询,使用分页插件,避免一次性加载大量数据导致性能问题。
为 Map 时,Map 的键对应的属性。
@Select("SELECT * FROM users")
@MapKey("id")
Map<Long, User> getUsersMap();
这些注解使得 MyBatis 的使用更加简洁和直观,减少了 XML 配置的复杂性。
通过遵循上述最佳实践,开发者可以在 Spring Boot 项目中高效地构建持久层,提升系统的性能和可维护性。
- 本文链接: https://refblogs.com/article/1047
- 版权声明: 本文为互联网转载文章,出处已在文章中说明(部分除外)。如果侵权,请联系本站长删除,谢谢。