spring事务管理-xml配置aop事务(重点)
生活随笔
收集整理的這篇文章主要介紹了
spring事务管理-xml配置aop事务(重点)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
剛才咱們是使用了模板操作咱們事務,當然使用模板操作比較low,還得寫代碼,每個方法都寫太費勁了,首先把之前寫的先注釋掉,把這個transfer這個代碼直接復制一份,然后底下展一份,留著注釋掉就行了,上面的恢復原狀,是這個意思不,然后事務模板的話先留著吧,然后不用他就完事了,然后接下來看一下AOP事務,AOP事務呢,咱們先講一下原理,咱們學習了Spring中的AOP,說這個簡單也簡單,說起來也就這么個事,首先是通知,然后你再搞一個目標對象,然后代理,然后把這個通知織入到目標對象當中,形成一個代理對象,然后代理對象當中,這個方法,比如這個目標對象當中,方法當中,要實現一個業務邏輯,然后咱們這個通知的話,加上事務管理,然后這個變成代理對象之后,把這個事務管理業務邏輯調用,相當于動態的合在一起了,不就這點事嗎,那咱們的Spring的AOP,這個Spring的AOP事務,他事其實就是這么一個事,Spring給我準備了一個事務的通知,SpringAOP,也就是他給我們準備了一個事務的通知,他已經寫好了,他寫好了一個事務通知,你看通知都不需要咱們寫了,知道啥意思不,而這個通知我問你,假設Spring沒寫,要咱們自己去寫,用那種類型的通知,你能想到嗎,是不是環繞通知,是不是在方法之前開啟,之后關閉,然后方法還得控制,用try catch包裹一下,如果出了異常,咱們是不是再回滾,其實這塊的話通知,計算Spring沒提供,咱們也能拿環繞通知寫出來,重要是Spring寫的,就不用寫了,所以通知現在已經有了,目標對象咱們現在有沒有,目標對象是咱們寫好的service,那咱們離管理業務邏輯還差什么事,你這兩條線連成代理對象要告訴他能夠配置,所以這塊你只需要配置就完事了,這個前面講Spring事務配置就完事了,所以咱們接下來萬事俱備,只差配置,接下來咱們來配置一下,準備工作咱們給你列一下,使用AOP來管理的話,首先你得導包,導什么包呢,4+2咱們已經有了,你要玩AOP的話,AOP的包要導進來,aspect是不是要導入進來,然后除此之外還有aop聯盟,然后還有一個是咱們的織入,weaving,織入包,這是咱們昨天下午玩AOP用的包,粘貼到咱們的lib目錄下,這樣的話全導入進來了,還需要再做另外一件事,配置的話需要導入一個新的命名空間
導入新的約束,這個約束是tx約束,你要想配置事務通知,你得需要tx約束來配,這個事咱們已經是干了第四遍了,咱們之前導過beans,context,aop,這是第四個,tx,add在這選擇spring,然后找tx
然后選擇Schema Location,復制文件名粘到這里
open with xml editor,然后選design,然后beans右鍵
那這里的可以導入兩個了,http://www.springframework.org/schema/aop這一對復制,最后這個也復制
然后再add一個,再來一個tx
這一對復制,然后最后tx
這樣咱們的命名空間一共要導四個,加起來一共導4個,有一個問題不知道你們怎么想,還記得這些命名空間是干啥的,beans是咱們第一個命名空間,所以這是最基本的,這不用說,context你拿出來干啥的,注解,但是咱們現在沒有注解,讀取properties配置文件,配置用的,AOP咱們現在沒用,所以這是配置AOP的,tx需要配置事務通知,接下來的話第三步,約束導完以后,目標對象也有了,那咱們就需要配置通知,通知的話咱們看怎么配,通知就在模板下面,在這配置事務通知,通知這個東西,是Spring已經寫好了,咱們壓根不用寫代碼,但是咱們得配一下,是叫advice吧,然后advice需要指明事務管理器,你這個transactionManager是管理事務的核心,只要是用Spring管理事務,肯定需要這玩意,是不是這個意思,這是咱們操作事務的核心,然后再到這里面,要使用tx:attributes,來指定咱們事務的屬性,然后指定屬性的時候,它是以方法為單位指定的,比如咱們service這個方法的話,transfer方法,所以你在配置里面指明方法是transfer,然后接下來的話你就可以配置屬性,就是咱們開始的事務屬性,咱們一共有三個,分別是隔離級別,隔離級別一共有幾個,是不是4個,讀未提交,讀已提交,可以重復讀,串行化,或者你不想改的話,你也可以用default默認級別,這塊我就改一下,REPEATABLE_READ,還有一個屬性propagation,這是咱們的傳播行為,是不是REQUIRED這個,然后這里還有一個read-only,如果為true的話,現在這個只讀,我這個方法顯然是需要修改數據庫的,所以千萬別配true,就用false,看明白啥意思不,這樣的話咱們事務通知就配好了,這樣的話他遇到transfer方法,他就知道transfer方法呢,他就需要后面這些屬性,大家配完以后,將來業務方法有好幾百個,難道我要配好幾百行嗎,聽明白啥意思吧,如果以后咱們再來一個業務方法,太痛苦了,我告訴你,在真正企業當中,他怎么配呢,看好,他們是這樣配的,save*,persist*,update*,modify*,然后delete*,remove*,get*,find*,這啥意思呢,企業當中開發是這樣,他直接使用通配符的方式來完成批量配置,你配置save*的意思就是說,你這個service的方法名只要以save開頭,后面無論你寫什么,如果你persist開頭的方法,都應用后續的屬性,這里就是把企業中的兩套增刪改查,命名都給你寫上了,直接使用星號通配符,來批量為所有的service方法,來進行事務屬性的定制,那這樣的話反過來,以后再寫service方法的時候,咱們就要按照咱們定的規則來吧,那咱們現在用transfer這個方法,那是不是要換成別的名字,按照剛才咱們配置的規則開頭,明白啥意思吧,當然的話現在不打算改了,而且為了讓你們看的明確一點,我會在底下再補一個,看明白啥意思不,那transfer就單獨的應用下面這一個,如果其中以get或者find開頭的,往往only要配成true,這樣就可以防止在find或者get中間不小心操作,操作就會給你報錯的,這樣就是業務當中事務通知的配置,記住它是以方法為單位,進行配置了,而這個方法的話你不一定要傻乎乎的,寫死一個方法名,你可以通過通配符這種方式,是不是批量來指定方法,看明白啥意思不,那通知寫好之后,目標對象也有了,接下來就要配置織入,配置織入,那這個配置織入的話看著,咱們就使用AOP,然后config,這個配置方式跟昨天有點像,后面有點區別,首先要指定一個pointcut,就是指定切點,execution,然后括號方法,在這里像表達式第一次填,怎么填呢,找到transfer方法,是不是粘過來,加入星號,返回值東西,這個方法名改成*,對所有方法切入,這個類型的話改成..,任意,咱們一般是應用到所有的service當中去,這樣就配完了,然后來冉鳴一個名字,叫txPc,transaction Point cut,然后再來一個aop,這個aspect是手動指定前置,咱們現在已經有現成的通知的話,就可以使用aspect,aspect就叫切面,還記得名詞切面,切面是不是二合一,是通知加切入點,aop是advisor,配置切面,在Spring切面是advisor,通知的引用,advice-ref,pointcut-ref是切點的引用,這樣的話你只要告訴他通知是誰呢,給這個通知起個名字,id=txAdvice,txAdvice,然后pointcut-ref是txPc,知道啥意思不,把剛才咱們的通知,應用到這個切入點,然后就完了,然后你再加入這個配置之后,他就會自動去根據你的這個切點表達式,對所有符合條件的,這個對象,織入這個通知的,而在織入通知之后,需要進一步你這個方法要使用哪個屬性,來執行對應的事務,所以說白了你只要配置兩行,然后配置完以后,在demo中配置一下,數據庫恢復一下原狀,然后接下來看到,現在轉500,現在沒有異常轉成功了,900,1100,現在事務有沒有加成功很簡單,你是不是要在這造一個異常,int i = 1/0,然后再到這里執行一下,這回執行報錯了,然后重點是看數據庫,是不是還是900,1100,這里就是使用XML配置AOP,這個配置方式,第三步配置通知,以方法為單位,指定方法應用什么事務屬性,isolation是隔離級別,propagation是隔離級別,然后read-only是否只讀,這樣的話事務通知就配完了,然后接下來就看第四個了,配置將通知織入目標對象,然后這個配置就是剛才看的,就這兩行,切點表達式,切面再提醒一下,切面就是通知加切點,然后提供advice-ref,這里寫什么東西,通知的名稱,然后point-cut是切點的名稱,切點通知有了以后,去加入通知了
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://www.springframework.org/schema/beans" 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-4.2.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd "><!-- 指定spring讀取db.properties配置 -->
<context:property-placeholder location="classpath:db.properties" /><!-- 事務核心管理器,封裝了所有事務操作. 依賴于連接池 -->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" ><property name="dataSource" ref="dataSource" ></property>
</bean><!-- 事務模板對象 -->
<bean name="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate" ><property name="transactionManager" ref="transactionManager" ></property>
</bean><!-- 配置事務通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager" ><tx:attributes><!-- 以方法為單位,指定方法應用什么事務屬性isolation:隔離級別propagation:傳播行為read-only:是否只讀--><tx:method name="save*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><tx:method name="persist*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><tx:method name="update*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><tx:method name="modify*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><tx:method name="delete*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><tx:method name="remove*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /><tx:method name="get*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" /><tx:method name="find*" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="true" /><tx:method name="transfer" isolation="REPEATABLE_READ" propagation="REQUIRED" read-only="false" /></tx:attributes>
</tx:advice><!-- 配置織入 -->
<aop:config ><!-- 配置切點表達式 --><aop:pointcut expression="execution(* com.learn.service.*ServiceImpl.*(..))" id="txPc"/><!-- 配置切面 : 通知+切點advice-ref:通知的名稱pointcut-ref:切點的名稱--><aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config><!-- 1.連接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" ><property name="jdbcUrl" value="${jdbc.jdbcUrl}" ></property><property name="driverClass" value="${jdbc.driverClass}" ></property><property name="user" value="${jdbc.user}" ></property><property name="password" value="${jdbc.password}" ></property>
</bean><!-- 2.Dao-->
<bean name="accountDao" class="com.learn.dao.AccountDaoImpl" ><property name="dataSource" ref="dataSource" ></property>
</bean>
<!-- 3.Service-->
<bean name="accountService" class="com.learn.service.AccountServiceImpl" ><property name="ad" ref="accountDao" ></property><property name="tt" ref="transactionTemplate" ></property>
</bean> </beans>
package com.learn.dao;public interface AccountDao {//加錢void increaseMoney(Integer id,Double money);//減錢void decreaseMoney(Integer id,Double money);
}
package com.learn.dao;import org.springframework.jdbc.core.support.JdbcDaoSupport;public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {@Overridepublic void increaseMoney(Integer id, Double money) {getJdbcTemplate().update("update t_account set money = money+? where id = ? ", money,id);}@Overridepublic void decreaseMoney(Integer id, Double money) {getJdbcTemplate().update("update t_account set money = money-? where id = ? ", money,id);}}
package com.learn.service;public interface AccountService {//轉賬方法void transfer(Integer from,Integer to,Double money);}
package com.learn.service;import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.support.TransactionTemplate;import com.learn.dao.AccountDao;@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=true)
public class AccountServiceImpl implements AccountService {private AccountDao ad ;private TransactionTemplate tt;@Override@Transactional(isolation=Isolation.REPEATABLE_READ,propagation=Propagation.REQUIRED,readOnly=false)public void transfer(final Integer from,final Integer to,final Double money) {//減錢ad.decreaseMoney(from, money);int i = 1/0;//加錢ad.increaseMoney(to, money);}/* @Overridepublic void transfer(final Integer from,final Integer to,final Double money) {tt.execute(new TransactionCallbackWithoutResult() {@Overrideprotected void doInTransactionWithoutResult(TransactionStatus arg0) {//減錢ad.decreaseMoney(from, money);int i = 1/0;//加錢ad.increaseMoney(to, money);}});}
*/public void setAd(AccountDao ad) {this.ad = ad;}public void setTt(TransactionTemplate tt) {this.tt = tt;}}
package com.learn.tx;import javax.annotation.Resource;import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;import com.learn.service.AccountService;@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {@Resource(name="accountService")private AccountService as;@Testpublic void fun1(){as.transfer(1, 2, 100d);}
}
?
總結
以上是生活随笔為你收集整理的spring事务管理-xml配置aop事务(重点)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: spring事务管理-Transacti
- 下一篇: spring事务管理-注解配置aop事务