前言
上篇主要從編程式事務和聲明式事務注解的形式來了解了事務,而這篇我們針對AOP的方式來實現事務。先回顧下事務的基礎知識事務的隔離級別和事務的傳播行為。使用aop 配置事務時注意引用aspectjweaver,要不然程序啟動起來就會報錯,找不到相關類
事務隔離級別
隔離級別是指若干個並發的事務之間的隔離程度。TransactionDefinition 接口中定義了五個表示隔離級別的常量:
- TransactionDefinition.ISOLATION_DEFAULT:這是默認值,表示使用底層數據庫的默認隔離級別。對大部分數據庫而言,通常這值就是TransactionDefinition.ISOLATION_READ_COMMITTED。
- TransactionDefinition.ISOLATION_READ_UNCOMMITTED:該隔離級別表示一個事務可以讀取另一個事務修改但還沒有提交的數據。該級別不能防止臟讀和不可重復讀,因此很少使用該隔離級別。
- TransactionDefinition.ISOLATION_READ_COMMITTED:該隔離級別表示一個事務只能讀取另一個事務已經提交的數據。該級別可以防止臟讀,這也是大多數情況下的推薦值。
- TransactionDefinition.ISOLATION_REPEATABLE_READ:該隔離級別表示一個事務在整個過程中可以多次重復執行某個查詢,並且每次返回的記錄都相同。即使在多次查詢之間有新增的數據滿足該查詢,這些新增的記錄也會被忽略。該級別可以防止臟讀和不可重復讀。
- TransactionDefinition.ISOLATION_SERIALIZABLE:所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀。但是這將嚴重影響程序的性能。通常情況下也不會用到該級別。
事務傳播行為
所謂事務的傳播行為是指,如果在開始當前事務之前,一個事務上下文已經存在,此時有若干選項可以指定一個事務性方法的執行行為。在TransactionDefinition定義中包括了如下幾個表示傳播行為的常量:
- TransactionDefinition.PROPAGATION_REQUIRED:如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務。
- TransactionDefinition.PROPAGATION_REQUIRES_NEW:創建一個新的事務,如果當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行。
- TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以非事務方式運行,如果當前存在事務,則把當前事務掛起。
- TransactionDefinition.PROPAGATION_NEVER:以非事務方式運行,如果當前存在事務,則拋出異常。
- TransactionDefinition.PROPAGATION_MANDATORY:如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出異常。
- TransactionDefinition.PROPAGATION_NESTED:如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價於TransactionDefinition.PROPAGATION_REQUIRED。
使用AOP實現事務管理
<!--配置數據源,這里使用Spring默認--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${sqlserver.driver}"/> <property name="url" value="${sqlserver.url}"/> <property name="username" value="${sqlserver.username}"/> <property name="password" value="${sqlserver.password}"/> </bean> <!--配置sqlSessionFactory--> <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean"> <property name="configLocation" value="classpath:springmvc-mybatis.xml"/> <property name="dataSource" ref="dataSource"/> </bean> <!--掃描mapper--> <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.autohome.dao"/> </bean> <!--事務管理器 --> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <property name="dataSource" ref="dataSource"/> </bean> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="insert*" isolation="DEFAULT" propagation="REQUIRED"/> <tx:method name="*" read-only="true" /> </tx:attributes> </tx:advice> <!--只對業務邏輯層開啟事務--> <aop:config expose-proxy="true"> <aop:pointcut id="txPointcut" expression="execution(* com.autohome.service..*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointcut"/> </aop:config>
運行action后,console會打印入庫成功的提示,從數據庫里查詢其實數據已經回滾。
總結
以上兩篇總結了事務兩種配置方式,編程式事務和聲明式事務,而從應用的角度來看@Transactional注解屬性最簡單也最實用,aop的方式控制更細膩些。同時回顧了基礎知識事務傳播屬性和隔離級別,這兩個地方不好理解,平時解除的業務解除相對也很好,還要繼續摸索和demo。
參考
https://www.ibm.com/developerworks/cn/education/opensource/os-cn-spring-trans/index.html