Spring事务背后的真相:我们被骗了这么多年?

B站影视 港台电影 2025-06-05 16:21 7

摘要:上个月我去面了一家还不错的互联网公司,坐标杭州。项目上刚好不那么忙,我心想,去试试水,也算是看看市场行情。

上个月我去面了一家还不错的互联网公司,坐标杭州。项目上刚好不那么忙,我心想,去试试水,也算是看看市场行情。

面试开始五分钟,面试官就抛出了这道题:

我当时一听,心里偷笑:这题我熟,春招秋招社招必考题,面试圈的“Hello World”。

于是我立刻答道:

“Spring事务通过AOP实现的,在方法上加上 @Transactional 注解,Spring会用代理拦截方法调用,创建事务、提交事务、回滚事务。”

面试官听着点头,但脸上没有一丝波澜。他继续追问:

“那你知道数据库层的事务是怎么实现的吗?Spring怎么协调的?”

我一愣。数据库层?不是我说完 AOP 和代理就够了吗?

我顿了几秒,开始强行接住:

“数据库本身有事务支持,Spring只是通过事务管理器调用JDBC接口…”

话没说完,面试官突然说了一句话:

“其实你刚刚说的那些都只是表象,真正的事务发生在数据库内部,是靠 redo log 和 binlog 这样的机制实现的,Spring 只是配合你演了一出戏。

那一刻,我突然像是被人点醒了武林盲点。

我们很多人,尤其是工作 1~3 年的小伙伴,可能都能说出下面这些话:

Spring 事务使用 @Transactional 实现。Spring 提供 PlatformTransactionManager 管理事务。Spring 使用 AOP 或 CGLIB 动态代理来包裹方法,实现前置开启事务、后置提交或回滚。

没错,这都对。

但是,这只是“Spring层面的事务包装”,而不是事务的本质

让我们打个比方:

假如Spring是剧组,@Transactional 是舞台

我们写下:

就像我们写下一个剧本:

主角转账扣钱 -> 加钱

Spring 会出动一个“导演”TransactionManager,它会:

在方法执行前:调用 JDBC 的 connection.setAutoCommit(false),开启事务在方法执行后:如果没异常,connection.commit;否则,connection.rollback

你看,这就是我们眼里的“事务”。但你有没有想过:

Spring这么做,能保证你的数据真的一致吗?

我们都知道,事务的4大特性:ACID

让我们来看看数据库是怎么处理事务的。

我们以 MySQL 的 InnoDB 存储引擎为例。

1、redo log:持久化的保障者

当你开启一个事务后,在执行 update、insert、delete 等操作时,数据库其实并没有立即改动磁盘上的数据页

它只是:

先在内存(buffer pool)里改数据再写入一份 redo log(重做日志)

只有等你执行 commit 时:

数据库会将 redo log 标记为已提交后台线程慢慢把脏页刷新到磁盘

也就是说,redo log 才是事务是否成功的关键。

哪怕宕机了,只要 redo log 在,数据库就能“重做”你的操作。

2、undo log:回滚的守护者

而在执行每一个数据修改时,数据库会记录对应的undo log,也就是“怎么把这一步撤销”。

如果事务执行中途抛出异常,Spring调用了rollback,数据库就通过 undo log 让数据恢复原样。

3、binlog:MySQL 的官方记账本

除了 redo log 和 undo log,还有一个经常被提到的 binlog(归档日志),它是 MySQL Server 层记录的日志,用于主从同步、数据恢复等。

那我们回过头来说说,Spring 到底干了什么?

答案很简单:

Spring 是一个“事务协调器”。

它通过声明式或编程式事务管理,告诉数据库:

“老哥,接下来我要演一场戏,你看着点,该加锁就加锁,该提交就提交。”

Spring事务的实现流程:

拦截方法调用(AOP)获取当前数据源连接调用 connection.setAutoCommit(false) 开启事务调用目标方法若无异常,执行 commit;否则 rollback清理资源,释放连接

这一切,背后的关键类是:

TransactionInterceptor(事务拦截器)DataSourceTransactionManager(事务管理器)TransactionSynchronizationManager(事务同步器)

而这些类本身,并不负责数据一致性

它们只是告诉数据库该干什么,真正的数据安全,是数据库层做的。

假设你用的是一个不支持事务的数据库(比如一些 NoSQL 数据库),你在方法上加再多的 @Transactional 都没用。

Spring 调用 setAutoCommit(false) 报错调用 rollback 没效果数据库根本没有 redo log,无法回滚!

所以说到底:

我们不能把“事务的一切”都归功于Spring。

回到我的面试现场,当我听完面试官的一句话之后,感觉就像是被打通了任督二脉。

他说:

“真正能保障事务一致性的,是数据库引擎内部对日志的使用。而 Spring,只是帮你把这些逻辑用优雅的方式封装了一下。”

听懂这句话,才算是“真正理解了Spring事务”。

如果你也在准备 Java 后端社招,这些点一定要掌握:

1. Spring事务的三种方式:

编程式事务(繁琐,灵活)声明式事务(常用,基于注解)XML配置事务(古早风格)

2. 核心类和接口:

PlatformTransactionManagerDataSourceTransactionManagerTransactionDefinitionTransactionStatusTransactionInterceptor

3. 数据库事务的实现:

redo log:持久化保证undo log:回滚保证binlog:主从/恢复记录

4. 常见面试深入问题:

现在回头看,很多技术我们以为懂了,其实只是“听懂了名词,没理解机制”。

就像 Spring 事务。

它的本质,其实就是你和数据库的一场“双人舞”。

Spring负责指挥,数据库负责执行。没有 redo log、undo log、binlog 的支持,Spring只是“空喊口号”。

希望这篇文章,能帮你真正理解事务背后的那些机制,也希望你下次面试能“打到核心”。

如果你喜欢这类“故事+技术”的风格,点个在看或者转发给你的技术伙伴吧,我们一起成长!

来源:沛菡教育

相关推荐