docs/Spring全家桶/Spring源码分析/Spring事务/Spring事务(六):事务的隔离级别与传播方式的处理04.md
ǡĸ뼶봫ʽĴĵ 4 ƪģǼ
£
retVal = invocation.proceedWithInvocation();
ջõҵ UserService#insertIJ̽һùȥģҪ˽ù̵СԲο aop ز
쳣ķΪ TransactionAspectSupport#completeTransactionAfterThrowing£
protected void completeTransactionAfterThrowing(@Nullable TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// 쳣ϲŻع
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
}
catch (...) {
...
}
}
else {
try {
// 쳣ϣʹִгҲύ
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
catch (...) {
...
}
}
}
}
쳣ֱӽлعģҪж쳣ͣҪع쳣Żع
ж쳣ǷϵķΪ RuleBasedTransactionAttribute#rollbackOn
public boolean rollbackOn(Throwable ex) {
RollbackRuleAttribute winner = null;
int deepest = Integer.MAX_VALUE;
if (this.rollbackRules != null) {
for (RollbackRuleAttribute rule : this.rollbackRules) {
// ȡ쳣
int depth = rule.getDepth(ex);
// ʾǰ쳣Ҫع
if (depth >= 0 && depth < deepest) {
deepest = depth;
winner = rule;
}
}
}
if (winner == null) {
return super.rollbackOn(ex);
}
return !(winner instanceof NoRollbackRuleAttribute);
}
ȡķΪ RollbackRuleAttribute#getDepth(Throwable)£
public int getDepth(Throwable ex) {
return getDepth(ex.getClass(), 0);
}
private int getDepth(Class<?> exceptionClass, int depth) {
if (exceptionClass.getName().contains(this.exceptionName)) {
// Found it!
return depth;
}
// If we've gone as far as we can go and haven't found it...
if (exceptionClass == Throwable.class) {
return -1;
}
// ݹȡ
return getDepth(exceptionClass.getSuperclass(), depth + 1);
}
ʵֺܼǵݹȡ exception ĸ࣬ҵ˾ͷصݹĴҵ Throwableͷ - 1.
֮ʹжǷҪعԭûع쳣ʱ쳣ƣ
public @interface Transactional {
...
// עַ
String[] rollbackForClassName() default {};
}
˲ʹ ex instanceof Exception ķʽжܷع
RuleBasedTransactionAttribute#rollbackOn е RollbackRuleAttribute NoRollbackRuleAttribute ɶأ rollbackFor noRollbackFor İװ࣬ SpringTransactionAnnotationParser#parseTransactionAnnotation(AnnotationAttributes) ã£
protected TransactionAttribute parseTransactionAnnotation(AnnotationAttributes attributes) {
RuleBasedTransactionAttribute rbta = new RuleBasedTransactionAttribute();
...
// ع쳣
List<RollbackRuleAttribute> rollbackRules = new ArrayList<>();
for (Class<?> rbRule : attributes.getClassArray("rollbackFor")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("rollbackForClassName")) {
rollbackRules.add(new RollbackRuleAttribute(rbRule));
}
// ع쳣
for (Class<?> rbRule : attributes.getClassArray("noRollbackFor")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
for (String rbRule : attributes.getStringArray("noRollbackForClassName")) {
rollbackRules.add(new NoRollbackRuleAttribute(rbRule));
}
//
rbta.setRollbackRules(rollbackRules);
return rbta;
}
ع AbstractPlatformTransactionManager#rollback дݿĻع⣬һЩصǾͲˣֱӿؼĻع롣ǰķĴʱഫǻع PROPAGATION_NESTED ⣬ǻع㣬Ƿֱؼ룺
ع
عķΪ DataSourceTransactionManager#doRollbackյõ java.sql.Connection ķ
protected void doRollback(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// ȡӣConnection Ϊ java.sql.Connection
Connection con = txObject.getConnectionHolder().getConnection();
try {
con.rollback();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
}
}
ع عIJ AbstractTransactionStatus#rollbackToHeldSavepoint У
public void rollbackToHeldSavepoint() throws TransactionException {
Object savepoint = getSavepoint();
if (savepoint == null) {
throw new TransactionUsageException(...);
}
// ع
getSavepointManager().rollbackToSavepoint(savepoint);
// ͷű
getSavepointManager().releaseSavepoint(savepoint);
// Ϊnull
setSavepoint(null);
}
Ҫعͷű㡣
عIJ JdbcTransactionObjectSupport#rollbackToSavepoint
public void rollbackToSavepoint(Object savepoint) throws TransactionException {
ConnectionHolder conHolder = getConnectionHolderForSavepoint();
try {
conHolder.getConnection().rollback((Savepoint) savepoint);
conHolder.resetRollbackOnly();
}
catch (Throwable ex) {
throw new TransactionSystemException("Could not roll back to JDBC savepoint", ex);
}
}
ͷűIJ JdbcTransactionObjectSupport#releaseSavepoint
public void releaseSavepoint(Object savepoint) throws TransactionException {
ConnectionHolder conHolder = getConnectionHolderForSavepoint();
try {
conHolder.getConnection().releaseSavepoint((Savepoint) savepoint);
}
catch (Throwable ex) {
logger.debug("Could not explicitly release JDBC savepoint", ex);
}
}
նǵ java.sql.Connection ṩķɲ
ύύĴΪ
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
Ǹһֱ AbstractPlatformTransactionManager#processCommit
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
try {
...
try {
if (status.hasSavepoint()) {
...
unexpectedRollback = status.isGlobalRollbackOnly();
// 1\. ͷű
status.releaseHeldSavepoint();
}
else if (status.isNewTransaction()) {
...
unexpectedRollback = status.isGlobalRollbackOnly();
// 2\. ύ
doCommit(status);
}
else if (isFailEarlyOnGlobalRollbackOnly()) {
...
}
...
}
catch (...) {
...
}
}
finally {
// 3\. ɲָ(ָݿ)
cleanupAfterCompletion(status);
}
}
Ϸʡ˴룬 TransactionSynchronization صصģǾۼҪ
java.sql.Connection ṩķύֱӽմ룺DataSourceTransactionManager#doCommit
protected void doCommit(DefaultTransactionStatus status) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// ȡӣConnection Ϊ java.sql.Connection
Connection con = txObject.getConnectionHolder().getConnection();
try {
// ύ
con.commit();
}
catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
Ҳǵ java.sql.Connection ṩķ
ɲĴ AbstractPlatformTransactionManager#cleanupAfterCompletion
private void cleanupAfterCompletion(DefaultTransactionStatus status) {
status.setCompleted();
if (status.isNewSynchronization()) {
TransactionSynchronizationManager.clear();
}
if (status.isNewTransaction()) {
// ӣӣر
doCleanupAfterCompletion(status.getTransaction());
}
// йлָ
if (status.getSuspendedResources() != null) {
Object transaction = (status.hasTransaction() ? status.getTransaction() : null);
// ָ
resume(transaction, (SuspendedResourcesHolder) status.getSuspendedResources());
}
}
DataSourceTransactionManager#doCleanupAfterCompletion :
protected void doCleanupAfterCompletion(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
// ƳԴӵİϵ
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.unbindResource(obtainDataSource());
}
// ӣǽϢִָǰ״̬
Connection con = txObject.getConnectionHolder().getConnection();
try {
if (txObject.isMustRestoreAutoCommit()) {
con.setAutoCommit(true);
}
DataSourceUtils.resetConnectionAfterTransaction(
con, txObject.getPreviousIsolationLevel(), txObject.isReadOnly());
}
catch (Throwable ex) {
logger.debug("Could not reset JDBC Connection after transaction", ex);
}
// ӣر
if (txObject.isNewConnectionHolder()) {
// յõ java.sql.Connection#close
DataSourceUtils.releaseConnection(con, this.dataSource);
}
txObject.getConnectionHolder().clear();
}
ĻָҲ resume(...) յõ DataSourceTransactionManager#doResume £
@Override
protected void doResume(@Nullable Object transaction, Object suspendedResources) {
// Դݿ뵱ǰ̰߳
TransactionSynchronizationManager.bindResource(obtainDataSource(), suspendedResources);
}
һʱԴ֮ǰԴˡ
ijЩʽ£ PROPAGATION_REQUIRES_NEWҪǰȻµִɺҪָԭϢǽǰϢָΪϢֻǻָϢݿӲָ
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
// ŵǰʹõϢ
private static final ThreadLocal<TransactionInfo> transactionInfoHolder =
new NamedThreadLocal<>("Current aspect-driven transaction");
// ΪɵϢ
protected void cleanupTransactionInfo(@Nullable TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
/**
* TransactionInfo: Ϣ
*/
protected static final class TransactionInfo {
// ǰ״̬
@Nullable
private TransactionStatus transactionStatus;
// ɵϢҲǹϢ
@Nullable
private TransactionInfo oldTransactionInfo;
...
private void restoreThreadLocalStatus() {
// ΪɵϢ
transactionInfoHolder.set(this.oldTransactionInfo);
}
...
}
}
ԿTransactionInfo ԻһϢoldTransactionInfo ijԱûһϢʱֻǼؽ oldTransactionInfo õΪ transactionInfoHolder ThreadLocal
ύĴΪ TransactionAspectSupport#commitTransactionAfterReturning£
protected void commitTransactionAfterReturning(@Nullable TransactionInfo txInfo) {
// ж״̬
if (txInfo != null && txInfo.getTransactionStatus() != null) {
// ύǰѾ
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
ڸ÷Уֿд룺
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
Ѿ쳣ύзˣͲٷˡ
ԭӣhttps://my.oschina.net/funcy/blog/4947800 ߸ˮƽд֮ӭָԭףҵתϵȨҵתע