摘要: 在 的自動裝配事務裡面, , ,`PlatformTransactionManager InfrastructureAdvisorAutoProxyCreator TransactionInterceptor Spring`事務的核心角色。 支撐著整個事務功能的架構,邏輯還是相對複雜的,那麼 ...
摘要:
在springboot
的自動裝配事務裡面,InfrastructureAdvisorAutoProxyCreator
,TransactionInterceptor
,PlatformTransactionManager
這三個bean都被裝配進來了,InfrastructureAdvisorAutoProxyCreator
已經講過了,就是一個後置處理器,並且優先順序不是很高,而是最低,今天的重點是講解後面兩者之間在事務的扮演角色。TransactionInterceptor
作為事務的增強子,扮演著增強處理Spring
事務的核心角色。
TransactionInterceptor
支撐著整個事務功能的架構,邏輯還是相對複雜的,那麼現在我們切入正題來分析此攔截器是如何實現事務特性的。
Spring事務三大介面
TransactionDefinition:用於描述隔離級別、超時時間、是否為只讀事務和事務傳播規則
public interface TransactionDefinition {
int PROPAGATION_REQUIRED = 0;
int PROPAGATION_SUPPORTS = 1;
int PROPAGATION_MANDATORY = 2;
int PROPAGATION_REQUIRES_NEW = 3;
int PROPAGATION_NOT_SUPPORTED = 4;
int PROPAGATION_NEVER = 5;
int PROPAGATION_NESTED = 6;
int ISOLATION_DEFAULT = -1;
int ISOLATION_READ_UNCOMMITTED = 1;
int ISOLATION_READ_COMMITTED = 2;
int ISOLATION_REPEATABLE_READ = 4;
int ISOLATION_SERIALIZABLE = 8;
int TIMEOUT_DEFAULT = -1;
}
TransactionStatus:代表一個事務的具體運行狀態、以及保存點
public interface TransactionStatus extends SavepointManager, Flushable {
// 判斷當前的事務是否是新事務
boolean isNewTransaction();
// 判斷該事務裡面是否含有保存點
boolean hasSavepoint();
// 這是事務的唯一結果是否進行回滾。因此如果你在外層給try catche住不讓事務回滾,就會拋出你可能常見的異常
void setRollbackOnly();
boolean isRollbackOnly();
void flush();
// 不管是commit或者rollback了都算結束了~~~
boolean isCompleted();
}
一般都是使用它的實現類DefaultTransactionStatus
,它是Spring預設使用的事務狀態。
PlatformTransactionManager:一個高層次的介面,看名字就知道是管理事務的
public interface PlatformTransactionManager {
TransactionStatus getTransaction(@Nullable TransactionDefinition var1) throws TransactionException;
void commit(TransactionStatus var1) throws TransactionException;
void rollback(TransactionStatus var1) throws TransactionException;
}
事務攔截器
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable {
public TransactionInterceptor() {
}
public TransactionInterceptor(PlatformTransactionManager ptm, Properties attributes) {
this.setTransactionManager(ptm);
this.setTransactionAttributes(attributes);
}
public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) {
this.setTransactionManager(ptm);
this.setTransactionAttributeSource(tas);
}
//最重要的方法,攔截入口
@Nullable
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> targetClass = invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null;
Method var10001 = invocation.getMethod();
invocation.getClass();
return this.invokeWithinTransaction(var10001, targetClass, invocation::proceed);
}
//省略無關代碼......
}
我們已經知道了,它是個MethodInterceptor
,被事務攔截的方法最終都會執行到此增強器身上。
MethodInterceptor
是個環繞通知,敲好符合我們的開啟、提交、回滾事務等操作,源碼分析可以看出,真正做事情的其實還是在父類,它有一個執行事務的模版。
TransactionAspectSupport
public abstract class TransactionAspectSupport implements BeanFactoryAware, InitializingBean {
private static final Object DEFAULT_TRANSACTION_MANAGER_KEY = new Object();
// currentTransactionStatus() 方法需要使用到它
private static final ThreadLocal<TransactionAspectSupport.TransactionInfo> transactionInfoHolder = new NamedThreadLocal("Current aspect-driven transaction");
protected final Log logger = LogFactory.getLog(this.getClass());
//事務管理器的名稱
@Nullable
private String transactionManagerBeanName;
//事務管理器
@Nullable
private PlatformTransactionManager transactionManager;
//事務屬性源
@Nullable
private TransactionAttributeSource transactionAttributeSource;
@Nullable
private BeanFactory beanFactory;
// 因為事務管理器可能也會有多個 所以此處做了一個簡單的緩存~
private final ConcurrentMap<Object, PlatformTransactionManager> transactionManagerCache = new ConcurrentReferenceHashMap(4);
public TransactionAspectSupport() {
}
@Nullable
protected static TransactionAspectSupport.TransactionInfo currentTransactionInfo() throws NoTransactionException {
return (TransactionAspectSupport.TransactionInfo)transactionInfoHolder.get();
}
//外部調用此Static方法,可議獲取到當前事務的狀態 從而甚至可議手動來提交、回滾事務
public static TransactionStatus currentTransactionStatus() throws NoTransactionException {
TransactionAspectSupport.TransactionInfo info = currentTransactionInfo();
if (info != null && info.transactionStatus != null) {
return info.transactionStatus;
} else {
throw new NoTransactionException("No transaction aspect-managed TransactionStatus in scope");
}
}
//省略無關代碼......
// 這裡可以發現,若傳入的為Properties 內部是實際使用的是NameMatchTransactionAttributeSource 去匹配的,transactionAttributeSource會被覆蓋的喲
public void setTransactionAttributes(Properties transactionAttributes) {
NameMatchTransactionAttributeSource tas = new NameMatchTransactionAttributeSource();
tas.setProperties(transactionAttributes);
this.transactionAttributeSource = tas;
}
// 根據方法和目標類來選擇
public void setTransactionAttributeSources(TransactionAttributeSource... transactionAttributeSources) {
this.transactionAttributeSource = new CompositeTransactionAttributeSource(transactionAttributeSources);
}
//省略無關代碼......
// 接下來就只剩我們最為核心的處理事務的模版方法了
@Nullable
protected Object invokeWithinTransaction(Method method, @Nullable Class<?> targetClass,
final InvocationCallback invocation) throws Throwable {
// If the transaction attribute is null, the method is non-transactional.
// 獲取事務屬性源~
TransactionAttributeSource tas = getTransactionAttributeSource();
// 獲取該方法對應的事務屬性(這個特別重要)
// 不同的事務處理方式使用不同的邏輯。對於聲明式事務的處理與編程式事務的處理,重要區別在於事務屬性上,因為編程式的事務處理是不需要有事務屬性的
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
// 找到一個合適的事務管理器
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
// 拿到目標方法唯一標識
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 看是否有必要創建一個事務,根據`事務傳播行為`,做出相應的判斷
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
//回調方法執行,執行目標方法(原有的業務邏輯)
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
// target invocation exception
// 出現異常了,進行回滾(註意:並不是所有異常都會rollback的)
// 備註:此處若沒有事務屬性 會commit 相容編程式事務吧
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
//清除信息
cleanupTransactionInfo(txInfo);
}
// 目標方法完全執行完成後,提交事務~~~
commitTransactionAfterReturning(txInfo);
return retVal;
}
else {
//編程式事務處理(CallbackPreferringPlatformTransactionManager) 會走這裡
// 原理也差不太多,這裡不做詳解~~~~
final ThrowableHolder throwableHolder = new ThrowableHolder();
// It's a CallbackPreferringPlatformTransactionManager: pass a TransactionCallback in.
try {
Object result = ((CallbackPreferringPlatformTransactionManager) tm).execute(txAttr, status -> {
TransactionInfo txInfo = prepareTransactionInfo(tm, txAttr, joinpointIdentification, status);
try {
return invocation.proceedWithInvocation();
}
catch (Throwable ex) {
if (txAttr.rollbackOn(ex)) {
// A RuntimeException: will lead to a rollback.
if (ex instanceof RuntimeException) {
throw (RuntimeException) ex;
}
else {
throw new ThrowableHolderException(ex);
}
}
else {
// A normal return value: will lead to a commit.
throwableHolder.throwable = ex;
return null;
}
}
finally {
cleanupTransactionInfo(txInfo);
}
});
// Check result state: It might indicate a Throwable to rethrow.
if (throwableHolder.throwable != null) {
throw throwableHolder.throwable;
}
return result;
}
catch (ThrowableHolderException ex) {
throw ex.getCause();
}
catch (TransactionSystemException ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
ex2.initApplicationException(throwableHolder.throwable);
}
throw ex2;
}
catch (Throwable ex2) {
if (throwableHolder.throwable != null) {
logger.error("Application exception overridden by commit exception", throwableHolder.throwable);
}
throw ex2;
}
}
}
// 從容器中找到一個事務管理器
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
if (txAttr != null && this.beanFactory != null) {
// qualifier 就在此處發揮作用了,他就相當於BeanName
String qualifier = txAttr.getQualifier();
if (StringUtils.hasText(qualifier)) {
// 根據此名稱 以及PlatformTransactionManager.class 去容器內找
return this.determineQualifiedTransactionManager(this.beanFactory, qualifier); // 若沒有指定qualifier 那再看看是否指定了 transactionManagerBeanName
} else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return this.determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
} else {
// 若都沒指定,那就不管了。直接根據類型去容器里找 getBean(Class)
// 此處:若容器內有兩個PlatformTransactionManager ,那就鐵定會報錯啦~~~
PlatformTransactionManager defaultTransactionManager = this.getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = (PlatformTransactionManager)this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = (PlatformTransactionManager)this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
} else {
// 如果這兩個都沒配置,所以肯定是手動設置了PlatformTransactionManager的,那就直接返回即可
return this.getTransactionManager();
}
}
private PlatformTransactionManager determineQualifiedTransactionManager(BeanFactory beanFactory, String qualifier) {
PlatformTransactionManager txManager = (PlatformTransactionManager)this.transactionManagerCache.get(qualifier);
if (txManager == null) {
txManager = (PlatformTransactionManager)BeanFactoryAnnotationUtils.qualifiedBeanOfType(beanFactory, PlatformTransactionManager.class, qualifier);
this.transactionManagerCache.putIfAbsent(qualifier, txManager);
}
return txManager;
}
private String methodIdentification(Method method, @Nullable Class<?> targetClass, @Nullable TransactionAttribute txAttr) {
String methodIdentification = this.methodIdentification(method, targetClass);
if (methodIdentification == null) {
if (txAttr instanceof DefaultTransactionAttribute) {
methodIdentification = ((DefaultTransactionAttribute)txAttr).getDescriptor();
}
if (methodIdentification == null) {
methodIdentification = ClassUtils.getQualifiedMethodName(method, targetClass);
}
}
return methodIdentification;
}
@Nullable
protected String methodIdentification(Method method, @Nullable Class<?> targetClass) {
return null;
}
// 若有需要 創建一個TransactionInfo (具體的事務從事務管理器裡面getTransaction())
protected TransactionAspectSupport.TransactionInfo createTransactionIfNecessary(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, final String joinpointIdentification) {
//賦值
if (txAttr != null && ((TransactionAttribute)txAttr).getName() == null) {
txAttr = new DelegatingTransactionAttribute((TransactionAttribute)txAttr) {
public String getName() {
return joinpointIdentification;
}
};
}
// 從事務管理器里,通過txAttr拿出來一個TransactionStatus
TransactionStatus status = null;
if (txAttr != null) {
if (tm != null) {
status = tm.getTransaction((TransactionDefinition)txAttr);
} else if (this.logger.isDebugEnabled()) {
this.logger.debug("Skipping transactional joinpoint [" + joinpointIdentification + "] because no transaction manager has been configured");
}
}
// 通過TransactionStatus 等,轉換成一個通用的TransactionInfo
return this.prepareTransactionInfo(tm, (TransactionAttribute)txAttr, joinpointIdentification, status);
}
protected TransactionAspectSupport.TransactionInfo prepareTransactionInfo(@Nullable PlatformTransactionManager tm, @Nullable TransactionAttribute txAttr, String joinpointIdentification, @Nullable TransactionStatus status) {
//構造一個TransactionInfo
TransactionAspectSupport.TransactionInfo txInfo = new TransactionAspectSupport.TransactionInfo(tm, txAttr, joinpointIdentification);
if (txAttr != null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Getting transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
// 設置事務狀態
txInfo.newTransactionStatus(status);
} else if (this.logger.isTraceEnabled()) {
this.logger.trace("No need to create transaction for [" + joinpointIdentification + "]: This method is not transactional.");
}
// 這句話是最重要的,把生成的TransactionInfo並綁定到當前線程的ThreadLocal
txInfo.bindToThread();
return txInfo;
}
//比較簡單 只用用事務管理器提交事務即可~~~ 具體的實現邏輯在事務管理器的commit實現里~~
protected void commitTransactionAfterReturning(@Nullable TransactionAspectSupport.TransactionInfo txInfo) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "]");
}
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
}
}
protected void completeTransactionAfterThrowing(@Nullable TransactionAspectSupport.TransactionInfo txInfo, Throwable ex) {
if (txInfo != null && txInfo.getTransactionStatus() != null) {
if (this.logger.isTraceEnabled()) {
this.logger.trace("Completing transaction for [" + txInfo.getJoinpointIdentification() + "] after exception: " + ex);
}
// 如果有事務屬性了,那就調用rollbackOn看看這個異常需不需要回滾
if (txInfo.transactionAttribute != null && txInfo.transactionAttribute.rollbackOn(ex)) {
try {
txInfo.getTransactionManager().rollback(txInfo.getTransactionStatus());
} catch (TransactionSystemException var6) {
this.logger.error("Application exception overridden by rollback exception", ex);
var6.initApplicationException(ex);
throw var6;
} catch (Error | RuntimeException var7) {
this.logger.error("Application exception overridden by rollback exception", ex);
throw var7;
}
} else {
// 編程式事務沒有事務屬性,那就commit吧
try {
txInfo.getTransactionManager().commit(txInfo.getTransactionStatus());
} catch (TransactionSystemException var4) {
this.logger.error("Application exception overridden by commit exception", ex);
var4.initApplicationException(ex);
throw var4;
} catch (Error | RuntimeException var5) {
this.logger.error("Application exception overridden by commit exception", ex);
throw var5;
}
}
}
}
protected void cleanupTransactionInfo(@Nullable TransactionAspectSupport.TransactionInfo txInfo) {
if (txInfo != null) {
txInfo.restoreThreadLocalStatus();
}
}
private static class ThrowableHolderException extends RuntimeException {
public ThrowableHolderException(Throwable throwable) {
super(throwable);
}
public String toString() {
return this.getCause().toString();
}
}
private static class ThrowableHolder {
@Nullable
public Throwable throwable;
private ThrowableHolder() {
}
}
@FunctionalInterface
protected interface InvocationCallback {
Object proceedWithInvocation() throws Throwable;
}
protected final class TransactionInfo {
// 當前事務 的事務管理器
@Nullable
private final PlatformTransactionManager transactionManager;
// 當前事務 的事務屬性
@Nullable
private final TransactionAttribute transactionAttribute;
//joinpoint標識
private final String joinpointIdentification;
//當前事務 的TransactionStatus
@Nullable
private TransactionStatus transactionStatus;
// 重點就是這個oldTransactionInfo欄位
// 這個欄位保存了當前事務所在的`父事務`上下文的引用,構成了一個鏈,準確的說是一個有向無環圖
@Nullable
private TransactionAspectSupport.TransactionInfo oldTransactionInfo;
public TransactionInfo(@Nullable PlatformTransactionManager transactionManager, @Nullable TransactionAttribute transactionAttribute, String joinpointIdentification) {
this.transactionManager = transactionManager;
this.transactionAttribute = transactionAttribute;
this.joinpointIdentification = joinpointIdentification;
}
public PlatformTransactionManager getTransactionManager() {
Assert.state(this.transactionManager != null, "No PlatformTransactionManager set");
return this.transactionManager;
}
@Nullable
public TransactionAttribute getTransactionAttribute() {
return this.transactionAttribute;
}
public String getJoinpointIdentification() {
return this.joinpointIdentification;
}
//註意這個方法名,新的一個事務status
public void newTransactionStatus(@Nullable TransactionStatus status) {
this.transactionStatus = status;
}
@Nullable
public TransactionStatus getTransactionStatus() {
return this.transactionStatus;
}
public boolean hasTransaction() {
return this.transactionStatus != null;
}
//綁定當前正在處理的事務的所有信息到ThreadLocal
private void bindToThread() {
// 老的事務 先從線程中拿出來,再把新的(也就是當前)綁定進去~~~~~~
this.oldTransactionInfo = (TransactionAspectSupport.TransactionInfo)TransactionAspectSupport.transactionInfoHolder.get();
TransactionAspectSupport.transactionInfoHolder.set(this);
}
//當前事務處理完之後,恢復父事務上下文
private void restoreThreadLocalStatus() {
TransactionAspectSupport.transactionInfoHolder.set(this.oldTransactionInfo);
}
public String toString() {
return this.transactionAttribute != null ? this.transactionAttribute.toString() : "No transaction";
}
}
}
事務管理器
AbstractPlatformTransactionManager
可見它是對PlatformTransactionManager
的一個抽象實現。實現Spring的標準事務工作流
這個基類提供了以下工作流程處理:
- 確定如果有現有的事務;
- 應用適當的傳播行為;
- 如果有必要暫停和恢復事務;
- 提交時檢查rollback-only標記;
- 應用適當的修改當回滾(實際回滾或設置rollback-only);
觸發同步回調註冊(如果事務同步是激活的)
public abstract class AbstractPlatformTransactionManager implements PlatformTransactionManager, Serializable {
//始終激活事務同步(請參閱事務的傳播屬性~)
public static final int SYNCHRONIZATION_ALWAYS = 0;
//僅對實際事務(即,不針對由傳播導致的空事務)激活事務同步\不支持現有後端事務
public static final int SYNCHRONIZATION_ON_ACTUAL_TRANSACTION = 1;
//永遠不激活事務同步
public static final int SYNCHRONIZATION_NEVER = 2;
// 相當於把本類的所有的public static final的變數都收集到此處~~~~
private static final Constants constants = new Constants(AbstractPlatformTransactionManager.class);
// ===========預設值
private int transactionSynchronization = SYNCHRONIZATION_ALWAYS;
// 事務預設的超時時間 為-1表示不超時
private int defaultTimeout = TransactionDefinition.TIMEOUT_DEFAULT;
//Set whether nested transactions are allowed. Default is "false".
private boolean nestedTransactionAllowed = false;
// Set whether existing transactions should be validated before participating(參與、加入)
private boolean validateExistingTransaction = false;
//設置是否僅在參與事務`失敗後`將 現有事務`全局`標記為回滾 預設值是true 需要註意~~~
// 表示只要你的事務失敗了,就標記此事務為rollback-only 表示它只能給與回滾 而不能再commit或者正常結束了
// 這個調用者經常會犯的一個錯誤就是:上層事務service拋出異常了,自己把它給try住,並且並且還不throw,那就肯定會報錯的:
// 報錯信息:Transaction rolled back because it has been marked as rollback-only
// 當然嘍,這個屬性強制不建議設置為false~~~~~~
private boolean globalRollbackOnParticipationFailure = true;
// 如果事務被全局標記為僅回滾,則設置是否及早失敗~~~~
private boolean failEarlyOnGlobalRollbackOnly = false;
// 設置在@code docommit調用失敗時是否應執行@code dorollback 通常不需要,因此應避免
private boolean rollbackOnCommitFailure = false;
// 我們發現使用起來有點枚舉的意思了,特別是用XML配置的時候 非常像枚舉的使用~~~~~~~
// 這也是Constants的重要意義~~~~
public final void setTransactionSynchronizationName(String constantName) {
setTransactionSynchronization(constants.asNumber(constantName).intValue());
}
public final void setTransactionSynchronization(int transactionSynchronization) {
this.transactionSynchronization = transactionSynchronization;
}
//... 省略上面所有欄位的一些get/set方法~~~
// 最為重要的一個方法,根據實物定義,獲取到一個事務TransactionStatus
@Override
public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException {
//doGetTransaction()方法是抽象方法,具體的實現由具體的事務處理器提供(下麵會以DataSourceTransactionManager為例子)
Object transaction = doGetTransaction();
//如果沒有配置事務屬性,則使用預設的事務屬性
if (definition == null) {
definition = new DefaultTransactionDefinition();
}
//檢查當前線程是否存在事務 isExistingTransaction此方法預設返回false 但子類都覆寫了此方法
if (isExistingTransaction(transaction)) {
// handleExistingTransaction方法為處理已經存在事務的情況
// 這個方法的實現也很複雜,總之還是對一些傳播屬性進行解析,各種情況的考慮~~~~~ 如果有新事務產生 doBegin()就會被調用~~~~
return handleExistingTransaction(definition, transaction, debugEnabled);
}
// 超時時間的簡單校驗~~~~
if (definition.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) {
throw new InvalidTimeoutException("Invalid transaction timeout", definition.getTimeout());
}
// 處理事務屬性中配置的事務傳播特性==============
// PROPAGATION_MANDATORY 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常
if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) {
throw new IllegalTransactionStateException("No existing transaction found for transaction marked with propagation 'mandatory'");
}
//如果事務傳播特性為required、required_new或nested
else if (definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW ||
definition.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) {
// 掛起,但是doSuspend()由子類去實現~~~
// 掛起操作,觸發相關的掛起註冊的事件,把當前線程事物的所有屬性都封裝好,放到一個SuspendedResourcesHolder
// 然後清空清空一下`當前線程事務`
SuspendedResourcesHolder suspendedResources = suspend(null);
// 此處,開始創建事務~~~~~
try {
boolean newSynchronization = (getTransactionSynchronization() != SYNCHRONIZATION_NEVER);
// //創建一個新的事務狀態 就是new DefaultTransactionStatus() 把個屬性都賦值上
DefaultTransactionStatus status = newTransactionStatus(
definition, transaction, true, newSynchronization, debugEnabled, suspendedResources);
// 開始事務,抽象方法,由子類去實現~
doBegin(transaction, definition);
//初始化和同步事務狀態 是TransactionSynchronizationManager這個類 它內部維護了很多的ThreadLocal
prepareSynchronization(status, definition);
return status;
}
catch (RuntimeException | Error ex) {
//重新開始 doResume由子類去實現
resume(null, suspendedResources);
throw ex;
}
}
// 走到這裡 傳播屬性就是不需要事務的 那就直接創建一個
else {
boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS);
// 這個方法相當於先newTransactionStatus,再prepareSynchronization這兩步~~~
// 顯然和上面的區別是:中間不回插入調用doBegin()方法,因為沒有事務 begin個啥~~
return prepareTransactionStatus(definition, null, true, newSynchronization, debugEnabled, null);
}
}
// 再看看commit方法
@Override
public final void commit(TransactionStatus status) throws TransactionException {
//如果是一個已經完成的事物,不可重覆提交
if (status.isCompleted()) {
throw new IllegalTransactionStateException("Transaction is already completed - do not call commit or rollback more than once per transaction");
}
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
// 如果已經標記為了需要回滾,那就執行回滾吧
if (defStatus.isLocalRollbackOnly()) {
processRollback(defStatus, false);
return;
}
// shouldCommitOnGlobalRollbackOnly這個預設值是false,目前只有JTA事務覆寫成true了
// isGlobalRollbackOnly:是否標記為了全局的RollbackOnly
if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
processRollback(defStatus, true);
return;
}
// 提交事務 這裡面還是挺複雜的,會考慮到還原點、新事務、事務是否是rollback-only之類的~~
processCommit(defStatus);
}
// rollback方法 裡面doRollback方法交給子類去實現~~~
@Override
public final void rollback(TransactionStatus status) throws TransactionException {
DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
processRollback(defStatus, false);
}
}
從這個抽象類源碼分析可以看出,它絕對是一個非常非常典型的模版實現,各個方法實現都是這樣。自己先提供實現模版,很多具體的實現方案都開放給子類,比如begin
,suspend
, resume
,commit
,rollback
等,相當於留好了眾多的連接點
DataSourceTransactionManager
// 它還實現了ResourceTransactionManager介面,提供了getResourceFactory()方法
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager implements ResourceTransactionManager, InitializingBean {
// 顯然它管理的就是DataSource 而JTA分散式事務管理可能就是各種各樣的數據源了
@Nullable
private DataSource dataSource;
// 不要強制標記為ReadOnly
private boolean enforceReadOnly = false;
// JDBC預設是允許內嵌的事務的
public DataSourceTransactionManager() {
setNestedTransactionAllowed(true);
}
public DataSourceTransactionManager(DataSource dataSource) {
this();
setDataSource(dataSource);
// 它自己的InitializingBean也是做了一個簡單的校驗而已~~~
afterPropertiesSet();
}
// 手動設置數據源
public void setDataSource(@Nullable DataSource dataSource) {
// 這步處理有必要
// TransactionAwareDataSourceProxy是對dataSource 的包裝
if (dataSource instanceof TransactionAwareDataSourceProxy) {
this.dataSource = ((TransactionAwareDataSourceProxy) dataSource).getTargetDataSource();
} else {
this.dataSource = dataSource;
}
}
//Return the JDBC DataSource
@Nullable
public DataSource getDataSource() {
return this.dataSource;
}
// @since 5.0 Spring5.0提供的方法 其實還是調用的getDataSource() 判空了而已
protected DataSource obtainDataSource() {
DataSource dataSource = getDataSource();
Assert.state(dataSource != null, "No DataSource set");
return dataSource;
}
// 直接返回的數據源~~~~
@Override
public Object getResourceFactory() {
return obtainDataSource();
}
...
// 這裡返回的是一個`DataSourceTransactionObject`
// 它是一個`JdbcTransactionObjectSupport`,所以它是SavepointManager、實現了SmartTransactionObject介面
@Override
protected Object doGetTransaction() {
DataSourceTransactionObject txObject = new DataSourceTransactionObject();
txObject.setSavepointAllowed(isNestedTransactionAllowed());
// 這個獲取有意思~~~~相當於按照線程來的~~~
ConnectionHolder conHolder = (ConnectionHolder) TransactionSynchronizationManager.getResource(obtainDataSource());
txObject.setConnectionHolder(conHolder, false);
return txObject;
}
// 檢查當前事務是否active
@Override
protected boolean isExistingTransaction(Object transaction) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
return (txObject.hasConnectionHolder() && txObject.getConnectionHolder().isTransactionActive());
}
// 這是一個核心內容了,裡面邏輯需要分析分析~~~
@Override
protected void doBegin(Object transaction, TransactionDefinition definition) {
DataSourceTransactionObject txObject = (DataSourceTransactionObject) transaction;
Connection con = null;
try {
if (!txObject.hasConnectionHolder() || txObject.getConnectionHolder().isSynchronizedWithTransaction()) {
// 從DataSource里獲取一個連接(這個DataSource一般是有連接池的~~~)
Connection newCon = obtainDataSource().getConnection();
// 把這個鏈接用ConnectionHolder包裝一下~~~
txObject.setConnectionHolder(new ConnectionHolder(newCon), true);
}
txObject.getConnectionHolder().setSynchronizedWithTransaction(true);
con = txObject.getConnectionHolder().getConnection();
// 設置isReadOnly、設置隔離界別等~
Integer previousIsolationLevel = DataSourceUtils.prepareConnectionForTransaction(con, definition);
txObject.setPreviousIsolationLevel(previousIsolationLevel);
// 這裡非常的關鍵,先看看Connection 是否是自動提交的
// 如果是 就con.setAutoCommit(false) 要不然資料庫預設沒執行一條SQL都是一個事務,就沒法進行事務的管理了
if (con.getAutoCommit()) {
txObject.setMustRestoreAutoCommit(true);
con.setAutoCommit(false);
}
// ====因此從這後面,通過此Connection執行的所有SQL語句只要沒有commit就都不會提交給資料庫的=====
// 這個方法特別特別有意思 它自己`Statement stmt = con.createStatement()`拿到一個Statement
// 然後執行了一句SQL:`stmt.executeUpdate("SET TRANSACTION READ ONLY");`
// 所以,所以:如果你僅僅只是查詢。把事務的屬性設置為readonly=true Spring對幫你對SQl進行優化的
// 需要註意的是:readonly=true 後,只能讀,不能進行dml操作)(只能看到設置事物前數據的變化,看不到設置事物後數據的改變)
prepareTransactionalConnection(con, definition);
txObject.getConnectionHolder().setTransactionActive(true);
int timeout = determineTimeout(definition);
if (timeout != TransactionDefinition.TIMEOUT_DEFAULT) {
txObject.getConnectionHolder().setTimeoutInSeconds(timeout);
}
// Bind the connection holder to the thread.
// 這一步:就是把當前的鏈接 和當前的線程進行綁定~~~~
if (txObject.isNewConnectionHolder()) {
TransactionSynchronizationManager.bindResource(obtainDataSource(), txObject.getConnectionHolder());
}
} catch (Throwable ex) {
// 如果是新創建的鏈接,那就釋放~~~~
if (txObject.isNewConnectionHolder()) {
DataSourceUtils.releaseConnection(con, obtainDataSource());
txObject.setConnectionHolder(null, false);
}
throw new CannotCreateTransactionException("Could not open JDBC Connection for transaction", ex);
}
}
// 真正提交事務
@Override
protected void doCommit(DefaultTransactionStatus status) { DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
// 拿到鏈接 然後直接就commit了
Connection con = txObject.getConnectionHolder().getConnection();
try {
con.commit();
} catch (SQLException ex) {
throw new TransactionSystemException("Could not commit JDBC transaction", ex);
}
}
//doRollback()方法也類似 這裡不再細說
}
小結:
事務屬性readonly=true
後,只能讀操作)(只能看到設置事物前數據的變化,看不到設置事物後數據的改變) 但是通過源碼我發現,你只設置@Transactional(readOnly = true)
這樣是不夠的,還必須在配置DataSourceTransactionManager
的時候,來這麼一句dataSourceTransactionManager.setEnforceReadOnly(true)
,最終才會對你的只讀事務進行優化~~~~
其實如果僅僅只是設置@Transactional(readOnly = true)
,最終會把這個Connection
設置為只讀:con.setReadOnly(true)
; 它表示將此連接設置為只讀模式,作為驅動程式啟用資料庫優化的提示。 將鏈接設置為只讀模式通知資料庫後,資料庫會對做自己的只讀優化。但是,這對資料庫而言不一定對於資料庫而言這就是readonly事務,這點是非常重要的。(因為畢竟一個事務內可能有多個鏈接.