一、Spring 事务管理(Transaction Management)
1. 事务基本配置步骤
Spring Boot 中使用声明式事务非常简单,只需三步:
✅ 步骤一:引入依赖(通常已包含)
<!-- spring-boot-starter-data-jpa 或 mybatis-spring-boot-starter 已包含 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
⚠️ 实际上
spring-boot-starter-*
数据相关 starter 已默认集成事务支持,无需手动添加 AOP 依赖(但底层依赖 AOP 实现)。
✅ 步骤二:启用事务支持
在主启动类或配置类上添加 @EnableTransactionManagement
(Spring Boot 2.x+ 可省略,自动启用):
@SpringBootApplication
@EnableTransactionManagement // 可选,Spring Boot 默认开启
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
✅ 步骤三:使用 @Transactional
注解
标注在 Service 层的方法 上(不建议在 Controller 使用):
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
@Transactional
public void transferMoney(Long fromId, Long toId, BigDecimal amount) {
userMapper.decreaseBalance(fromId, amount);
// 模拟异常
if (amount.compareTo(BigDecimal.TEN) > 0) {
throw new RuntimeException("金额过大,转账失败");
}
userMapper.increaseBalance(toId, amount);
}
}
✅ 效果:若方法中抛出异常(默认检查 RuntimeException 和 Error),事务将回滚;否则提交。
2. 事务隔离级别(Isolation Level)
隔离级别 | 说明 | 存在问题 |
---|---|---|
READ_UNCOMMITTED |
读未提交 | 脏读、不可重复读、幻读 |
READ_COMMITTED |
读已提交 | 不可重复读、幻读 |
REPEATABLE_READ |
可重复读 | 幻读(部分数据库可避免) |
SERIALIZABLE |
串行化 | 性能极低,排队执行 |
🔺 安全性递增,性能递减
🔹 默认值:
ISOLATION_DEFAULT
→ 使用数据库默认隔离级别(MySQL 默认为REPEATABLE_READ
)
@Transactional(isolation = Isolation.READ_COMMITTED)
public void method() { ... }
3. 事务传播机制(Propagation Behavior)
Spring 定义了 7 种传播行为,控制多个事务方法调用时的事务边界。
传播行为 | 说明 | 使用场景 |
---|---|---|
REQUIRED (默认) |
必须有事务。若已有则加入,否则新建 | 增删改操作(CRUD-write) |
SUPPORTS |
支持事务。有则加入,无则非事务执行 | 查询方法(只读) |
MANDATORY |
必须运行在事务中,否则抛异常 | 强制要求调用者开启事务 |
REQUIRES_NEW |
总是新建事务,挂起当前事务 | 日志记录、独立操作 |
NOT_SUPPORTED |
不支持事务,挂起当前事务 | 批量导入等耗时操作 |
NEVER |
不支持事务,若有事务则抛异常 | 确保非事务环境运行 |
NESTED |
嵌套事务。外层回滚,内层也回滚;内层可独立回滚 | 复杂业务逻辑中的子事务控制 |
📌 示例:
@Service
public class BusinessService {
@Autowired
private LogService logService;
@Transactional(propagation = Propagation.REQUIRED)
public void businessMethod() {
// 主业务逻辑
doBusiness();
// 即使主事务失败,日志仍需记录
logService.saveLog(); // 内部使用 REQUIRES_NEW
}
}
@Service
public class LogService {
@Transactional(propagation = Propagation.REQUIRES_NEW)
public void saveLog() {
// 新建事务,独立提交
}
}
二、Spring 缓存机制(Caching Abstraction)
基于 AOP + 注解 实现,统一抽象缓存操作,支持多种缓存实现(如 Caffeine、Redis、EhCache 等)。
1. 核心注解
注解 | 作用 |
---|---|
@EnableCaching |
启用 Spring 缓存支持(加在启动类或配置类) |
@Cacheable |
方法执行前查缓存,命中则不执行方法 |
@CachePut |
方法执行后更新缓存,总是执行方法 |
@CacheEvict |
清除缓存(可清单个或全部) |
@CacheConfig |
类级别缓存配置(统一 cacheNames、keyGenerator 等) |
2. Spring Boot 整合 Redis 缓存
✅ 步骤一:引入依赖
<!-- Spring Data Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- Spring Cache 抽象 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
✅ 步骤二:配置文件(application.yml)
spring:
# Redis 配置
data:
redis:
host: localhost
port: 6379
password: 123456
database: 0
timeout: 1s
connect-timeout: 3s
lettuce:
pool:
max-active: 8
max-idle: 8
min-idle: 0
# 缓存配置
cache:
type: redis
redis:
time-to-live: 4h # 缓存过期时间(TTL)
cache-null-values: false # 是否缓存 null 值
cache-names: userCache, deptCache # 预定义缓存名称
✅ 步骤三:启用缓存
@SpringBootApplication
@EnableCaching // 启用缓存
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
✅ 步骤四:使用缓存注解
@Service
@CacheConfig(cacheNames = "userCache") // 统一指定缓存名
public class UserService {
@Autowired
private UserMapper userMapper;
// 查询时先查缓存,key = userId
@Cacheable(key = "#id")
public User findById(Long id) {
System.out.println("查询数据库...");
return userMapper.findById(id);
}
// 更新后同步更新缓存
@CachePut(key = "#user.id")
public User update(User user) {
userMapper.update(user);
return user; // 返回值会自动放入缓存
}
// 删除用户,同时清除缓存
@CacheEvict(key = "#id")
public void deleteById(Long id) {
userMapper.deleteById(id);
}
// 清空整个缓存
@CacheEvict(allEntries = true)
public void clearCache() {
// ...
}
}
3. Redis 五大数据类型简介
类型 | 特点 | 应用场景 |
---|---|---|
String | 字符串 | 缓存、计数器、分布式锁 |
List | 有序、可重复 | 消息队列、最新消息列表 |
Set | 无序、不重复 | 好友标签、共同关注 |
ZSet (Sorted Set) | 有序集合,带 score 排序 | 排行榜、延迟队列 |
Hash | 键值对集合 | 存储对象(如用户信息) |
🔍 示例:用 Hash 存储用户信息
opsHash.put("user:1001", "name", "张三");
opsHash.put("user:1001", "age", "25");
4. 缓存过期策略(TTL - Time To Live)
-
Redis 支持设置键的过期时间,单位秒或毫秒。
-
Spring Cache 中通过
time-to-live
配置全局 TTL。 -
可在注解中单独设置:
@Cacheable(key = "#id", ttl = 3600) // 单独设置过期时间(需自定义 CacheManager)
三、Caffeine vs Redis
对比项 | Caffeine(本地缓存) | Redis(分布式缓存) |
---|---|---|
存储位置 | JVM 内存 | 独立服务 |
速度 | 极快(纳秒级) | 快(毫秒级) |
容量 | 受限于 JVM | 大(可集群扩展) |
一致性 | 单机一致 | 分布式一致 |
适用场景 | 高频读、低变更数据 | 共享数据、跨服务缓存 |
✅ 推荐组合使用:Caffeine + Redis(多级缓存)
四、最佳实践与注意事项
✅ 事务使用建议
- 标注在 public 方法 上(AOP 代理限制)。
- 避免在 private、final、static 方法上使用。
- 异常要抛出,才能触发回滚。
- 自调用(this.method())不会触发事务(代理失效)。
✅ 缓存使用建议
- 合理设置 TTL,避免数据陈旧。
- 缓存穿透:加空值缓存或布隆过滤器。
- 缓存雪崩:设置随机过期时间。
- 缓存击穿:热点数据加互斥锁。
- 使用
@CacheConfig
统一管理缓存配置。
五、总结对比表
功能 | 事务(Transaction) | 缓存(Caching) |
---|---|---|
实现机制 | AOP + PlatformTransactionManager | AOP + CacheManager |
核心注解 | @Transactional |
@Cacheable , @CachePut , @CacheEvict |
配置注解 | @EnableTransactionManagement |
@EnableCaching |
性能影响 | 回滚代价高 | 显著提升读性能 |
典型场景 | 数据一致性保障 | 减少数据库压力 |
📌 学习建议:
- 动手实践事务传播行为(如 REQUIRED vs REQUIRES_NEW)。
- 使用 Redis Desktop Manager 查看缓存数据。
- 结合日志观察缓存命中情况。
- 理解 AOP 是事务和缓存的底层支撑机制。
✅ Spring 事务 + 缓存 = 高可用、高性能应用的基石!