ORM 与事务
持久化上下文、sb-transaction 衔接。
25 分钟
ORM 与事务
ORM 的 持久化上下文 与数据库 事务 生命周期绑定:同一 @Transactional 内,Entity 修改会在 flush 时变成 SQL;异常则整批回滚。
学习目标
- 理解持久化上下文与 Session 直觉
- 在 Service 层配合
@Transactional使用 JPA/MyBatis - 衔接 sb-transaction
典型业务:发布课程
@Service
public class TrackPublishService {
private final TrackRepository trackRepository;
private final LessonRepository lessonRepository;
@Transactional
public void publishTrack(Long trackId) {
Track track = trackRepository.findById(trackId).orElseThrow();
track.setStatus("published"); // 脏检查,flush 时 UPDATE
lessonRepository.findByTrackIdAndStatus(trackId, "draft")
.forEach(l -> l.setStatus("published"));
// 任一步抛 RuntimeException → 全部回滚
}
}
MyBatis 同理:同一 @Transactional 内多次 update 共享一个 JDBC 连接。
持久化上下文(JPA)
@Transactional 开始
→ EntityManager 打开持久化上下文
→ find() 返回 managed 对象
→ 改字段 → 事务提交前 flush → SQL
@Transactional 结束
→ 上下文关闭,对象 detached
坑:事务外改 detached 对象不会自动写库,需 merge() 或在新事务内重新加载。
只读与传播(常用)
@Transactional(readOnly = true)
public TrackDetailDto getTrackDetail(String slug) { ... }
只读事务可优化连接、避免无意 flush。传播行为默认 REQUIRED 即可,详见 sb-transaction。
ORM 特有事务坑
| 坑 | 说明 |
|---|---|
| 懒加载事务外访问 | LazyInitializationException |
| 长事务 | 持久化上下文堆积,占内存 |
| 自调用 | 同类方法互调不走代理,事务失效 |
| 批量 flush | 大量 insert 需 saveAll + 分批或 JDBC batch |
SQL 层 ACID 复习:sql-transaction、pg-transactions。