spring 中常用的兩種事務配置方式以及事務的傳播性、隔離級別
在前面的文章中總結了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 事務配置
看到上面的這兩段配置檔案是不是很熟悉,對的這就是我們平時看到的事務的配置,在spring的配置中配置資料來源即dataSource、事務管理器,事務管理器使用不同的orm框架事務管理器類就不同,比如這裡使用的是mybatis 所以是<!-- 事務管理器配置,單資料來源事務 --> <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" />
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類繼承 這樣事務才會回滾!