@Transaction

@Transactional = 把一段代码包进"要么全成功、要么全失败"的数据库事务里

事务

事务可以理解成一组数据库操作的保险箱

事务最关键的两个特性:

  • 原子性:要么都成功,要么都失败
  • 一致性:数据不会出现"写了一半"的怪状态

@Transactioal

java 复制代码
@Transactional
public void doSomething() {
    saveA();
    saveB();
}

加上这个注解后,Spring会在方法执行前后帮你做这件事:

复制代码
开启事务
  ↓
执行方法
  ↓
没异常 → 提交事务
有异常 → 回滚事务

完全不用手写 begin / commit / rollback

但JPA自带方法,如save(),delete()都是自带@Transactional的

如果在类上加@Transactional,则这个类里所有public方法默认都有事务

rollbackFor属性

用来指定:当抛出哪些"异常类型"时,事务也要回滚,因为Spring默认并不是"所有异常都会回滚"

默认为:

异常类型 是否回滚
RuntimeException ✅ 回滚
Error ✅ 回滚
受检异常(Exception) 不回滚

也就是说对于:

java 复制代码
@Transactional
public void test() throws Exception {
    repository.save(order);
    throw new Exception("出错了");
}

事务不会回滚

如果没有事务

java 复制代码
public void refundAndLog(RefundOrder order) {
    refundOrderRepository.save(order);   // 步骤1:保存退款订单
    logRepository.save(new Log("退款成功")); // 步骤2:写日志
}

如果没有@Transactional,save(order)会独立开一个事务提交,save(log)也会再开一个事务提交,如果第二步报错(如数据库断开,或唯一约束冲突)

就会产生结果:

refund_order 表里已经插入了一条数据 log 表没插入

数据库就处于 不一致状态

但如果加上@Transactional,Spring会在方法开始时开启事务,如果第二步报错,则事务回滚,refund_order的插入也被撤销,

推荐用法

  • Service层:凡是有"写数据库"的方法,加@Transactional
  • 查询可以不加,或者加@Transactional(readOnly = true)
  • Controller上不要加,防止事务时间过长,容易锁表

脏检查

脏检查 = Hibernate 在事务提交前,自动检查"被托管的实体对象有没有被改过",如果改过,就自动生成 UPDATE SQL

java 复制代码
@Service
@Transactional   // 注意:类上有事务
public class RefundOrderService {

    public RefundOrder getAndFormat(Long id) {
        RefundOrder order = repository.findById(id).orElse(null);

        // 你只是想格式化一下数据,给前端看
        order.setMoney(
            order.getMoney().setScale(2, RoundingMode.HALF_UP)
        );

        return order;
    }
}

这段代码看似

也就是说你不用写Update,它也会帮你更新

什么情况下会有脏检查

脏检查不是随时都有,需要满足三个条件

  1. 实体是"托管状态"
java 复制代码
`RefundOrder order = repository.findById(1L).get();`

此时:

  • order 被 Hibernate 托管

  • 放在 Session / Persistence Context 里

  1. 处在事务中(@Transactional)
java 复制代码
@Transactional
public void test() {
    ...
}
  1. 修改了实体属性
java 复制代码
order.setMoney(new BigDecimal("100"));

满足这三点时,脏检查一定会发生

脏检查是怎么工作的:

  1. 实体第一次加载时:
java 复制代码
RefundOrder order = repository.findById(1L).get();

Hibernate会:

  • 从数据库查数据
  • 保存一份"快照"
  1. 你在Java里改对象
java 复制代码
order.setMoney(100);
  1. 事务即将提交

Hibernate 在commit前:

  • 对比快照和当前对象
  • 发现不一样->脏了
  1. 自动生成update的SQL

Session:Hibernate的核心概念

Session是什么

Java对象和数据库之间的"中间人"

它负责:

  1. 持久化对象管理(Persistent Context)

    • 把你 new 出来的对象变成"托管对象"(managed entity)

    托管对象 = 正被Hibernate监控的对象,直到你有没有改它,什么时候该同步到数据库

  2. 缓存

    • Session 内部会缓存你查出来的实体,减少重复 SQL
  3. 事务同步

    • 事务提交时,自动把对象状态同步到数据库(自动 flush)
  4. 延迟加载(Lazy Loading)

    • 代理对象在访问时通过 Session 去数据库加载数据

和数据库的关系

  • Session不是数据库
  • 它是 Hibernate 管理对象和数据库连接的工具
  • Session 内部会拿 Connection 去操作数据库

当你在事务里操作JPA/Hibernate:

rust 复制代码
方法开始 -> Spring 开启事务 -> Hibernate 打开 Session -> 获取 JDBC Connection
  • Session 里保存实体的状态
  • flush / commit 时 → JDBC Connection 执行 SQL

为什么 Lazy Loading 需要 Session?

java 复制代码
RefundOrder order = repository.findById(1L).orElse(null);
System.out.println(order.getItems().size()); // 懒加载触发
  • items 是 LAZY
  • Hibernate 给你一个代理对象
  • 代理对象会去 Session 拿连接,发 SQL
  • 如果 Session 关闭(事务结束) → 连接没了 → 报 LazyInitializationException

Session生命周期

阶段 发生什么
开启事务 Session 开始,连接准备好
执行查询 Session 缓存实体,生成代理对象
访问 LAZY 属性 Session 用 Connection 发 SQL
事务提交/回滚 Session flush 或清空
方法返回后 Session 被关闭,延迟加载不再可用

总结

Session 是 Hibernate 管理实体对象、缓存和数据库连接的中间人,Lazy Loading 和事务依赖它,但它本身不是数据库

相关推荐
星辰徐哥18 小时前
Spring Boot 微服务架构设计与实现
spring boot·后端·微服务
星辰徐哥18 小时前
Spring Boot 数据导入导出与报表生成
spring boot·后端·ui
明夜之约18 小时前
Spring Boot 自动装配源码
java·spring boot·后端
Leaton Lee18 小时前
Spring Boot分层架构详解:从Controller到Service再到Mapper的完整流程
java·spring boot·后端·架构
Micro麦可乐18 小时前
Spring Boot 实战:从零设计一个短链系统(含完整代码与数据库设计)
数据库·spring boot·后端·哈希算法·雪花算法·短链系统
Jinkxs18 小时前
Resilience4j- 与 Spring Boot 快速集成:自动配置与基础注解使用
java·spring boot·后端
毕设源码_郑学姐18 小时前
计算机毕业设计springboot网络相册设计与实现 基于Spring Boot框架的在线相册管理系统开发与应用 Spring Boot驱动的网络影集设计与实践
spring boot·后端·课程设计
辣机小司18 小时前
【踩坑记录:Spring Boot 配置文件读取值不一致?警惕 YAML 的“八进制陷阱”与 SnakeYAML 版本之谜】
java·spring boot·后端·yaml·踩坑记录
码农阿豪18 小时前
从零到一:Spring Boot快速接入金仓数据库实战
数据库·spring boot·后端
追逐时光者18 小时前
一个基于 .NET 与 Avalonia 构建、面向 TrinityCore 的开源 WoW 数据库编辑器
后端·.net