在前面的文章中總結了spring事務的5中配置方式,但是很多方式都不用而且當時的配置使用的所有參數都是默認的參數,這篇文章就看常用的兩種事務配置方式並信息配置事務的傳播性、隔離級別、以及超時等問題,廢話不說下面就來看看!
一、注解式事務
1、注解式事務在平時的開發中使用的挺多,工作的兩個公司中看到很多項目使用了這種方式,下面看看具體的配置demo。
2、事務配置實例
(1)、spring+mybatis 事務配置
- <!-- 定義事務管理器 -->
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!--使用注釋事務 -->
- <tx:annotation-driven transaction-manager="transactionManager" />
(2)、spring+hibernate 事務配置
- <!-- 事務管理器配置,單數據源事務 -->
- <bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
- <property name="sessionFactory" ref="sessionFactory" />
- </bean>
- <!-- 使用annotation定義事務 -->
- <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
看到上面的這兩段配置文件是不是很熟悉,對的這就是我們平時看到的事務的配置,在spring的配置中配置數據源即dataSource、事務管理器,事務管理器使用不同的orm框架事務管理器類就不同,比如這里使用的是mybatis 所以是
- org.springframework.jdbc.datasource.DataSourceTransactionManager
如果使用hibernate 則事務管理器類為
- org.springframework.orm.hibernate3.HibernateTransactionManager
這是使用注解方式時要配置的,代碼中的具體的注解以及事務的傳播性、隔離級別一般在service 層中配置下面看看
3、@Transactional
(1)、這里說明一下,有的把這個注解放在類名稱上面了,這樣你配置的這個@Transactional 對這個類中的所有public方法都起作用
(2)、@Transactional 方法方法名上,只對這個方法有作用,同樣必須是public的方法
比如這里就對這個方法定義了一個事務同時設置了很多屬性:
- @Transactional(propagation=Propagation.REQUIRED,rollbackFor=Exception.class,timeout=1,isolation=Isolation.DEFAULT)
- public void saveUser(Map<String, String> map) throws Exception {
- System.out.println("方法開始");
- for (int i = 0; i < 500000; i++) {
- System.out.println("*");
- }
- System.out.println("進入保存");
- userDao.saveUser(map);
- System.out.println("退出保存");
- }
4、事物配置中有哪些屬性可以配置
(1)、事務的傳播性:@Transactional(propagation=Propagation.REQUIRED)
如果有事務, 那么加入事務, 沒有的話新建一個(默認情況下)
(2)、事務的超時性:@Transactional(timeout=30) //默認是30秒
注意這里說的是事務的超時性而不是Connection的超時性,這兩個是有區別的
(3)、事務的隔離級別:@Transactional(isolation = Isolation.READ_UNCOMMITTED)
讀取未提交數據(會出現臟讀, 不可重復讀) 基本不使用
(4)、回滾:
指定單一異常類:@Transactional(rollbackFor=RuntimeException.class)
指定多個異常類:@Transactional(rollbackFor={RuntimeException.class, Exception.class})
該屬性用於設置需要進行回滾的異常類數組,當方法中拋出指定異常數組中的異常時,則進行事務回滾。
(5)、只讀:@Transactional(readOnly=true)
該屬性用於設置當前事務是否為只讀事務,設置為true表示只讀,false則表示可讀寫,默認值為false。
ok 這種注解方式實現事務的配置以及一些屬性的定義,其實事務的東西還有很多要注意的事項,如果要深入學習的話要學習的東西還很多,這里只是簡單記錄一下
那我們要注意什么那:
1、在spring配置文件中引入<tx:>命名空間:xmlns:tx="http://www.springframework.org/schema/tx"
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.2.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-3.2.xsd">
2、@Transactional 只能被應用到public方法上, 對於其它非public的方法,如果標記了@Transactional也不會報錯,但方法沒有事務功能.
3、用 spring 事務管理器,由spring來負責數據庫的打開,提交,回滾.默認遇到運行期例外(throw new RuntimeException("注釋");)會回滾,即遇到不受檢查(unchecked)的例外時回滾;而遇到需要捕獲的例外(throw new Exception("注釋");)不會回滾,即遇到受檢查的例外(就是非運行時拋出的異常,編譯器會檢查到的異常叫受檢查例外或說受檢查異常)時,需我們指定方式來讓事務回滾 要想所有異常都回滾,要加上 @Transactional( rollbackFor={Exception.class,其它異常}) .如果讓unchecked例外不回滾: @Transactional(notRollbackFor=RunTimeException.class)
如下:
@Transactional(rollbackFor=Exception.class) //指定回滾,遇到異常Exception時回滾
public void methodName() {
throw new Exception("注釋");
}
@Transactional(noRollbackFor=Exception.class)//指定不回滾,遇到運行期例外(throw new RuntimeException("注釋");)會回滾
public ItimDaoImpl getItemDaoImpl() {
throw new RuntimeException("注釋");
}
4、@Transactional 注解應該只被應用到 public 可見度的方法上。 如果你在 protected、private 或者 package-visible 的方法上使用 @Transactional 注解,它也不會報錯, 但是這個被注解的方法將不會展示已配置的事務設置。
5、@Transactional 注解可以被應用於接口定義和接口方法、類定義和類的 public 方法上。然而,請注意僅僅 @Transactional 注解的出現不足於開啟事務行為,它僅僅 是一種元數據,能夠被可以識別 @Transactional 注解和上述的配置適當的具有事務行為的beans所使用。上面的例子中,其實正是 <tx:annotation-driven/>元素的出現 開啟 了事務行為。
6、Spring團隊的建議是你在具體的類(或類的方法)上使用 @Transactional 注解,而不要使用在類所要實現的任何接口上。你當然可以在接口上使用 @Transactional 注解,但是這將只能當你設置了基於接口的代理時它才生效。因為注解是 不能繼承 的,這就意味着如果你正在使用基於類的代理時,那么事務的設置將不能被基於類的代理所識別,而且對象也將不會被事務代理所包裝(將被確認為嚴重的)。因 此,請接受Spring團隊的建議並且在具體的類上使用 @Transactional 注解。
二、使用AOP的方式實現事務的配置
1、這種事務使用也很多,下面我們來看看簡單的例子
2、事務配置實例:
(1)、配置文件
- <!-- 定義事務管理器 -->
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
- <!-- 下面使用aop切面的方式來實現 -->
- <tx:advice id="TestAdvice" transaction-manager="transactionManager">
- <!--配置事務傳播性,隔離級別以及超時回滾等問題 -->
- <tx:attributes>
- <tx:method name="save*" propagation="REQUIRED" />
- <tx:method name="del*" propagation="REQUIRED" />
- <tx:method name="update*" propagation="REQUIRED" />
- <tx:method name="add*" propagation="REQUIRED" />
- <tx:method name="*" rollback-for="Exception" />
- </tx:attributes>
- </tx:advice>
- <aop:config>
- <!--配置事務切點 -->
- <aop:pointcut id="services"
- expression="execution(* com.website.service.*.*(..))" />
- <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
- </aop:config>
上面我們看到了,簡單的配置了事務,其中tx:attributes中設置了事務的傳播性,隔離級別以及那種問題能進行回滾超時等這些問題,也就是你自己按照業務需求定制一個事務來滿足你的業務需求。
注意: 這里注意一下,在tx:method中配置了rollback_for 中配置的Exception 這個是運行時的異常才會回滾不然其他異常是不會回滾的!
- @Service("userService")
- public class UserService {
- @Autowired
- private UserDao userDao;
- public void saveUser(Map<String, String> map) throws Exception {
- userDao.saveUser(map);
- throw new RuntimeException();
- // throw new Exception ();
- }
- }
這里我們看到了,如果拋出的是一個運行時異常則會回滾而如果拋出的不是運行時異常則會不回滾的。
需要注意的地方:
(1)、在spring 配置文件中引入:xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
- <beans xmlns="http://www.springframework.org/schema/beans"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:tx="http://www.springframework.org/schema/tx"
- xmlns:context="http://www.springframework.org/schema/context"
- xmlns:aop="http://www.springframework.org/schema/aop"
- xsi:schemaLocation="http://www.springframework.org/schema/beans
- http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
- http://www.springframework.org/schema/context
- http://www.springframework.org/schema/context/spring-context-3.2.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-3.2.xsd">
(2) advice(建議)的命名:由於每個模塊都會有自己的Advice,所以在命名上需要作出規范,初步的構想就是模塊名+Advice(只是一種命名規范)。
(3) tx:attribute標簽所配置的是作為事務的方法的命名類型。
如<tx:method name="save*" propagation="REQUIRED"/>
其中*為通配符,即代表以save為開頭的所有方法,即表示符合此命名規則的方法作為一個事務。
propagation="REQUIRED"代表支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
(4) aop:pointcut標簽配置參與事務的類,由於是在Service中進行數據庫業務操作,配的應該是包含那些作為事務的方法的Service類。
首先應該特別注意的是id的命名,同樣由於每個模塊都有自己事務切面,所以我覺得初步的命名規則因為 all+模塊名+ServiceMethod。而且每個模塊之間不同之處還在於以下一句:
expression="execution(* com.test.testAda.test.model.service.*.*(..))"
其中第一個*代表返回值,第二*代表service下子包,第三個*代表方法名,“(..)”代表方法參數。
(5) aop:advisor標簽就是把上面我們所配置的事務管理兩部分屬性整合起來作為整個事務管理。
(6)注意標紅的地方
ok 到這里兩種配置方式簡單的demo 都有了,下面我們來看看tx:method 中還有那些屬性可以配置
下面來看看aop 這種方式來配置的時候我們還能配置那些屬性:
<tx:advice id="advice" transaction-manager="txManager">
<tx:attributes>
<!-- tx:method的屬性:
* name 是必須的,表示與事務屬性關聯的方法名(業務方法名),對切入點進行細化。通配符(*)可以用來指定一批關聯到相同的事務屬性的方法。
如:'get*'、'handle*'、'on*Event'等等.
* propagation 不是必須的 ,默認值是REQUIRED
表示事務傳播行為, 包括REQUIRED,SUPPORTS,MANDATORY,REQUIRES_NEW,NOT_SUPPORTED,NEVER,NESTED
* isolation 不是必須的 默認值DEFAULT
表示事務隔離級別(數據庫的隔離級別)
* timeout 不是必須的 默認值-1(永不超時)
表示事務超時的時間(以秒為單位)
* read-only 不是必須的 默認值false不是只讀的
表示事務是否只讀?
* rollback-for 不是必須的
表示將被觸發進行回滾的 Exception(s);以逗號分開。
如:'com.foo.MyBusinessException,ServletException'
* no-rollback-for 不是必須的
表示不被觸發進行回滾的 Exception(s);以逗號分開。
如:'com.foo.MyBusinessException,ServletException'
任何 RuntimeException 將觸發事務回滾,但是任何 checked Exception 將不觸發事務回滾
-->
<tx:method name="save*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="update*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<tx:method name="delete*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
<!-- 其他的方法之只讀的 -->
<tx:method name="*" read-only="true"/>
</tx:attributes>
</tx:advice>
OK 兩種配置方式我們也都簡單學習了,兩種配置方式有哪些屬性要配置我們也了解了,但是,這里只是說了有這兩種常用的方法,而沒有具體說事務以及事務的配置帶來的數據的安全性以及性能的影響,其實事務不是那么簡單,具體深入學習希望以后有總結!