《四 spring原始碼》利用TransactionManager手寫spring的aop

x號開發者發表於2019-03-28

事務控制分類

程式設計式事務控制

         自己手動控制事務,就叫做程式設計式事務控制。

     Jdbc程式碼:

         Conn.setAutoCommite(false);  // 設定手動控制事務

     Hibernate程式碼:

         Session.beginTransaction();    // 開啟一個事務

     【細粒度的事務控制: 可以對指定的方法、指定的方法的某幾行新增事務控制】

     (比較靈活,但開發起來比較繁瑣: 每次都要開啟、提交、回滾.)

 

宣告式事務控制

         Spring提供了對事務的管理, 這個就叫宣告式事務管理。

     Spring提供了對事務控制的實現。使用者如果想用Spring的宣告式事務管理,只需要在配置檔案中配置即可; 不想使用時直接移除配置。這個實現了對事務控制的最大程度的解耦。

     Spring宣告式事務管理,核心實現就是基於Aop。

     【粗粒度的事務控制: 只能給整個方法應用事務,不可以對方法的某幾行應用事務。】

     (因為aop攔截的是方法。)

 

     Spring宣告式事務管理器類:

     Jdbc技術:DataSourceTransactionManager

     Hibernate技術:HibernateTransactionManager

手寫Spring事務框架

程式設計事務實現

概述

所謂程式設計式事務指的是通過編碼方式實現事務,即類似於JDBC程式設計實現事務管理。管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對於程式設計式事務管理,spring推薦使用TransactionTemplate。

案例

使用程式設計事務實現手動事務

使用程式設計事務實現,手動事務 begin、commit、rollback

@Component
public class TransactionUtils {

    @Autowired
    private DataSourceTransactionManager dataSourceTransactionManager;

    // 開啟事務
    public TransactionStatus begin() {
        TransactionStatus transaction = dataSourceTransactionManager.getTransaction(new DefaultTransactionAttribute());
        return transaction;
    }

    // 提交事務
    public void commit(TransactionStatus transactionStatus) {
        dataSourceTransactionManager.commit(transactionStatus);
    }

    // 回滾事務
    public void rollback(TransactionStatus transactionStatus) {
        dataSourceTransactionManager.rollback(transactionStatus);
    }
}

@Service
public class UserService {
    @Autowired
    private UserDao userDao;
    @Autowired
    private TransactionUtils transactionUtils;

    public void add() {
        TransactionStatus transactionStatus = null;
        try {
            transactionStatus = transactionUtils.begin();
            userDao.add("wangmazi", 27);
            int i = 1 / 0;
            System.out.println("我是add方法");
            userDao.add("zhangsan", 16);
            transactionUtils.commit(transactionStatus);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (transactionStatus != null) {
                transactionStatus.rollbackToSavepoint(transactionStatus);
            }
        }

    }

}

AOP技術封裝手動事務

@Component
@Aspect
public class AopTransaction {
    @Autowired
    private TransactionUtils transactionUtils;

    // // 異常通知
    @AfterThrowing("execution(* com.service.UserService.add(..))")
    public void afterThrowing() {
        System.out.println("程式已經回滾");
        // 獲取程式當前事務 進行回滾
        TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
    }

    // 環繞通知
    @Around("execution(* com.service.UserService.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("開啟事務");
        TransactionStatus begin = transactionUtils.begin();
        proceedingJoinPoint.proceed();
        transactionUtils.commit(begin);
        System.out.println("提交事務");
    }

}

宣告事務實現

概述

管理建立在AOP之上的。其本質是對方法前後進行攔截,然後在目標方法開始之前建立或者加入一個事務,在執行完目標方法之後根據執行情況提交或者回滾事務。宣告式事務最大的優點就是不需要通過程式設計的方式管理事務,這樣就不需要在業務邏輯程式碼中摻雜事務管理的程式碼,只需在配置檔案中做相關的事務規則宣告(或通過基於@Transactional註解的方式),便可以將事務規則應用到業務邏輯中。

       顯然宣告式事務管理要優於程式設計式事務管理,這正是spring倡導的非侵入式的開發方式。

 

宣告式事務管理使業務程式碼不受汙染,一個普通的POJO物件,只要加上註解就可以獲得完全的事務支援。和程式設計式事務相比,宣告式事務唯一不足地方是,後者的最細粒度只能作用到方法級別,無法做到像程式設計式事務那樣可以作用到程式碼塊級別。但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進行事務管理的程式碼塊獨立為方法等等。

XML實現宣告

 

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
          http://www.springframework.org/schema/context
         http://www.springframework.org/schema/context/spring-context.xsd
         http://www.springframework.org/schema/aop
         http://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd">


    <!-- 開啟註解 -->
    <context:component-scan base-package="com.itmayiedu"></context:component-scan>
    <!-- 1. 資料來源物件: C3P0連線池 -->
    <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
        <property name="driverClass" value="com.mysql.jdbc.Driver"></property>
        <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test"></property>
        <property name="user" value="root"></property>
        <property name="password" value="root"></property>
    </bean>

    <!-- 2. JdbcTemplate工具類例項 -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- 配置事物 -->
    <bean id="dataSourceTransactionManager"
        class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"></property>
    </bean>
    <!-- 開啟註解事物 -->
    <tx:annotation-driven transaction-manager="dataSourceTransactionManager" />
</beans>

 

註解版本宣告

    @Transactional
    public void add() {
        userDao.add("wangmazi", 27);
        int i = 1 / 0;
        System.out.println("我是add方法");
        userDao.add("zhangsan", 16);
    }

 

相關文章