batch spring 重复执行_一个3年老javaer竟然连Spring的事务管理都不知道,惊呆了
1、事務(wù)介紹
事務(wù)(Transaction),一般是指要做的或所做的事情。在計(jì)算機(jī)術(shù)語(yǔ)中是指訪問(wèn)并可能更新數(shù)據(jù)庫(kù)中各種數(shù)據(jù)項(xiàng)的一個(gè)程序執(zhí)行單元(unit)。
這里我們以取錢的例子來(lái)講解:比如你去ATM機(jī)取1000塊錢,大體有兩個(gè)步驟:第一步輸入密碼金額,銀行卡扣掉1000元錢;第二步從ATM出1000元錢。這兩個(gè)步驟必須是要么都執(zhí)行要么都不執(zhí)行。如果銀行卡扣除了1000塊但是ATM出錢失敗的話,你將會(huì)損失1000元;如果銀行卡扣錢失敗但是ATM卻出了1000塊,那么銀行將損失1000元。
如何保證這兩個(gè)步驟不會(huì)出現(xiàn)一個(gè)出現(xiàn)異常了,而另一個(gè)執(zhí)行成功呢?事務(wù)就是用來(lái)解決這樣的問(wèn)題。事務(wù)是一系列的動(dòng)作,它們綜合在一起才是一個(gè)完整的工作單元,這些動(dòng)作必須全部完成,如果有一個(gè)失敗的話,那么事務(wù)就會(huì)回滾到最開(kāi)始的狀態(tài),仿佛什么都沒(méi)發(fā)生過(guò)一樣。在企業(yè)級(jí)應(yīng)用程序開(kāi)發(fā)中,事務(wù)管理是必不可少的技術(shù),用來(lái)確保數(shù)據(jù)的完整性和一致性。
2、事務(wù)的四個(gè)特性(ACID)
①、原子性(Atomicity):事務(wù)是一個(gè)原子操作,由一系列動(dòng)作組成。事務(wù)的原子性確保動(dòng)作要么全部完成,要么完全不起作用。
②、一致性(Consistency):一旦事務(wù)完成(不管成功還是失敗),系統(tǒng)必須確保它所建模的業(yè)務(wù)處于一致的狀態(tài),而不會(huì)是部分完成部分失敗。在現(xiàn)實(shí)中的數(shù)據(jù)不應(yīng)該被破壞。
③、隔離性(Isolation):可能有許多事務(wù)會(huì)同時(shí)處理相同的數(shù)據(jù),因此每個(gè)事務(wù)都應(yīng)該與其他事務(wù)隔離開(kāi)來(lái),防止數(shù)據(jù)損壞。
④、持久性(Durability):一旦事務(wù)完成,無(wú)論發(fā)生什么系統(tǒng)錯(cuò)誤,它的結(jié)果都不應(yīng)該受到影響,這樣就能從任何系統(tǒng)崩潰中恢復(fù)過(guò)來(lái)。通常情況下,事務(wù)的結(jié)果被寫(xiě)到持久化存儲(chǔ)器中。
3、Spring 事務(wù)管理的核心接口
首先我們創(chuàng)建一個(gè)Java工程,然后導(dǎo)入 Spring 核心事務(wù)包
我們打開(kāi)Spring的核心事務(wù)包,查看如下類:org.springframework.transaction
上面所示的三個(gè)類文件便是Spring的事務(wù)管理接口。
如下圖所示:下面我們分別對(duì)這三個(gè)接口進(jìn)行簡(jiǎn)單的介紹
4、 PlatformTransactionManager ?事務(wù)管理器
Spring事務(wù)管理器的接口是org.springframework.transaction.PlatformTransactionManager,如上圖所示,Spring并不直接管理事務(wù),通過(guò)這個(gè)接口,Spring為各個(gè)平臺(tái)如JDBC、Hibernate等都提供了對(duì)應(yīng)的事務(wù)管理器,也就是將事務(wù)管理的職責(zé)委托給Hibernate或者JTA等持久化機(jī)制所提供的相關(guān)平臺(tái)框架的事務(wù)來(lái)實(shí)現(xiàn)。
我們進(jìn)入到 PlatformTransactionManager 接口,查看源碼:
①、TransactionStatus getTransaction(TransactionDefinition definition) ,事務(wù)管理器 通過(guò)TransactionDefinition,獲得“事務(wù)狀態(tài)”,從而管理事務(wù)。
②、void commit(TransactionStatus status) 根據(jù)狀態(tài)提交
③、void rollback(TransactionStatus status) 根據(jù)狀態(tài)回滾
也就是說(shuō)Spring事務(wù)管理的為不同的事務(wù)API提供一致的編程模型,具體的事務(wù)管理機(jī)制由對(duì)應(yīng)各個(gè)平臺(tái)去實(shí)現(xiàn)。
比如下面我們導(dǎo)入實(shí)現(xiàn)事務(wù)管理的兩種平臺(tái):JDBC和Hibernate
然后我們?cè)俅尾榭碢latformTransactionManager接口,會(huì)發(fā)現(xiàn)它多了幾個(gè)實(shí)現(xiàn)類,如下:
5、TransactionStatus 事務(wù)狀態(tài)
在上面 PlatformTransactionManager 接口中,有如下方法:
這個(gè)方法返回的是 TransactionStatus對(duì)象,然后程序根據(jù)返回的對(duì)象來(lái)獲取事務(wù)狀態(tài),然后進(jìn)行相應(yīng)的操作。
而 TransactionStatus 這個(gè)接口的內(nèi)容如下:
這個(gè)接口描述的是一些處理事務(wù)提供簡(jiǎn)單的控制事務(wù)執(zhí)行和查詢事務(wù)狀態(tài)的方法,在回滾或提交的時(shí)候需要應(yīng)用對(duì)應(yīng)的事務(wù)狀態(tài)。
6、TransactionDefinition 基本事務(wù)屬性的定義
上面講到的事務(wù)管理器接口PlatformTransactionManager通過(guò)getTransaction(TransactionDefinition definition)方法來(lái)得到事務(wù),這個(gè)方法里面的參數(shù)是TransactionDefinition類,這個(gè)類就定義了一些基本的事務(wù)屬性。
那么什么是事務(wù)屬性呢?事務(wù)屬性可以理解成事務(wù)的一些基本配置,描述了事務(wù)策略如何應(yīng)用到方法上。事務(wù)屬性包含了5個(gè)方面,如圖所示:
TransactionDefinition 接口方法如下:
一、傳播行為:當(dāng)事務(wù)方法被另一個(gè)事務(wù)方法調(diào)用時(shí),必須指定事務(wù)應(yīng)該如何傳播。
Spring 定義了如下七中傳播行為,這里以A業(yè)務(wù)和B業(yè)務(wù)之間如何傳播事務(wù)為例說(shuō)明:
①、PROPAGATION_REQUIRED :required , 必須。默認(rèn)值,A如果有事務(wù),B將使用該事務(wù);如果A沒(méi)有事務(wù),B將創(chuàng)建一個(gè)新的事務(wù)。
②、PROPAGATION_SUPPORTS:supports ,支持。A如果有事務(wù),B將使用該事務(wù);如果A沒(méi)有事務(wù),B將以非事務(wù)執(zhí)行。
③、PROPAGATION_MANDATORY:mandatory ,強(qiáng)制。A如果有事務(wù),B將使用該事務(wù);如果A沒(méi)有事務(wù),B將拋異常。
④、PROPAGATION_REQUIRES_NEW :requires_new,必須新的。如果A有事務(wù),將A的事務(wù)掛起,B創(chuàng)建一個(gè)新的事務(wù);如果A沒(méi)有事務(wù),B創(chuàng)建一個(gè)新的事務(wù)。
⑤、PROPAGATION_NOT_SUPPORTED :not_supported ,不支持。如果A有事務(wù),將A的事務(wù)掛起,B將以非事務(wù)執(zhí)行;如果A沒(méi)有事務(wù),B將以非事務(wù)執(zhí)行。
⑥、PROPAGATION_NEVER :never,從不。如果A有事務(wù),B將拋異常;如果A沒(méi)有事務(wù),B將以非事務(wù)執(zhí)行。
⑦、PROPAGATION_NESTED :nested ,嵌套。A和B底層采用保存點(diǎn)機(jī)制,形成嵌套事務(wù)。
二、隔離級(jí)別:定義了一個(gè)事務(wù)可能受其他并發(fā)事務(wù)影響的程度。
并發(fā)事務(wù)引起的問(wèn)題:
在典型的應(yīng)用程序中,多個(gè)事務(wù)并發(fā)運(yùn)行,經(jīng)常會(huì)操作相同的數(shù)據(jù)來(lái)完成各自的任務(wù)。并發(fā)雖然是必須的,但可能會(huì)導(dǎo)致以下的問(wèn)題。
①、臟讀(Dirty reads)——臟讀發(fā)生在一個(gè)事務(wù)讀取了另一個(gè)事務(wù)改寫(xiě)但尚未提交的數(shù)據(jù)時(shí)。如果改寫(xiě)在稍后被回滾了,那么第一個(gè)事務(wù)獲取的數(shù)據(jù)就是無(wú)效的。
②、不可重復(fù)讀(Nonrepeatable read)——不可重復(fù)讀發(fā)生在一個(gè)事務(wù)執(zhí)行相同的查詢兩次或兩次以上,但是每次都得到不同的數(shù)據(jù)時(shí)。這通常是因?yàn)榱硪粋€(gè)并發(fā)事務(wù)在兩次查詢期間進(jìn)行了更新。
③、幻讀(Phantom read)——幻讀與不可重復(fù)讀類似。它發(fā)生在一個(gè)事務(wù)(T1)讀取了幾行數(shù)據(jù),接著另一個(gè)并發(fā)事務(wù)(T2)插入了一些數(shù)據(jù)時(shí)。在隨后的查詢中,第一個(gè)事務(wù)(T1)就會(huì)發(fā)現(xiàn)多了一些原本不存在的記錄。
注意:不可重復(fù)讀重點(diǎn)是修改,而幻讀重點(diǎn)是新增或刪除。
在 Spring 事務(wù)管理中,為我們定義了如下的隔離級(jí)別:
①、ISOLATION_DEFAULT:使用后端數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別
②、ISOLATION_READ_UNCOMMITTED:最低的隔離級(jí)別,允許讀取尚未提交的數(shù)據(jù)變更,可能會(huì)導(dǎo)致臟讀、幻讀或不可重復(fù)讀
③、ISOLATION_READ_COMMITTED:允許讀取并發(fā)事務(wù)已經(jīng)提交的數(shù)據(jù),可以阻止臟讀,但是幻讀或不可重復(fù)讀仍有可能發(fā)生
④、ISOLATION_REPEATABLE_READ:對(duì)同一字段的多次讀取結(jié)果都是一致的,除非數(shù)據(jù)是被本身事務(wù)自己所修改,可以阻止臟讀和不可重復(fù)讀,但幻讀仍有可能發(fā)生
⑤、ISOLATION_SERIALIZABLE:最高的隔離級(jí)別,完全服從ACID的隔離級(jí)別,確保阻止臟讀、不可重復(fù)讀以及幻讀,也是最慢的事務(wù)隔離級(jí)別,因?yàn)樗ǔJ峭ㄟ^(guò)完全鎖定事務(wù)相關(guān)的數(shù)據(jù)庫(kù)表來(lái)實(shí)現(xiàn)的
上面定義的隔離級(jí)別,在 Spring 的 TransactionDefinition.class 中也分別用常量 -1,0,1,2,4,8表示。比如 ISOLATION_DEFAULT 的定義:
三、只讀
這是事務(wù)的第三個(gè)特性,是否為只讀事務(wù)。如果事務(wù)只對(duì)后端的數(shù)據(jù)庫(kù)進(jìn)行該操作,數(shù)據(jù)庫(kù)可以利用事務(wù)的只讀特性來(lái)進(jìn)行一些特定的優(yōu)化。通過(guò)將事務(wù)設(shè)置為只讀,你就可以給數(shù)據(jù)庫(kù)一個(gè)機(jī)會(huì),讓它應(yīng)用它認(rèn)為合適的優(yōu)化措施。
四、事務(wù)超時(shí)
為了使應(yīng)用程序很好地運(yùn)行,事務(wù)不能運(yùn)行太長(zhǎng)的時(shí)間。因?yàn)槭聞?wù)可能涉及對(duì)后端數(shù)據(jù)庫(kù)的鎖定,所以長(zhǎng)時(shí)間的事務(wù)會(huì)不必要的占用數(shù)據(jù)庫(kù)資源。事務(wù)超時(shí)就是事務(wù)的一個(gè)定時(shí)器,在特定時(shí)間內(nèi)事務(wù)如果沒(méi)有執(zhí)行完畢,那么就會(huì)自動(dòng)回滾,而不是一直等待其結(jié)束。
五、回滾規(guī)則
事務(wù)五邊形的最后一個(gè)方面是一組規(guī)則,這些規(guī)則定義了哪些異常會(huì)導(dǎo)致事務(wù)回滾而哪些不會(huì)。默認(rèn)情況下,事務(wù)只有遇到運(yùn)行期異常時(shí)才會(huì)回滾,而在遇到檢查型異常時(shí)不會(huì)回滾(這一行為與EJB的回滾行為是一致的) 。但是你可以聲明事務(wù)在遇到特定的檢查型異常時(shí)像遇到運(yùn)行期異常那樣回滾。同樣,你還可以聲明事務(wù)遇到特定的異常不回滾,即使這些異常是運(yùn)行期異常。
7、Spring 編程式事務(wù)和聲明式事務(wù)的區(qū)別
編程式事務(wù)處理:所謂編程式事務(wù)指的是通過(guò)編碼方式實(shí)現(xiàn)事務(wù),允許用戶在代碼中精確定義事務(wù)的邊界。即類似于JDBC編程實(shí)現(xiàn)事務(wù)管理。管理使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對(duì)于編程式事務(wù)管理,spring推薦使用TransactionTemplate。
聲明式事務(wù)處理:管理建立在AOP之上的。其本質(zhì)是對(duì)方法前后進(jìn)行攔截,然后在目標(biāo)方法開(kāi)始之前創(chuàng)建或者加入一個(gè)事務(wù),在執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行情況提交或者回滾事務(wù)。聲明式事務(wù)最大的優(yōu)點(diǎn)就是不需要通過(guò)編程的方式管理事務(wù),這樣就不需要在業(yè)務(wù)邏輯代碼中摻雜事務(wù)管理的代碼,只需在配置文件中做相關(guān)的事務(wù)規(guī)則聲明(或通過(guò)基于@Transactional注解的方式),便可以將事務(wù)規(guī)則應(yīng)用到業(yè)務(wù)邏輯中。
簡(jiǎn)單地說(shuō),編程式事務(wù)侵入到了業(yè)務(wù)代碼里面,但是提供了更加詳細(xì)的事務(wù)管理;而聲明式事務(wù)由于基于AOP,所以既能起到事務(wù)管理的作用,又可以不影響業(yè)務(wù)代碼的具體實(shí)現(xiàn)。
8、不用事務(wù)實(shí)現(xiàn)轉(zhuǎn)賬
我們還是以轉(zhuǎn)賬為實(shí)例。不用事務(wù)看如何實(shí)現(xiàn)轉(zhuǎn)賬。在數(shù)據(jù)庫(kù)中有如下表 account ,內(nèi)容如下:
有兩個(gè)用戶 Tom 和 Marry 。他們初始賬戶余額都為 10000。這時(shí)候我們進(jìn)行如下業(yè)務(wù):Tom 向 Marry 轉(zhuǎn)賬 1000 塊。那么這在程序中可以分解為兩個(gè)步驟:
①、Tom 的賬戶余額 10000 減少 1000 塊,剩余 9000 塊。
②、Marry 的賬戶余額 10000 增加 1000 塊,變?yōu)?11000塊。
上面兩個(gè)步驟要么都執(zhí)行成功,要么都不執(zhí)行。我們通過(guò) TransactionTemplate 編程式事務(wù)來(lái)控制:
第一步:創(chuàng)建Java工程并導(dǎo)入相應(yīng)的 jar 包(這里不用事務(wù)其實(shí)不需要這么多jar包,為了后面的講解需要,我們一次性導(dǎo)入所有的jar包)
第二步:編寫(xiě) Dao 層
AccountDao 接口:
package com.ys.dao; public interface AccountDao { ? ?/** ? ? * 匯款 ? ? * @param outer 匯款人 ? ? * @param money 匯款金額 ? ? */ ? ?public void out(String outer,int money); ? ? ? ?/** ? ? * 收款 ? ? * @param inner 收款人 ? ? * @param money 收款金額 ? ? */ ? ?public void in(String inner,int money); }AccountDaoImpl 接口實(shí)現(xiàn)類
package com.ys.dao.impl; import org.springframework.jdbc.core.support.JdbcDaoSupport; import com.ys.dao.AccountDao; public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao { ? ?/** ? ? * 根據(jù)用戶名減少賬戶金額 ? ? */ ? ?@Override ? ?public void out(String outer, int money) { ? ? ? ?this.getJdbcTemplate().update("update account set money = money - ? where username = ?",money,outer); ? } ? ?/** ? ? * 根據(jù)用戶名增加賬戶金額 ? ? */ ? ?@Override ? ?public void in(String inner, int money) { ? ? ? ?this.getJdbcTemplate().update("update account set money = money + ? where username = ?",money,inner); ? } }第三步:實(shí)現(xiàn) Service 層
AccountService 接口
package com.ys.service; public interface AccountService { ? ? ? ?/** ? ? * 轉(zhuǎn)賬 ? ? * @param outer 匯款人 ? ? * @param inner 收款人 ? ? * @param money 交易金額 ? ? */ ? ?public void transfer(String outer,String inner,int money); }AccountServiceImpl 接口實(shí)現(xiàn)類
package com.ys.service.impl; import com.ys.dao.AccountDao;import com.ys.service.AccountService; public class AccountServiceImpl implements AccountService{ ? ?private AccountDao accountDao; ? ? ? ?public void setAccountDao(AccountDao accountDao) { ? ? ? ?this.accountDao = accountDao; ? } ? ?@Override ? ?public void transfer(String outer, String inner, int money) { ? ? ? ?accountDao.out(outer, money); ? ? ? ?accountDao.in(inner, money); ? } }第四步:Spring 全局配置文件 applicationContext.xml ? ?
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ? ? ? 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.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/aop ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/aop/spring-aop.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context/spring-context.xsd"> ? ? ?<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> ? ? ? ?<property name="driverClass" value="com.mysql.jdbc.Driver">property> ? ? ? ?<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test">property> ? ? ? ?<property name="user" value="root">property> ? ? ? ?<property name="password" value="root">property> ? ?bean> ? ? ? ?<bean id="accountDao" class="com.ys.dao.impl.AccountDaoImpl"> ? ? ? ?<property name="dataSource" ref="dataSource">property> ? ?bean> ? ? ? ?<bean id="accountService" class="com.ys.service.impl.AccountServiceImpl"> ? ? ? ?<property name="accountDao" ref="accountDao">property> ? ?bean>beans>第五步:測(cè)試
public class TransactionTest { ? ? ? ?@Test ? ?public void testNoTransaction(){ ? ? ? ?ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); ? ? ? ?AccountService account = (AccountService)context.getBean("accountService"); ? ? ? ?//Tom 向 Marry 轉(zhuǎn)賬1000 ? ? ? ?account.transfer("Tom", "Marry", 1000); ? } }第六步:查看數(shù)據(jù)庫(kù)表 account
上面的結(jié)果和我們想的一樣,Tom 賬戶 money 減少了1000塊。而 Marry 賬戶金額增加了1000塊。
這時(shí)候問(wèn)題來(lái)了,比如在 Tom 賬戶 money 減少了1000塊正常。而 Marry 賬戶金額增加時(shí)發(fā)生了異常,實(shí)際應(yīng)用中比如斷電(這里我們?nèi)藶闃?gòu)造除數(shù)不能為0的異常),如下:
那么這時(shí)候我們執(zhí)行測(cè)試程序,很顯然會(huì)報(bào)錯(cuò),那么數(shù)據(jù)庫(kù)是什么情況呢?
數(shù)據(jù)庫(kù)account :
我們發(fā)現(xiàn),程序執(zhí)行報(bào)錯(cuò)了,但是數(shù)據(jù)庫(kù) Tom 賬戶金額依然減少了 1000 塊,但是 Marry 賬戶的金額卻沒(méi)有增加。這在實(shí)際應(yīng)用中肯定是不允許的,那么如何解決呢?
9、編程式事務(wù)處理實(shí)現(xiàn)轉(zhuǎn)賬(TransactionTemplate )
上面轉(zhuǎn)賬的兩步操作中間發(fā)生了異常,但是第一步依然在數(shù)據(jù)庫(kù)中進(jìn)行了增加操作。實(shí)際應(yīng)用中不會(huì)允許這樣的情況發(fā)生,所以我們這里用事務(wù)來(lái)進(jìn)行管理。
Dao 層不變,我們?cè)?Service 層注入 TransactionTemplate 模板,因?yàn)槭怯媚0鍋?lái)管理事務(wù),所以模板需要注入事務(wù)管理器 ?DataSourceTransactionManager 。而事務(wù)管理器說(shuō)到底還是用底層的JDBC在管理,所以我們需要在事務(wù)管理器中注入 DataSource。這幾個(gè)步驟分別如下:
AccountServiceImpl 接口:
package com.ys.service.impl; import org.springframework.transaction.TransactionStatus;import org.springframework.transaction.support.TransactionCallbackWithoutResult;import org.springframework.transaction.support.TransactionTemplate; import com.ys.dao.AccountDao;import com.ys.service.AccountService; public class AccountServiceImpl implements AccountService{ ? ?private AccountDao accountDao; ? ?private TransactionTemplate transactionTemplate; ? ? ? ?public void setTransactionTemplate(TransactionTemplate transactionTemplate){ ? ? ? ?this.transactionTemplate = transactionTemplate; ? } ? ?public void setAccountDao(AccountDao accountDao) { ? ? ? ?this.accountDao = accountDao; ? } ? ?@Override ? ?public void transfer(final String outer,final String inner,final int money){ ? ? ? ?transactionTemplate.execute(new TransactionCallbackWithoutResult() { ? ? ? ? ? ?@Override ? ? ? ? ? ?protected void doInTransactionWithoutResult(TransactionStatus arg0){ ? ? ? ? ? ? ? ?accountDao.out(outer, money); ? ? ? ? ? ? ? ?//int i = 1/0; ? ? ? ? ? ? ? ?accountDao.in(inner, money); ? ? ? ? ? } ? ? ? }); ? } }Spring 全局配置文件 applicationContext.xml: ? ?
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ? ? ? 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.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/aop ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/aop/spring-aop.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context/spring-context.xsd"> ? ? ?<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> ? ? ? ?<property name="driverClass" value="com.mysql.jdbc.Driver">property> ? ? ? ?<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test">property> ? ? ? ?<property name="user" value="root">property> ? ? ? ?<property name="password" value="root">property> ? ?bean> ? ? ? ?<bean id="accountDao" class="com.ys.dao.impl.AccountDaoImpl"> ? ? ? ?<property name="dataSource" ref="dataSource">property> ? ?bean> ? ? ? ?<bean id="accountService" class="com.ys.service.impl.AccountServiceImpl"> ? ? ? ?<property name="accountDao" ref="accountDao">property> ? ? ? ?<property name="transactionTemplate" ref="transactionTemplate">property> ? ?bean> ? ? ? ? ? ?<bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate"> ? ? ? ?<property name="transactionManager" ref="txManager">property> ? ?bean> ? ? ? ? ? ?<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> ? ? ? ?<property name="dataSource" ref="dataSource">property> ? ?bean>beans>測(cè)試文件保持不變,可以分兩次測(cè)試,第一次兩次操作沒(méi)有發(fā)生異常,然后數(shù)據(jù)庫(kù)正常改變了。第二次操作中間發(fā)生了異常,發(fā)現(xiàn)數(shù)據(jù)庫(kù)內(nèi)容沒(méi)變。
如果大家有興趣也可以試試底層的PlatformTransactionManager來(lái)進(jìn)行事務(wù)管理,我這里給出主要代碼:
//定義一個(gè)某個(gè)框架平臺(tái)的TransactionManager,如JDBC、Hibernate ? ? ? ?DataSourceTransactionManager dataSourceTransactionManager = ? ? ? ? ? ? ? ?new DataSourceTransactionManager(); ? ? ? ?dataSourceTransactionManager.setDataSource(this.getJdbcTemplate().getDataSource()); // 設(shè)置數(shù)據(jù)源 ? ? ? ? ? ?DefaultTransactionDefinition transDef = new DefaultTransactionDefinition(); // 定義事務(wù)屬性 ? ? ? ?transDef.setPropagationBehavior(DefaultTransactionDefinition.PROPAGATION_REQUIRED); // 設(shè)置傳播行為屬性 ? ? ? ?TransactionStatus status = dataSourceTransactionManager.getTransaction(transDef); // 獲得事務(wù)狀態(tài) ? ? ? ?try { ? ? ? ? ? ?// 數(shù)據(jù)庫(kù)操作 ? ? ? ? ? ?accountDao.out(outer, money); ? ? ? ? ? ?int i = 1/0; ? ? ? ? ? ?accountDao.in(inner, money); ? ? ? ? ? ? ? ? ? ? ? ?dataSourceTransactionManager.commit(status);// 提交 ? ? ? } catch (Exception e) { ? ? ? ? ? ?dataSourceTransactionManager.rollback(status);// 回滾 ? ? ? }10、聲明式事務(wù)處理實(shí)現(xiàn)轉(zhuǎn)賬(基于AOP的 xml 配置)
Dao 層和 Service 層與我們最先開(kāi)始的不用事務(wù)實(shí)現(xiàn)轉(zhuǎn)賬保持不變。主要是 applicationContext.xml 文件變化了。
我們?cè)?applicationContext.xml 文件中配置 aop 自動(dòng)生成代理,進(jìn)行事務(wù)管理:
①、配置管理器
②、配置事務(wù)詳情
③、配置 aop ? ? ? ? ? ? ? ? ? ? ? ? ? ?
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" ? ? ? xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" ? ? ? xmlns:context="http://www.springframework.org/schema/context" ? ? ? xmlns:aop="http://www.springframework.org/schema/aop" ? ? ? xmlns:tx="http://www.springframework.org/schema/tx" ? ? ? xsi:schemaLocation="http://www.springframework.org/schema/beans ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/beans/spring-beans.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/aop ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/aop/spring-aop.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/context/spring-context.xsd ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/tx ? ? ? ? ? ? ? ? ? ? ? ? ? http://www.springframework.org/schema/tx/spring-tx.xsd"> ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> ? ? ? ?<property name="driverClass" value="com.mysql.jdbc.Driver">property> ? ? ? ?<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test">property> ? ? ? ?<property name="user" value="root">property> ? ? ? ?<property name="password" value="root">property> ? ?bean> ? ? ? ?<bean id="accountDao" class="com.ys.dao.impl.AccountDaoImpl"> ? ? ? ?<property name="dataSource" ref="dataSource">property> ? ?bean> ? ? ? ?<bean id="accountService" class="com.ys.service.impl.AccountServiceImpl"> ? ? ? ?<property name="accountDao" ref="accountDao">property> ? ?bean> ? ? ? ? ? ?<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> ? ? ? ?<property name="dataSource" ref="dataSource">property> ? ?bean> ? ? ? ? ? ?<tx:advice id="txAdvice" transaction-manager="txManager"> ? ? ? ?<tx:attributes> ? ? ? ? ? ?<tx:method name="transfer" propagation="REQUIRED" isolation="DEFAULT"/> ? ? ? ?tx:attributes> ? ?tx:advice> ? ? ? ? ? ?<aop:config> ? ? ? ?<aop:advisor advice-ref="txAdvice" pointcut="execution(* com.ys.service..*.*(..))"/> ? ?aop:config>beans>測(cè)試類這里我們就不描述了,也是分有異常和無(wú)異常進(jìn)行測(cè)試,發(fā)現(xiàn)與預(yù)期結(jié)果是吻合的。
11、聲明式事務(wù)處理實(shí)現(xiàn)轉(zhuǎn)賬(基于AOP的 注解 配置)
分為如下兩步:
①、在applicationContext.xml 配置事務(wù)管理器,將并事務(wù)管理器交予spring
②、在目標(biāo)類或目標(biāo)方法添加注解即可 @Transactional
首先在 applicationContext.xml 文件中配置如下:
? ?<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> ? ? ? ?<property name="dataSource" ref="dataSource">property> ? ?bean> ? ? ? ?<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>其次在目標(biāo)類或者方法添加注解@Transactional。如果在類上添加,則說(shuō)明類中的所有方法都添加事務(wù),如果在方法上添加,則只有該方法具有事務(wù)。
package com.ys.service.impl; import javax.annotation.Resource; import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;import org.springframework.transaction.annotation.Isolation;import org.springframework.transaction.annotation.Propagation;import org.springframework.transaction.annotation.Transactional; import com.ys.dao.AccountDao;import com.ys.service.AccountService; @Transactional(propagation=Propagation.REQUIRED , isolation = Isolation.DEFAULT)@Service("accountService")public class AccountServiceImpl implements AccountService{ ? ?@Resource(name="accountDao") ? ?private AccountDao accountDao; ? ? ? ?public void setAccountDao(AccountDao accountDao) { ? ? ? ?this.accountDao = accountDao; ? } ? ?@Override ? ?public void transfer(String outer, String inner, int money) { ? ? ? ?accountDao.out(outer, money); ? ? ? ?//int i = 1/0; ? ? ? ?accountDao.in(inner, money); ? } } 與50位技術(shù)專家面對(duì)面20年技術(shù)見(jiàn)證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的batch spring 重复执行_一个3年老javaer竟然连Spring的事务管理都不知道,惊呆了的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 苹果更新 iPad 和 Mac 端 Lo
- 下一篇: java框架ssm整合_SSM三大框架整