在前面的文章中總結了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 兩種配置方式我們也都簡單學習了,兩種配置方式有哪些屬性要配置我們也了解了,但是,這里只是說了有這兩種常用的方法,而沒有具體說事務以及事務的配置帶來的數據的安全性以及性能的影響,其實事務不是那么簡單,具體深入學習希望以后有總結!
下面給大家列出spring事務的幾種傳播特性:
1. PROPAGATION_REQUIRED: 如果存在一個事務,則支持當前事務。如果沒有事務則開啟 2. PROPAGATION_SUPPORTS: 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執行 3. PROPAGATION_MANDATORY: 如果已經存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。 4. PROPAGATION_REQUIRES_NEW: 總是開啟一個新的事務。如果一個事務已經存在,則將這個存在的事務掛起。 5. PROPAGATION_NOT_SUPPORTED: 總是非事務地執行,並掛起任何存在的事務。 6. PROPAGATION_NEVER: 總是非事務地執行,如果存在一個活動事務,則拋出異常 7. PROPAGATION_NESTED:如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行
Spring事務的隔離級別
1. ISOLATION_DEFAULT: 這是一個PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務隔離級別,另外四個與JDBC的隔離級別相對應 2. ISOLATION_READ_UNCOMMITTED: 這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的數據,這種隔離級別會產生臟讀,不可重復讀和幻像讀。 3. ISOLATION_READ_COMMITTED: 保證一個事務修改的數據提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數據 4. ISOLATION_REPEATABLE_READ: 這種事務隔離級別可以防止臟讀,不可重復讀。但是可能出現幻像讀,它除了保證一個事務不能讀取另一個事務未提交的數據外,還保證了避免下面的情況產生(不可重復讀)。 5. ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執行,除了防止臟讀,不可重復讀外,還避免了幻像讀。
事務的隔離級別和數據庫中是一樣的大家可以看數據庫事務隔離級別就能明白了但是事務的傳播性是個什么鬼貌似之前沒聽過那下面就來看看
拷貝文章:http://blog.sina.com.cn/s/blog_4b5bc0110100z7jr.html
我們都知道事務的概念,那么事務的傳播特性是什么呢?(此處着重介紹傳播特性的概念,關於傳播特性的相關配置就不介紹了,可以查看spring的官方文檔)在我們用SSH開發項目的時候,我們一般都是將事務設置在Service層 那么當我們調用Service層的一個方法的時候它能夠保證我們的這個方法中執行的所有的對數據庫的更新操作保持在一個事務中,在事務層里面調用的這些方法要么全部成功,要么全部失敗。那么事務的傳播特性也是從這里說起的。如果你在你的Service層的這個方法中,除了調用了Dao層的方法之外,還調用了本類的其他的Service方法,那么在調用其他的Service方法的時候,這個事務是怎么規定的呢,我必須保證我在我方法里掉用的這個方法與我本身的方法處在同一個事務中,否則如果保證事物的一致性。事務的傳播特性就是解決這個問題的,“事務是會傳播的”在Spring中有針對傳播特性的多種配置我們大多數情況下只用其中的一種:PROPGATION_REQUIRED:這個配置項的意思是說當我調用service層的方法的時候開啟一個事務(具體調用那一層的方法開始創建事務,要看你的aop的配置),那么在調用這個service層里面的其他的方法的時候,如果當前方法產生了事務就用當前方法產生的事務,否則就創建一個新的事務。這個工作使由Spring來幫助我們完成的。以前沒有Spring幫助我們完成事務的時候我們必須自己手動的控制事務,例如當我們項目中僅僅使用hibernate,而沒有集成進spring的時候,我們在一個service層中調用其他的業務邏輯方法,為了保證事物必須也要把當前的hibernate session傳遞到下一個方法中,或者采用ThreadLocal的方法,將session傳遞給下一個方法,其實都是一個目的。現在這個工作由spring來幫助我們完成,就可以讓我們更加的專注於我們的業務邏輯。而不用去關心事務的問題。默認情況下當發生RuntimeException的情況下,事務才會回滾,所以要注意一下 如果你在程序發生錯誤的情況下,有自己的異常處理機制定義自己的Exception,必須從RuntimeException類繼承 這樣事務才會回滾!