Spring事務(wù)管理
Spring不會(huì )直接去管理事務(wù),它提供了很多可供選擇的事務(wù)管理器,將事務(wù)委托給JTA或某些特定的平臺事務(wù)實(shí)現。常見(jiàn)的Spring事務(wù)管理器:
org.springframework.jdbc.datasource.DataSourceTransactionManager 提供JDBC事務(wù)支持,也可以用來(lái)支持iBatis
org.springframework.orm.hibernate.HibernateTransactionManager Hibernate2持久事務(wù)支持
org.springframework.orm.hibernate.HibernateTransactionManager Hibernate3持久事務(wù)支持
org.springframework.orm.jpa.JpaTransactionManager JPA持久事務(wù)支持
這些都是一些持久性事務(wù),也是平時(shí)用的最多的(尤其是對我這種天天CRUD的人)
OK!知道了這一點(diǎn)我們便可以在Spring中編寫(xiě)事務(wù),最常用的方法是使用TransactionTemplate,如果你用過(guò)Spring的JdbcTemplate的話(huà)就會(huì )覺(jué)的它跟這個(gè)用法很像。
首先我們需要聲明一個(gè)Spring的事務(wù)管理器。我們知道,使用JdbcTemplate需要一個(gè)數據源,使用事務(wù)那么也需要一個(gè)聲明一個(gè)事務(wù)管理器:
<bean id="transactionManager" class="org.springframework.jdbc.datasoure.DataSoureTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
這是JDBC的事務(wù)管理器,它有一個(gè)dataSource屬性,指向要操作的數據源.接下來(lái)我們要寫(xiě)一個(gè)用戶(hù)注冊的服務(wù)(我實(shí)在舉不出什么好例子來(lái)了):
public class UserService {
@Autowired
private TransactionTemplate transactionTemplate;
@Autowired
private UserDAO userDAO;
@Autowired
private MailSender sender;
public UserService(){
}
public void reg(final User user){
transactionTemplate.execute(new TransactionCallback(){
public Object doInTransaction(TransactionStatus ts){
try{
userDAO.insert(user);
sender.send();
}
catch(Exception e){
ts.setRollbackOnly();
}
return null;
}
});
}
}
注冊服務(wù)分為兩個(gè)步驟,一個(gè)是將用戶(hù)的信息插入到數據庫,二是向用戶(hù)發(fā)送郵件激活通知。這兩個(gè)步驟是原子性的(好吧),因此需要使用事務(wù)支持,事務(wù)操作主要是通過(guò)
TransactionTemplate來(lái)實(shí)現的,我們需要在Spring配置文件中配置它:
<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
<property name="transactionManager" ref="transactionManager"/>
</bean>
屬性transactionManager指向前面聲明的JDBC事務(wù)管理器
我們只需要將事務(wù)代碼放入到doInTransaction方法中即可,如果doIntransaction能夠被成功執行到return,則事務(wù)將被提交,如果中途遇到問(wèn)題,如Exception,則調用
setRollbackOnly()方法回滾整個(gè)事務(wù)
Spring對聲明式事務(wù)的支持:
嗯~~上面這段代碼不是很好,為啥?因為reg服務(wù)應該只去管用戶(hù)注冊這個(gè)事情,但是它現在卻包含了很多事務(wù)處理的代碼,違反了單一原則,這時(shí)候你可能會(huì )想到AOP,能不
能使用AOP來(lái)處理事務(wù)呢?嗯,開(kāi)發(fā)Spring的大牛們當然會(huì )去想到這一點(diǎn),他們?yōu)榇颂峁┝寺暶魇绞聞?wù)的支持,這個(gè)支持也是通過(guò)Spring的AOP框架來(lái)實(shí)現的。
什么是聲明式事務(wù)?就是通過(guò)配置文件和注解等方式來(lái)進(jìn)行事務(wù)的聲明,而不去侵犯程序代碼,這樣就不會(huì )違背單一職責原則了。
Spring中的聲明式事務(wù)是使用參數來(lái)定義的,一個(gè)參數就是對事務(wù)策略應該如何應用到某個(gè)方法的一段描述,這些參數名字很長(cháng),比我的發(fā)型還惡心。
傳播行為:傳播行為定義了關(guān)于客戶(hù)端和被調用方法的事務(wù)邊界
1. PROPAGATION_REQUIRED: 如果存在一個(gè)事務(wù),則支持當前事務(wù)。如果沒(méi)有事務(wù)則開(kāi)啟
2. PROPAGATION_SUPPORTS: 如果存在一個(gè)事務(wù),支持當前事務(wù)。如果沒(méi)有事務(wù),則非事務(wù)的執行
3. PROPAGATION_MANDATORY: 如果已經(jīng)存在一個(gè)事務(wù),支持當前事務(wù)。如果沒(méi)有一個(gè)活動(dòng)的事務(wù),則拋出異常。
4. PROPAGATION_REQUIRES_NEW: 總是開(kāi)啟一個(gè)新的事務(wù)。如果一個(gè)事務(wù)已經(jīng)存在,則將這個(gè)存在的事務(wù)掛起。
5. PROPAGATION_NOT_SUPPORTED: 總是非事務(wù)地執行,并掛起任何存在的事務(wù)。
6. PROPAGATION_NEVER: 總是非事務(wù)地執行,如果存在一個(gè)活動(dòng)事務(wù),則拋出異常
7. PROPAGATION_NESTED:如果一個(gè)活動(dòng)的事務(wù)存在,則運行在一個(gè)嵌套的事務(wù)中. 如果沒(méi)有活動(dòng)事務(wù),
則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執行
隔離級別:隔離級別定義了事務(wù)受并發(fā)活動(dòng)的影響程度
1. ISOLATION_DEFAULT: 這是一個(gè)PlatfromTransactionManager默認的隔離級別,使用數據庫默認的事務(wù)隔離級別.
另外四個(gè)與JDBC的隔離級別相對應
2. ISOLATION_READ_UNCOMMITTED: 這是事務(wù)最低的隔離級別,它充許令外一個(gè)事務(wù)可以看到這個(gè)事務(wù)未提交的數據。
這種隔離級別會(huì )產(chǎn)生臟讀,不可重復讀和幻像讀。
3. ISOLATION_READ_COMMITTED: 保證一個(gè)事務(wù)修改的數據提交后才能被另外一個(gè)事務(wù)讀取。另外一個(gè)事務(wù)不能讀取該事務(wù)未提交的數據
4. ISOLATION_REPEATABLE_READ: 這種事務(wù)隔離級別可以防止臟讀,不可重復讀。但是可能出現幻像讀。
它除了保證一個(gè)事務(wù)不能讀取另一個(gè)事務(wù)未提交的數據外,還保證了避免下面的情況產(chǎn)生(不可重復讀)。
5. ISOLATION_SERIALIZABLE 這是花費最高代價(jià)但是最可靠的事務(wù)隔離級別。事務(wù)被處理為順序執行。
除了防止臟讀,不可重復讀外,還避免了幻像讀
關(guān)于臟讀(Dirty read)、不可重復讀(Nonrepeatable read)和幻讀(Phantom reads)的介紹:
臟讀:如果事務(wù)A讀取了事務(wù)B改寫(xiě)但是尚未提交的數據,事務(wù)B發(fā)生了問(wèn)題(來(lái)了大姨媽?zhuān)浚┗貪L了,那么A所讀取的數據是無(wú)效的,這個(gè)故事叫做臟讀
不可重復讀:如果一個(gè)事務(wù)多次讀取數據,每一次結果都不同,這是由于另一個(gè)事務(wù)在更改數據,這個(gè)故事叫做不可重復讀
幻讀:幻讀跟不可重復讀差不多,如果一個(gè)事務(wù)A讀取了數據,事務(wù)B又插入了一些數據,在后來(lái)的查詢(xún)中事務(wù)A發(fā)現了一些額外的記錄
很簡(jiǎn)單?哈哈.看看在Spring中如何使用聲明式事務(wù):
Spring2.0開(kāi)始為事務(wù)提供了配置元素
首先需要在Spring配置文件中添加AOP支持,因為Spring聲明式事務(wù)是基于A(yíng)OP的,然后在加入事務(wù)標簽支持:
命名空間:
xmlns:tx="http://www.springframework.org/schema/tx"
Schema聲明:
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
接下來(lái)我們只需要添加如下配置內容就可以使用聲明式事務(wù)了:
<!- 這個(gè)就不詳細說(shuō)了,添加AOP支持 -->
<aop:config>
<aop:pointcut expression="execution(* *. .UserServicce.reg(..)"/>
<aop:advisor advice-ref="txAdvice"/>
</aop:config>
<!-- 重點(diǎn)是下面 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="reg" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<tx:advice>用來(lái)聲明事務(wù)策略,同樣需要指定一個(gè)事務(wù)管理器,這個(gè)是必須的,我們知道Spring不會(huì )自己去管理事務(wù)的,它一向喜歡代理,讓人看起來(lái)好像一切都是它的功
勞,嗯!
<tx:attribute>聲明了事務(wù)參數,<tx:method>是需要提供事務(wù)支持的方法,需要注意的是它有這么幾個(gè)參數:
isolation:指定事務(wù)隔離級別
no-rollback-for:對于哪些異常不回滾(設計者咋就想的這么周到呢???)
propagation:事務(wù)的傳播級別
read-only:該事務(wù)只讀
rollback-for:哪些異常發(fā)生之后回滾
timeout:定義事務(wù)超時(shí)
唉~~配置文件還是太惡心了,要是有注解~~嗯,還真有:
首先要添加一個(gè)注解驅動(dòng)標簽:<tx:annotation-driven transaction-manager="txManager"/>
然后我們使用@Transactional注解,這個(gè)注解可以修飾類(lèi)也可以修飾方法,修飾類(lèi)的話(huà)將作用于該類(lèi)所有的方法,注解的參數同<tx:method>的參數,另外有一個(gè)很酷的地方
是如果UserService是一個(gè)接口,那么我給他使用了@Transactional()注解,那么它的一系列實(shí)現類(lèi)UserServiceImpl1、UserServiceImpl2……UserServiceImpl10000都會(huì )自
動(dòng)支持該聲明事務(wù)
完!事務(wù)很重要!
聯(lián)系客服