事務是你們用的最多的,也是比較關心的一個功能。本章就詳細講解spring-tx模塊中事務的實現與spring-boot事務的處理。可能這一節就會把spring-tx說完,事務沒有你們想象的那麼複雜。java
java的鏈接池,事務管理,持久層(MyBtais,hibernation)都是基於jdbc(Java DataBase Connectivity,java數據庫鏈接)進行演進的。那麼仔細看下下面的jdbc代碼,從而理解鏈接池,事務管理,持久層(MyBtais,hibernation)。mysql
import java.sql.Connection; import java.sql.DriverManager; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Random; public class Demo { public static void main(String[] args) { Connection conn = null; PreparedStatement ps = null; try { Class.forName("com.mysql.jdbc.Driver");// 1. 註冊驅動 conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/testjdbc","root","mysql"); // 2. 建立鏈接 con.setAutoCommit(false);// 3. 不自動提交,開始事務 conn.setReadOnly(true);// 4. 設定只讀,或者其餘鏈接設定 String sql = "insert into t_user(userName,pwd)values(?,?)"; // 須要執行的sql語句 ps = conn.prepareStatement( sql );// 5. 在不一樣的statement中設置須要執行的sql語句 ps.setObject(1, "小高" + i);// 6. 預編譯,參數設置 ps.setObject(2, "123"); ps.execute(); // 7. 執行語句 // 8. 若是是查詢插座,對查詢結果進行操做 con.commit(); // 9. 提交 } catch (ClassNotFoundException e) { con.rollback(); // 9, 回滾 e.printStackTrace(); } catch (SQLException e) { con.rollback(); // 9. 回滾 e.printStackTrace(); } finally{ try { if (ps!=null) { ps.close(); // 10. 資源釋放 } } catch (SQLException e) { e.printStackTrace(); } try { if (conn!=null) { conn.close(); // 10. 資源釋放 } } catch (SQLException e) { e.printStackTrace(); } } } }
鏈接池 | 事務管理器 | 持久 | |
---|---|---|---|
1 | 註冊驅動 | ||
2 | 建立鏈接 | ||
3 | 不自動提交,開始事務 | ||
4 | 設定只讀,或者其餘鏈接設定 | ||
5 | 在不一樣的statement中設置須要執行的sql語句 | ||
6 | 預編譯,參數設置 | ||
7 | 執行語句 | ||
8 | 若是是查詢操做,對查詢結果進行操做 | ||
9 | 提交或者回滾 | ||
10 | 資源釋放 | 資源釋放 |
// 時序圖spring
<! ------------------------- 無情分割線 --------------------------------------------------->sql
下面聲明瞭TransactionStatus的接口, 實現了TransactionStatus的抽象類AbstractTransactionStatus,還有AbstractTransactionStatus的子類DefaultTransactionStatus與內部類TransactionInfo,其實只須要TransactionInfo一個類就好了,上面幾個類的細節不講述了。數據庫
爲何spring-tx須要設計那麼多類了。其實就是爲了實現spring中一個很雞肋的功能,事務傳播功能。爲了實現事務傳播功能的設計,代碼還有不少,本人很是不喜歡這個功能,因此不會講述事務傳播的細節,若是有讀者想了解,能夠依據本接內容爲基本自行擴展。 爲何spring-tx須要設計那麼多類了。其實就是爲了實現spring中一個很雞肋的功能,事務傳播功能。爲了實現事務傳播功能的設計,代碼還有不少,本人很是不喜歡這個功能,因此不會講述事務傳播的細節,若是有讀者想了解,能夠依據本接內容爲基本自行擴展。 爲何spring-tx須要設計那麼多類了。其實就是爲了實現spring中一個很雞肋的功能,事務傳播功能。爲了實現事務傳播功能的設計,代碼還有不少,本人很是不喜歡這個功能,因此不會講述事務傳播的細節,若是有讀者想了解,能夠依據本接內容爲基本自行擴展。mybatis
public abstract class AbstractTransactionStatus implements TransactionStatus { private boolean rollbackOnly = false; private boolean completed = false; @Nullable private Object savepoint }
public class DefaultTransactionStatus extends AbstractTransactionStatus { @Nullable private final Object transaction; private final boolean newTransaction; private final boolean newSynchronization; private final boolean readOnly; private final boolean debug; @Nullable private final Object suspendedResources; }
protected final class TransactionInfo { @Nullable private final PlatformTransactionManager transactionManager; @Nullable private final TransactionAttribute transactionAttribute; private final String joinpointIdentification; @Nullable private TransactionStatus transactionStatus; @Nullable private TransactionInfo oldTransactionInfo; }
<! ------------------------- 無情分割線結束 --------------------------------------------------->框架
spring事務的核心體系是PlatformTransactionManager以及實現了DataSourceTransactionManager(數據源事務管理器,好比mybatis,spring-jdbc),JpaTransactionManager(Jpa事務管理器),HibernateTransactionManager(hibernate5事務管理器)。本節直接講解DataSourceTransactionManager,其餘的管理器使用場景很是少不作講解了。dom
public interface PlatformTransactionManager { TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException; void commit(TransactionStatus status) throws TransactionException; void rollback(TransactionStatus status) throws TransactionException; }
看下這個方法的調用流程,就很容易懂了。一些其餘的代碼就不要看了,基本是爲了jta作了準備 分佈式
TransactionInterceptor 只作了一件事情調用了父類TransactionAspectSupport的invokeWithinTransaction方法,那麼你們把注意力放到TransactionAspectSupport的invokeWithinTransaction方法上吧ide
public class TransactionInterceptor extends TransactionAspectSupport implements MethodInterceptor, Serializable { // PlatformTransactionManager 事務管理 public TransactionInterceptor(PlatformTransactionManager ptm, TransactionAttributeSource tas) { setTransactionManager(ptm); setTransactionAttributeSource(tas); } @Override public Object invoke(final MethodInvocation invocation) throws Throwable { Class<?> targetClass = (invocation.getThis() != null ? AopUtils.getTargetClass(invocation.getThis()) : null); return invokeWithinTransaction(invocation.getMethod(), targetClass, new InvocationCallback() { @Override public Object proceedWithInvocation() throws Throwable { return invocation.proceed(); } }); } }
protected Object invokeWithinTransaction(Method method, Class<?> targetClass, final InvocationCallback invocation) throws Throwable { // 獲得對象與方法上的Transactio註解 final TransactionAttribute txAttr = getTransactionAttributeSource().getTransactionAttribute(method, targetClass); // 獲得事務管理器,@Transactio註解變量transactionManager,能夠指定這個事務由那個事務管理器執行。 final PlatformTransactionManager tm = determineTransactionManager(txAttr); final String joinpointIdentification = methodIdentification(method, targetClass); if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) { //開啓事務 TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification); Object retVal = null; try { // 執行方法 retVal = invocation.proceedWithInvocation(); } catch (Throwable ex) { // 回滾 completeTransactionAfterThrowing(txInfo, ex); throw ex; } finally { // 清理TransactionInfo cleanupTransactionInfo(txInfo); } commitTransactionAfterReturning(txInfo); return retVal; } else { ...... } } protected PlatformTransactionManager determineTransactionManager(TransactionAttribute txAttr) { // 若是 條件成立,返回默認事務管理器 if (txAttr == null || this.beanFactory == null) { return getTransactionManager(); } // 得到 事務管理器的名字 String qualifier = txAttr.getQualifier(); // 若是有 if (StringUtils.hasText(qualifier)) { // 經過事務管理器的名字得到事務管理器, return determineQualifiedTransactionManager(qualifier); } else if (StringUtils.hasText(this.transactionManagerBeanName)) { // 默認管理器名字得到管理器 return determineQualifiedTransactionManager(this.transactionManagerBeanName); } else { // 得到默認管理器 PlatformTransactionManager defaultTransactionManager = getTransactionManager(); if (defaultTransactionManager == null) { defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class); this.transactionManagerCache.putIfAbsent( DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager); } return defaultTransactionManager; } } // 經過事務管理器的名字得到事務管理器 private PlatformTransactionManager determineQualifiedTransactionManager(String qualifier) { PlatformTransactionManager txManager = this.transactionManagerCache.get(qualifier); if (txManager == null) { txManager = BeanFactoryAnnotationUtils.qualifiedBeanOfType( this.beanFactory, PlatformTransactionManager.class, qualifier); this.transactionManagerCache.putIfAbsent(qualifier, txManager); } return txManager; }
spring-boot啓動事務很簡單隻須要EnableTransactionManagement註解或者TransactionManagementConfigurationSelector被ApplicationContext加載,那麼就會自動啓動事務。詳細請看下面的流程
@Configuration public class ProxyTransactionManagementConfiguration extends AbstractTransactionManagementConfiguration { @Bean(name = TransactionManagementConfigUtils.TRANSACTION_ADVISOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public BeanFactoryTransactionAttributeSourceAdvisor transactionAdvisor() { // 建立Advisor BeanFactoryTransactionAttributeSourceAdvisor advisor = new BeanFactoryTransactionAttributeSourceAdvisor(); // 建立 註解識別 advisor.setTransactionAttributeSource(transactionAttributeSource()); // 建立方法攔截器與處理器 advisor.setAdvice(transactionInterceptor()); advisor.setOrder(this.enableTx.<Integer>getNumber("order")); return advisor; } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionAttributeSource transactionAttributeSource() { return new AnnotationTransactionAttributeSource(); } @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public TransactionInterceptor transactionInterceptor() { TransactionInterceptor interceptor = new TransactionInterceptor(); interceptor.setTransactionAttributeSource(transactionAttributeSource()); if (this.txManager != null) { interceptor.setTransactionManager(this.txManager); } return interceptor; } }
事務真的很簡單,可是爲了作不少的兼容於擴展,spring-tx寫得很複雜。我的感受在分佈式的微服務框架設計下,不少都不該該要了。