spring mybatis(保姆级教程)
💡一则或许对你有用的小广告
欢迎加入小哈的星球 ,你将获得:专属的项目实战 / 1v1 提问 / Java 学习路线 / 学习打卡 / 每月赠书 / 社群讨论
- 新项目:《从零手撸:仿小红书(微服务架构)》 正在持续爆肝中,基于
Spring Cloud Alibaba + Spring Boot 3.x + JDK 17...
,点击查看项目介绍 ;- 《从零手撸:前后端分离博客项目(全栈开发)》 2 期已完结,演示链接: http://116.62.199.48/ ;
截止目前, 星球 内专栏累计输出 82w+ 字,讲解图 3441+ 张,还在持续爆肝中.. 后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,权限管理,Spring Cloud Alibaba 微服务等等,已有 2900+ 小伙伴加入学习 ,欢迎点击围观
前言:Spring 与 MyBatis 的协同之道
在 Java 后端开发领域,Spring MyBatis 是一套被广泛采用的技术组合。Spring 框架以其强大的生态和模块化设计,为开发者提供了 IoC(控制反转)和 AOP(面向切面编程)等核心能力;而 MyBatis 则以灵活的 SQL 映射机制,解决了传统 ORM 框架(如 Hibernate)在复杂查询场景下的不足。两者的结合,既保留了 Spring 的优雅架构,又赋予了 MyBatis 的“精准控制”,成为企业级应用开发的黄金搭档。
本文将从零开始,逐步讲解如何通过 Spring 和 MyBatis 构建一个完整的数据访问层(DAO),并结合实战案例,帮助读者理解其核心原理与最佳实践。
核心概念:Spring 与 MyBatis 的角色定位
1. Spring 的职责
Spring 框架的核心在于“解耦”与“管理”。它通过以下方式简化开发:
- IoC 容器:负责对象的创建、初始化和依赖注入,避免手动管理对象生命周期。
- AOP 支持:将日志、事务、安全等横切逻辑从业务代码中分离,提升代码复用性。
- 模块化设计:提供
Spring MVC
(Web 层)、Spring Data
(数据层)、Spring Security
(安全层)等模块,实现分层解耦。
比喻:如果将系统比作一支交响乐团,Spring 就是指挥家,负责协调各个模块(乐手)的协作,确保整体流程顺畅。
2. MyBatis 的职责
MyBatis 是一款“半自动化”的 ORM 框架,其核心思想是手动编写 SQL 语句,并通过 XML 或注解将结果映射到 Java 对象。相比 Hibernate,它的优势在于:
- 灵活控制 SQL:开发者可以直接编写原生 SQL,无需依赖框架的复杂映射规则。
- 轻量级设计:仅需依赖少量核心类(如
SqlSession
),学习成本较低。 - 与 Spring 的天然适配:MyBatis 提供了
mybatis-spring
扩展包,无缝集成 Spring 的事务管理和依赖注入。
比喻:MyBatis 好比一位技艺精湛的乐手,专注于执行“演奏”(SQL 执行)的细节,而 Spring 则负责为其分配曲谱(数据库配置)和协调合奏(事务管理)。
环境搭建:快速启动项目
1. 依赖配置
使用 Maven 或 Gradle 管理项目依赖。以下以 Maven 为例:
<!-- 核心依赖 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.9</version>
</dependency>
<!-- Spring MyBatis 集成 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.2.0</version>
</dependency>
<!-- 数据库驱动(以 MySQL 为例) -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.29</version>
</dependency>
2. 配置数据源
在 application.properties
中配置数据库连接信息:
spring.datasource.url=jdbc:mysql://localhost:3306/mydb?useSSL=false
spring.datasource.username=root
spring.datasource.password=123456
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
mybatis.mapper-locations=classpath:mapper/*.xml
mybatis.type-aliases-package=com.example.entity
核心配置详解:Spring 与 MyBatis 的整合
1. 数据源与事务管理
通过 DataSource
和 TransactionManager
,Spring 管理数据库连接和事务边界:
@Configuration
@EnableTransactionManagement
public class DataSourceConfig {
@Bean
@ConfigurationProperties(prefix = "spring.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
@Bean
public PlatformTransactionManager transactionManager(
DataSource dataSource) {
return new DataSourceTransactionManager(dataSource);
}
}
2. MyBatis 配置
通过 SqlSessionFactory
和 SqlSessionTemplate
,将 MyBatis 的执行器与 Spring 整合:
@Configuration
public class MyBatisConfig {
@Bean
public SqlSessionFactory sqlSessionFactory(
DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);
return factory.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(
SqlSessionFactory sqlSessionFactory) {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
基础操作:CRUD 的实现
1. 实体类与 Mapper 接口
定义一个简单的 User
实体类:
public class User {
private Long id;
private String name;
private Integer age;
// 省略 getter/setter
}
创建对应的 Mapper 接口,并使用 @Mapper
注解声明:
@Mapper
public interface UserMapper {
@Select("SELECT * FROM user WHERE id = #{id}")
User selectById(Long id);
@Insert("INSERT INTO user(name, age) VALUES(#{name}, #{age})")
void insert(User user);
@Update("UPDATE user SET age = #{age} WHERE id = #{id}")
void update(User user);
@Delete("DELETE FROM user WHERE id = #{id}")
void deleteById(Long id);
}
2. 服务层与事务控制
在服务层通过 @Autowired
注入 Mapper,结合 @Transactional
管理事务:
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void transferMoney(Long fromId, Long toId, Integer amount) {
User fromUser = userMapper.selectById(fromId);
User toUser = userMapper.selectById(toId);
// 执行扣款和加款操作
fromUser.setAge(fromUser.getAge() - amount);
toUser.setAge(toUser.getAge() + amount);
userMapper.update(fromUser);
userMapper.update(toUser);
}
}
高级特性:动态 SQL 与缓存
1. 动态 SQL 的灵活使用
通过 MyBatis 的 <if>
、<choose>
、<foreach>
等标签,实现条件查询:
<!-- 在 UserMapper.xml 中 -->
<select id="selectUsers" resultType="User">
SELECT * FROM user
WHERE 1=1
<if test="name != null">
AND name LIKE CONCAT('%', #{name}, '%')
</if>
<if test="age != null">
AND age >= #{age}
</if>
</select>
2. 二级缓存优化性能
MyBatis 的二级缓存可缓存跨 SQL 查询的结果,通过以下配置开启:
<!-- 在 MyBatis 配置文件中 -->
<cache/>
同时,需确保实体类实现 Serializable
接口,并在 Mapper 接口添加 @CacheNamespace
注解:
@CacheNamespace
public interface UserMapper {
// 方法定义
}
常见问题与解决方案
1. 事务未生效
原因:未在方法上添加 @Transactional
,或未开启事务管理。
解决:检查 @EnableTransactionManagement
是否存在于配置类,并确保方法处于 Spring 管理的 Bean 中。
2. SQL 注入漏洞
原因:直接拼接 SQL 字符串,未使用参数化查询。
解决:使用 #{}
占位符代替字符串拼接,例如:
<update id="updateUser">
UPDATE user SET name = #{name} WHERE id = #{id}
</update>
实战案例:用户管理系统
1. 需求分析
实现一个简单的用户管理系统,支持以下功能:
- 新增用户
- 查询用户列表(带分页)
- 根据年龄筛选用户
2. 完整代码示例
Mapper 接口
@Mapper
public interface UserMapper {
void insert(User user);
@Select({
"SELECT * FROM user",
"<where>",
" <if test='age != null'>age >= #{age}</if>",
"</where>"
})
List<User> selectUsers(@Param("age") Integer age);
@Select("SELECT * FROM user LIMIT #{offset}, #{pageSize}")
List<User> selectPage(@Param("offset") int offset,
@Param("pageSize") int pageSize);
}
服务层实现
@Service
public class UserService {
private final UserMapper userMapper;
public UserService(UserMapper userMapper) {
this.userMapper = userMapper;
}
public void addUser(User user) {
userMapper.insert(user);
}
public List<User> getUsers(Integer age, int page, int pageSize) {
int offset = (page - 1) * pageSize;
List<User> allUsers = userMapper.selectUsers(age);
// 分页逻辑(简化示例)
return allUsers.subList(offset, offset + pageSize);
}
}
结论:构建可持续演进的代码架构
通过本文的讲解,我们完成了从基础配置到高级特性的全链路实践。Spring MyBatis 的组合既保留了 Spring 的架构优势,又赋予了 MyBatis 的灵活性,适合需要精细控制 SQL 的复杂业务场景。
在实际开发中,建议遵循以下原则:
- 分层清晰:严格分离 Controller、Service、DAO 层,避免业务逻辑侵入数据访问层。
- 代码复用:通过 MyBatis 的
<include>
标签或公共 SQL 片段,减少重复代码。 - 性能优化:合理使用缓存、分页和索引,避免全表查询。
希望本文能帮助开发者快速掌握 Spring MyBatis 的核心思想,并在实际项目中游刃有余地应用这一技术栈。