各位java大侠,上回我们聊了springboot事务的“表面功夫”,今天咱们来个深度解剖,看看当你潇洒地写下@transactional时,springboot在背后到底干了多少“脏活累活”。准备好你的ide,咱们一起开启源码之旅!🚀
第一章:@transactional的“前世今生”——注解解析全流程 📖
1.1 注解的“出生证明”
当你写@transactional时,spring是怎么知道要处理它的?
关键类:transactioninterceptor、annotationtransactionattributesource、beanfactorytransactionattributesourceadvisor
// 1. 首先,spring启动时,@enabletransactionmanagement注解开启事务支持
@target(elementtype.type)
@retention(retentionpolicy.runtime)
@import(transactionmanagementconfigurationselector.class)
public @interface enabletransactionmanagement {
// 代理模式:cglib 还是 jdk动态代理?
advicemode mode() default advicemode.proxy;
// 代理顺序
int order() default ordered.lowest_precedence;
}执行流程:
// 简化版调用链 1. 容器启动 → @enabletransactionmanagement生效 2. → 注册 infrastructureadvisorautoproxycreator(aop代理创建器) 3. → 扫描所有bean,找@transactional注解的方法 4. → 创建代理对象,将transactioninterceptor作为增强 5. → 调用代理方法时,进入transactioninterceptor.invoke()
1.2 transactioninterceptor的核心invoke()方法
这是事务的总入口,让我们看看它的真面目:
// org.springframework.transaction.interceptor.transactioninterceptor
public class transactioninterceptor extends transactionaspectsupport
implements methodinterceptor, serializable {
@override
public object invoke(methodinvocation invocation) throws throwable {
// 获取目标类
class<?> targetclass = (invocation.getthis() != null ?
aoputils.gettargetclass(invocation.getthis()) : null);
// 关键!调用父类的invokewithintransaction方法
return invokewithintransaction(
invocation.getmethod(), // 被调用的方法
targetclass, // 目标类
invocation::proceed // 实际要执行的业务方法
);
}
}第二章:invokewithintransaction——事务的“心脏” ❤️
这才是真正的事务处理核心,代码在父类transactionaspectsupport中:
// org.springframework.transaction.interceptor.transactionaspectsupport
protected object invokewithintransaction(method method,
@nullable class<?> targetclass,
final invocationcallback invocation) throws throwable {
// 1️⃣ 获取事务属性(@transactional注解的配置)
transactionattributesource tas = gettransactionattributesource();
final transactionattribute txattr = (tas != null ?
tas.gettransactionattribute(method, targetclass) : null);
// 2️⃣ 确定事务管理器
final platformtransactionmanager tm = determinetransactionmanager(txattr);
// 3️⃣ 构造方法标识(用于日志和监控)
final string joinpointidentification = methodidentification(method, targetclass, txattr);
// 4️⃣ 声明式事务处理
if (txattr == null || !(tm instanceof callbackpreferringplatformtransactionmanager)) {
// 🔥 关键!获取事务状态
transactioninfo txinfo = createtransactionifnecessary(tm, txattr, joinpointidentification);
object retval = null;
try {
// 5️⃣ 执行真正的业务逻辑
retval = invocation.proceedwithinvocation();
}
catch (throwable ex) {
// 6️⃣ 异常处理:回滚或提交
completetransactionafterthrowing(txinfo, ex);
throw ex;
}
finally {
// 7️⃣ 清理线程绑定的资源
cleanuptransactioninfo(txinfo);
}
// 8️⃣ 提交事务
committransactionafterreturning(txinfo);
return retval;
}
else {
// 编程式事务处理(略)
}
}第三章:createtransactionifnecessary——事务的“诞生” 👶
这个方法决定了是否创建新事务、如何传播事务:
// transactionaspectsupport.createtransactionifnecessary
protected transactioninfo createtransactionifnecessary(
@nullable platformtransactionmanager tm,
@nullable transactionattribute txattr,
final string joinpointidentification) {
// 如果transaction属性为空,则创建一个空事务
if (txattr == null || !(tm instanceof callbackpreferringplatformtransactionmanager)) {
// 1. 获取现有事务(可能为null)
transactionstatus status = null;
if (txattr != null) {
if (tm != null) {
// 🔥 关键!调用事务管理器的gettransaction方法
status = tm.gettransaction(txattr);
}
}
// 2. 准备事务信息
return preparetransactioninfo(tm, txattr, joinpointidentification, status);
}
// ...
}3.1 tm.gettransaction()——传播行为的实现
这是各种传播行为的实现核心,在abstractplatformtransactionmanager中:
// abstractplatformtransactionmanager.gettransaction
public final transactionstatus gettransaction(@nullable transactiondefinition definition)
throws transactionexception {
// 1. 获取事务定义(没有则用默认值)
transactiondefinition def = (definition != null ? definition :
transactiondefinition.withdefaults());
// 2. 🔥 获取现有事务(检查当前线程是否已有事务)
object transaction = dogettransaction();
// 3. 如果当前已存在事务
if (isexistingtransaction(transaction)) {
// 🔥 处理嵌套事务的情况
return handleexistingtransaction(def, transaction, debugenabled);
}
// 4. 检查超时设置
if (def.gettimeout() < transactiondefinition.timeout_default) {
throw new invalidtimeoutexception(...);
}
// 5. 当前没有事务,但需要事务(required, requires_new等)
if (def.getpropagationbehavior() == transactiondefinition.propagation_mandatory) {
throw new illegaltransactionstateexception(...);
}
else if (def.getpropagationbehavior() == transactiondefinition.propagation_required ||
def.getpropagationbehavior() == transactiondefinition.propagation_requires_new ||
def.getpropagationbehavior() == transactiondefinition.propagation_nested) {
// 🔥 关键!挂起null事务(因为当前没有事务)
suspendedresourcesholder suspendedresources = suspend(null);
try {
// 6. 开始新事务
return starttransaction(def, transaction, debugenabled, suspendedresources);
}
catch (runtimeexception | error ex) {
resume(null, suspendedresources);
throw ex;
}
}
else {
// 7. 当前不需要事务(propagation_supports等)
boolean newsynchronization = (gettransactionsynchronization() == synchronization_always);
return preparetransactionstatus(def, null, true, newsynchronization, debugenabled, null);
}
}3.2 传播行为的核心:handleexistingtransaction()
让我们看看不同传播行为在已有事务时的处理:
// abstractplatformtransactionmanager.handleexistingtransaction
private transactionstatus handleexistingtransaction(
transactiondefinition definition, object transaction, boolean debugenabled)
throws transactionexception {
// 1. never:不能有事务,有就抛异常
if (definition.getpropagationbehavior() == transactiondefinition.propagation_never) {
throw new illegaltransactionstateexception(...);
}
// 2. not_supported:不支持事务,挂起当前事务
if (definition.getpropagationbehavior() == transactiondefinition.propagation_not_supported) {
object suspendedresources = suspend(transaction);
boolean newsynchronization = (gettransactionsynchronization() == synchronization_always);
return preparetransactionstatus(
definition, null, false, newsynchronization, debugenabled, suspendedresources);
}
// 3. requires_new:挂起当前事务,创建新事务
if (definition.getpropagationbehavior() == transactiondefinition.propagation_requires_new) {
// 挂起当前事务
suspendedresourcesholder suspendedresources = suspend(transaction);
try {
// 开始新事务
return starttransaction(definition, transaction, debugenabled, suspendedresources);
}
catch (runtimeexception | error beginex) {
resumeafterbeginexception(transaction, suspendedresources, beginex);
throw beginex;
}
}
// 4. nested:嵌套事务
if (definition.getpropagationbehavior() == transactiondefinition.propagation_nested) {
if (!isnestedtransactionallowed()) {
throw new nestedtransactionnotsupportedexception(...);
}
// 使用保存点(savepoint)实现
if (usesavepointfornestedtransaction()) {
// 创建保存点
defaulttransactionstatus status = preparetransactionstatus(
definition, transaction, false, false, debugenabled, null);
status.createandholdsavepoint();
return status;
}
else {
// 有些数据库不支持保存点,只能开启新事务
return starttransaction(definition, transaction, debugenabled, null);
}
}
// 5. 其他(required, supports, mandatory):加入当前事务
if (isvalidateexistingtransaction()) {
// 验证隔离级别、只读等设置是否匹配
}
boolean newsynchronization = (gettransactionsynchronization() != synchronization_never);
return preparetransactionstatus(
definition, transaction, false, newsynchronization, debugenabled, null);
}第四章:starttransaction——开启事务的“魔法” 🪄
真正的事务开启在这里:
// datasourcetransactionmanager(具体实现)
@override
protected void dobegin(object transaction, transactiondefinition definition) {
datasourcetransactionobject txobject = (datasourcetransactionobject) transaction;
connection con = null;
try {
// 1. 如果还没有连接,从数据源获取
if (!txobject.hasconnectionholder() ||
txobject.getconnectionholder().issynchronizedwithtransaction()) {
connection newcon = obtaindatasource().getconnection();
txobject.setconnectionholder(new connectionholder(newcon), true);
}
// 2. 设置连接属性
txobject.getconnectionholder().setsynchronizedwithtransaction(true);
con = txobject.getconnectionholder().getconnection();
// 3. 🔥 关键!设置隔离级别
integer previousisolationlevel = datasourceutils.prepareconnectionfortransaction(
con, definition);
txobject.setpreviousisolationlevel(previousisolationlevel);
// 4. 🔥 关键!关闭自动提交
if (con.getautocommit()) {
txobject.setmustrestoreautocommit(true);
con.setautocommit(false); // 就是这一行!
}
// 5. 准备事务连接
preparetransactionalconnection(con, definition);
// 6. 设置事务状态
txobject.getconnectionholder().settransactionactive(true);
// 7. 设置超时
int timeout = determinetimeout(definition);
if (timeout != transactiondefinition.timeout_default) {
txobject.getconnectionholder().settimeoutinseconds(timeout);
}
// 8. 绑定到当前线程
if (txobject.isnewconnectionholder()) {
transactionsynchronizationmanager.bindresource(
obtaindatasource(), txobject.getconnectionholder());
}
} catch (throwable ex) {
// 异常处理
datasourceutils.releaseconnection(con, obtaindatasource());
throw new cannotcreatetransactionexception(...);
}
}看到第4步的con.setautocommit(false)了吗?这就是spring事务的基石!没有它,每个sql都会自动提交,就无法回滚了。
第五章:committransactionafterreturning——提交的“艺术” 🎨
业务方法执行成功后,提交事务:
// transactionaspectsupport.committransactionafterreturning
protected void committransactionafterreturning(@nullable transactioninfo txinfo) {
if (txinfo != null && txinfo.gettransactionstatus() != null) {
txinfo.gettransactionmanager().commit(txinfo.gettransactionstatus());
}
}
// abstractplatformtransactionmanager.commit
public final void commit(transactionstatus status) throws transactionexception {
// 1. 检查事务是否已完成
if (status.iscompleted()) {
throw new illegaltransactionstateexception(...);
}
defaulttransactionstatus defstatus = (defaulttransactionstatus) status;
// 2. 如果标记了回滚,则回滚
if (defstatus.islocalrollbackonly()) {
processrollback(defstatus, false);
return;
}
// 3. 检查是否需要全局回滚
if (!shouldcommitonglobalrollbackonly() &&
defstatus.isglobalrollbackonly()) {
processrollback(defstatus, true);
return;
}
// 4. 🔥 真正的提交
processcommit(defstatus);
}5.1 processcommit——真正的提交
// abstractplatformtransactionmanager.processcommit
private void processcommit(defaulttransactionstatus status) throws transactionexception {
try {
boolean beforecompletioninvoked = false;
try {
// 1. 触发提交前回调
prepareforcommit(status);
triggerbeforecommit(status);
triggerbeforecompletion(status);
beforecompletioninvoked = true;
// 2. 如果有保存点(嵌套事务)
if (status.hassavepoint()) {
status.releaseheldsavepoint(); // 释放保存点,但不提交
return;
}
// 3. 如果是新事务,才真正提交
if (status.isnewtransaction()) {
docommit(status); // 🔥 调用数据源提交
}
// 4. 如果是全局回滚
else if (status.isglobalrollbackonly()) {
unexpectedrollback = true;
}
}
catch (unexpectedrollbackexception ex) {
// 异常处理
}
finally {
// 5. 清理资源
cleanupaftercompletion(status);
}
}
finally {
// ...
}
}5.2 datasourcetransactionmanager.docommit()
// datasourcetransactionmanager.docommit
@override
protected void docommit(defaulttransactionstatus status) {
datasourcetransactionobject txobject = (datasourcetransactionobject) status.gettransaction();
connection con = txobject.getconnectionholder().getconnection();
try {
con.commit(); // 🔥 jdbc提交!
} catch (sqlexception ex) {
throw new transactionsystemexception("could not commit jdbc transaction", ex);
}
}第六章:completetransactionafterthrowing——回滚的“学问” 🔄
业务方法抛出异常时,决定是否回滚:
// transactionaspectsupport.completetransactionafterthrowing
protected void completetransactionafterthrowing(@nullable transactioninfo txinfo, throwable ex) {
// 1. 必须要有事务才需要回滚
if (txinfo != null && txinfo.gettransactionstatus() != null) {
// 2. 🔥 关键!判断是否应该回滚
if (txinfo.transactionattribute != null &&
txinfo.transactionattribute.rollbackon(ex)) {
try {
// 3. 执行回滚
txinfo.gettransactionmanager().rollback(txinfo.gettransactionstatus());
}
catch (transactionsystemexception ex2) {
ex2.initapplicationexception(ex);
throw ex2;
}
}
else {
// 4. 不应该回滚,则提交
try {
txinfo.gettransactionmanager().commit(txinfo.gettransactionstatus());
}
catch (transactionsystemexception ex2) {
ex2.initapplicationexception(ex);
throw ex2;
}
}
}
}6.1 rollbackon()——回滚判断逻辑
// rulebasedtransactionattribute.rollbackon
@override
public boolean rollbackon(throwable ex) {
// 1. 遍历所有回滚规则
for (rollbackruleattribute rule : this.rollbackrules) {
// 2. 检查异常是否匹配
if (rule.getdepth(ex) >= 0) {
return true; // 匹配,需要回滚
}
}
// 3. 默认:runtimeexception和error回滚,checkedexception不❌
return (ex instanceof runtimeexception || ex instanceof error);
}这就是为什么默认情况下,ioexception等checked exception不回滚的原因!
第七章:threadlocal的妙用——事务资源绑定 🧵
spring如何保证同一个线程内,多个dao操作用同一个连接?
核心类:transactionsynchronizationmanager
// 内部使用threadlocal存储资源
public abstract class transactionsynchronizationmanager {
private static final threadlocal<map<object, object>> resources =
new namedthreadlocal<>("transactional resources");
private static final threadlocal<set<transactionsynchronization>> synchronizations =
new namedthreadlocal<>("transaction synchronizations");
private static final threadlocal<string> currenttransactionname =
new namedthreadlocal<>("current transaction name");
private static final threadlocal<boolean> currenttransactionreadonly =
new namedthreadlocal<>("current transaction read-only status");
private static final threadlocal<integer> currenttransactionisolationlevel =
new namedthreadlocal<>("current transaction isolation level");
private static final threadlocal<boolean> actualtransactionactive =
new namedthreadlocal<>("actual transaction active");
// 绑定资源到当前线程
public static void bindresource(object key, object value) throws illegalstateexception {
map<object, object> map = resources.get();
if (map == null) {
map = new hashmap<>();
resources.set(map);
}
map.put(key, value);
}
// 从当前线程获取资源
public static object getresource(object key) {
map<object, object> map = resources.get();
if (map == null) {
return null;
}
return map.get(key);
}
}执行流程:
// 1. 事务开始时
connection con = datasource.getconnection();
transactionsynchronizationmanager.bindresource(datasource, con);
// 2. dao操作获取连接时
public static connection getconnection(datasource datasource) throws cannotgetjdbcconnectionexception {
// 先尝试从threadlocal获取
connectionholder conholder = (connectionholder)
transactionsynchronizationmanager.getresource(datasource);
if (conholder != null) {
return conholder.getconnection(); // ✅ 返回事务连接
}
// 没有事务,新建连接
return datasource.getconnection();
}
// 3. 事务结束时
transactionsynchronizationmanager.unbindresource(datasource);第八章:自调用失效的“终极揭秘” 🔍
现在你明白为什么自调用事务不生效了吗?
@service
public class userservice {
public void outermethod() {
// 直接调用内部方法
this.innermethod(); // ❌ 事务不生效!
}
@transactional
public void innermethod() {
// 业务逻辑
}
}原因:
- spring事务基于aop代理
- 只有通过代理对象调用,才会被
transactioninterceptor拦截 this.innermethod()是目标对象内部调用,不会经过代理- 因此
transactioninterceptor.invoke()不会执行
图解:
正常调用:controller → 代理对象 → transactioninterceptor → 目标对象 自调用:目标对象 → 目标对象(绕过了代理和拦截器!)
第九章:调试技巧——亲眼看看事务流转 🔬
9.1 开启调试日志
# application.yml
logging:
level:
org.springframework.transaction: debug
org.springframework.jdbc.datasource.datasourcetransactionmanager: debug
org.springframework.orm.jpa: debug9.2 观察日志输出
debug o.s.j.d.datasourcetransactionmanager: creating new transaction with name [com.example.userservice.saveuser]: propagation_required,isolation_default debug o.s.j.d.datasourcetransactionmanager: acquired connection [conn-id] for jdbc transaction debug o.s.j.d.datasourcetransactionmanager: switching jdbc connection [conn-id] to manual commit debug o.s.j.d.datasourcetransactionmanager: initiating transaction commit debug o.s.j.d.datasourcetransactionmanager: committing jdbc transaction on connection [conn-id] debug o.s.j.d.datasourcetransactionmanager: releasing jdbc connection [conn-id] after transaction
9.3 在关键方法打断点
transactioninterceptor.invoke()transactionaspectsupport.invokewithintransaction()abstractplatformtransactionmanager.gettransaction()datasourcetransactionmanager.dobegin()datasourcetransactionmanager.docommit()/dorollback()
第十章:手写一个简化版事务管理器(理解原理) 🛠️
理解了原理,让我们手写一个极简版:
// 1. 事务管理器
public class simpletransactionmanager {
private static threadlocal<connection> connectionholder = new threadlocal<>();
private static threadlocal<boolean> transactionactive = threadlocal.withinitial(() -> false);
public static void begin() throws sqlexception {
if (transactionactive.get()) {
return; // 已存在事务,支持传播
}
connection conn = datasourceutils.getconnection();
conn.setautocommit(false); // 关键!
connectionholder.set(conn);
transactionactive.set(true);
}
public static void commit() throws sqlexception {
if (!transactionactive.get()) {
return;
}
connection conn = connectionholder.get();
conn.commit();
conn.setautocommit(true);
conn.close();
connectionholder.remove();
transactionactive.set(false);
}
public static void rollback() throws sqlexception {
if (!transactionactive.get()) {
return;
}
connection conn = connectionholder.get();
conn.rollback();
conn.setautocommit(true);
conn.close();
connectionholder.remove();
transactionactive.set(false);
}
public static connection getconnection() {
return connectionholder.get();
}
}
// 2. 事务注解
@retention(retentionpolicy.runtime)
@target(elementtype.method)
public @interface simpletransactional {
class<? extends throwable>[] rollbackfor() default {runtimeexception.class};
}
// 3. 动态代理处理器
public class transactionproxy implements invocationhandler {
private object target;
public transactionproxy(object target) {
this.target = target;
}
@override
public object invoke(object proxy, method method, object[] args) throws throwable {
method targetmethod = target.getclass().getmethod(method.getname(),
method.getparametertypes());
// 检查是否有@simpletransactional注解
if (targetmethod.isannotationpresent(simpletransactional.class)) {
simpletransactional annotation = targetmethod.getannotation(simpletransactional.class);
try {
// 开启事务
simpletransactionmanager.begin();
// 执行业务方法
object result = method.invoke(target, args);
// 提交事务
simpletransactionmanager.commit();
return result;
} catch (throwable e) {
// 判断是否需要回滚
for (class<? extends throwable> rollbackex : annotation.rollbackfor()) {
if (rollbackex.isassignablefrom(e.getclass())) {
simpletransactionmanager.rollback();
break;
}
}
throw e;
}
} else {
return method.invoke(target, args);
}
}
}总结:事务的完整生命周期 🌀
- 代理创建:spring容器启动时,为
@transactional标注的bean创建代理 - 方法调用:通过代理调用方法,进入
transactioninterceptor.invoke() - 获取属性:解析
@transactional注解的配置 - 决策事务:根据传播行为,决定新建、加入还是挂起事务
- 开启事务:获取数据库连接,设置
autocommit=false - 执行业务:调用原始业务方法
- 异常处理:根据异常类型决定回滚或提交
- 提交/回滚:提交事务或回滚事务
- 清理资源:关闭连接,清理threadlocal
最后的思考 🤔
通过源码分析,我们发现springboot事务的本质是:
- 基于aop的拦截
- 基于threadlocal的资源管理
- 基于jdbc connection的autocommit控制
理解了这些,你就能:
- 解释为什么自调用失效
- 理解传播行为的底层实现
- 知道事务同步管理器的工作原理
- 调试复杂的事务问题
- 甚至自己实现一个简单的事务框架
下次遇到事务问题,不要只是重启应用,打开调试日志,跟踪源码,你会发现每个异常背后,都有一个清晰的逻辑链。这就是从“会用框架”到“懂框架”的蜕变!🦋
源码如诗,每一行都藏着智慧。读懂了它,你就读懂了springboot的灵魂。 📚
(现在,你可以自信地在团队分享:“我知道@transactional的每一行代码在做什么!” 这种感觉,比加薪还棒!💰😄)
到此这篇关于springboot事务源码从注解到数据库的“奇幻漂流”的文章就介绍到这了,更多相关springboot事务源码内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论