Spring的AOP配置
1.第一種:註解配置AOP
2.第二種:xml配置AOP
使用Spring AOP實現聲明式事務管理
1.基於XML配置,現在也有很多通過註解的方式來配置事務管理類
(1)配置事務管理類
[html] view plain copy
- <!-- 定義事務管理器 -->
- <bean id="transactionManager"
- class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
- <property name="dataSource" ref="dataSource" />
- </bean>
在spring的配置中配置數據源(dataSource)、事務管理器,事務管理器使用不同的orm框架事務管理器類就不同,mybatis 是org.springframework.jdbc.datasource.DataSourceTransactionManager 。而hibernate事務管理器爲org.springframework.orm.hibernate3.HibernateTransactionManager
或者通過註解配置事務管理類
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory(){
}
@Bean
public PlatformTransactionManager transactionManager() {
LocalContainerEntityManagerFactoryBean factoryBean = entityManagerFactory();
if (factoryBean != null) {
return new JpaTransactionManager(factoryBean.getObject());
}
return null;
}
(2)配置事務屬性
[html] view plain copy
- <!-- 配置事務的屬性 -->
- <tx:advice id="TestAdvice" transaction-manager="transactionManager">
- <!--配置事務傳播性,隔離級別以及超時回滾等問題 -->
- <tx:attributes>
- <tx:method name="search*" propagation="REQUIRED" read-only="true" isolation="DEFAUT" TIMEOUT="-1" />
- <tx:method name="del*" propagation="REQUIRED" />
- <tx:method name="update*" propagation="REQUIRED" />
- <tx:method name="add*" propagation="REQUIRED" />
- </tx:attributes>
- </tx:advice>
事務屬性在<tx:method>中進行設置,Spring支持對不同的方法設置不同的事務屬性,所以可以爲一個<tx:advice>設置多個<tx:method>,其中name屬性指定匹配的方法(這裏需要對這些方法名進行約定,如果事務切入點在service上,則最好和Dao的方法命名區分開,也不要使用get set關鍵字,防止和屬性的getter setter發生混淆)
事務有以下幾個常用屬性:
a.read-only:設置該事務中是否允許修改數據。(對於只執行查詢功能的事務,設置爲TRUE可以提高事務的執行速度)
b.propagation:事務的傳播機制。一般設置爲required。可以保證在事務中的代碼只在當前事務中運行,防止創建多個事務。
c.isolation:事務隔離級別。不是必須的。默認值是default。
d.timeout:允許事務運行的最長時間,以秒爲單位。
e.rollback-for:觸發回滾的異常。
f.no-rollback-for:不會觸發回滾的異常。
Table 9.1. <tx:method/> 有關的設置
屬性 | 是否需要? | 默認值 | 描述 |
---|---|---|---|
name | 是 |
與事務屬性關聯的方法名。通配符(*)可以用來指定一批關聯到相同的事務屬性的方法。 如:'get*'、'handle*'、'on*Event'等等。 |
|
propagation | 不 | REQUIRED | 事務傳播行爲 |
isolation | 不 | DEFAULT | 事務隔離級別 |
timeout | 不 | -1 | 事務超時的時間(以秒爲單位) |
read-only | 不 | false | 事務是否只讀? |
rollback-for | 不 |
將被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException' |
|
no-rollback-for | 不 |
不 被觸發進行回滾的 Exception(s);以逗號分開。 如:'com.foo.MyBusinessException,ServletException' |
***實際開發中,對於只執行查詢功能的事務,要設置read-only爲TRUE,其他屬性一般使用默認值即可。
(3)配置事務的AOP切入點
[html] view plain copy
- <aop:config>
- <!--配置事務切點 -->
- <aop:pointcut id="services"
- expression="execution(public* com.pb.service.*.*(..))" />
- <aop:advisor pointcut-ref="services" advice-ref="TestAdvice" />
- </aop:config>
該設置的含義是:對於com.pb.service.impl包及子包下的所有類的所有公共方法進行切入。(被切入的 方法經過<tx:method>篩選)web應用程序最合適的事務切入點是Service的方法上。
----通過以上三個步驟設置好聲明式事務後,當Service中 的業務方法被調用之前,Spring會獲取事務對象並啓動事務。並使用try-catch-finally來處理異常。業務方法執行成功則會提交事務,默認情況下如果拋出了RuntimeException 或者Rrror 對象就會回滾事務。(注意: 這裏注意一下,在tx:method中配置了rollback_for 中配置的Exception 這個是運行時的異常纔會回滾不然其他異常是不會回滾的!)
2.使用annotation配置
*1.在事務管理的dao實現類之前標註@Transactional
*2.在要進行事務管理的方法前加上@Transactional(propagation= Propagation.REQUIRED)
*3.在配置文件中指定驅動:<tx:annotation-driven transaction-manager="transactionManager" />
[html] view plain copy
- package demo.spring.dao;
- import java.util.Iterator;
- import java.util.List;
- import javax.sql.DataSource;
- import org.springframework.jdbc.core.JdbcTemplate;
- import org.springframework.transaction.annotation.Propagation;
- import org.springframework.transaction.annotation.Transactional;
- import demo.spring.entity.Person;
- @Transactional//將此類進行事務管理
- public class PersonDaoImpl implements PersonDao {
- private JdbcTemplate jt;
- public void setDataSource(DataSource dataSource){
- jt = new JdbcTemplate(dataSource);
- }
- @Override
- public void insert(long id, String name, int age) {
- jt.update("insert into person values('"+id+"','"+name+"','"+age+"')");
- }
- @Transactional(propagation= Propagation.REQUIRED)//定義要事務管理的方法,指定傳播行爲
- public void batchInsert(List persons) {
- for(Iterator it = persons.iterator(); it.hasNext(); ){
- Person p = (Person) it.next();
- insert(p.getId(),p.getName(),p.getAge());
- }
- }
- }
以上內容轉載於:https://blog.csdn.net/c_w_d/article/details/63252340
思考:在配置文件中對com.pb.service.impl包及子包下的所有類的所有公共方法進行切入,但是在這個包下面的要進行事務管理的方法沒有加@Transactional(propagation= Propagation.REQUIRED),還能對該方法進行事務管理嗎?
Spring中常用事務的傳播機制(事務類型):
- PROPAGATION_REQUIRED--支持當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。
- 解釋如下:1、如果ServiceA.methodA已經起了事務,這時調用ServiceB.methodB,ServiceB.methodB看到自己已經運行在ServiceA.methodA的事務內部,就不再起新的事務。這時只有外部事務並且他們是共用的,所以這時ServiceA.methodA或者ServiceB.methodB無論哪個發生異常methodA和methodB作爲一個整體都將一起回滾。
2、如果ServiceA.methodA沒有事務,ServiceB.methodB就會爲自己分配一個事務。這樣,在ServiceA.methodA中是沒有事務控制的。只是在ServiceB.methodB內的任何地方出現異常,ServiceB.methodB將會被回滾,不會有ServiceA.methodA的回滾 - PROPAGATION_SUPPORTS--支持當前事務,如果當前沒有事務,就以非事務方式執行。
- PROPAGATION_MANDATORY--支持當前事務,如果當前沒有事務,就拋出異常。
- PROPAGATION_REQUIRES_NEW--新建事務,如果當前存在事務,把當前事務掛起。
- 解釋如下:這個就比較繞口了。 比如我們設計ServiceA.methodA的事務級別爲PROPAGATION_REQUIRED,ServiceB.methodB的事務級別爲PROPAGATION_REQUIRES_NEW,那麼當執行到ServiceB.methodB的時候,ServiceA.methodA所在的事務就會掛起,ServiceB.methodB會起一個新的事務,等待ServiceB.methodB的事務完成以後,他才繼續執行。他與PROPAGATION_REQUIRED 的事務區別在於事務的回滾程度了。因爲ServiceB.methodB是新起一個事務,那麼就是存在兩個不同的事務。如果ServiceB.methodB已經提交,那麼ServiceA.methodA失敗回滾,ServiceB.methodB是不會回滾的。如果ServiceB.methodB失敗回滾,如果他拋出的異常被ServiceA.methodA捕獲,ServiceA.methodA事務仍然可能提交。
- PROPAGATION_NOT_SUPPORTED--以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。
- 解釋如下:比如ServiceA.methodA的事務級別是PROPAGATION_REQUIRED ,而ServiceB.methodB的事務級別是PROPAGATION_NOT_SUPPORTED ,
那麼當執行到ServiceB.methodB時,ServiceA.methodA的事務掛起,而他以非事務的狀態運行完,再繼續ServiceA.methodA的事務。 - PROPAGATION_NEVER--以非事務方式執行,如果當前存在事務,則拋出異常。
- 解釋如下:假設ServiceA.methodA的事務級別是PROPAGATION_REQUIRED, 而ServiceB.methodB的事務級別是PROPAGATION_NEVER ,
那麼ServiceB.methodB就要拋出異常了。 - PROPAGATION_REQUIRED類似的操作。
- PROPAGATION_NESTED--如果當前存在事務,則在嵌套事務內執行。如果當前沒有事務,則進行與PROPAGATION_REQUIRED類似的操作。
解釋如下: 理解Nested的關鍵是savepoint。他與PROPAGATION_REQUIRES_NEW的區別是,PROPAGATION_REQUIRES_NEW另起一個事務,將會與 他的父事務相互獨立,而Nested的事務和他的父事務是相依的,他的提交是要等和他的父事務一塊提交的。也就是說,如果父事務最後回滾, 他也要回滾的。而Nested事務的好處是他有一個savepoint。
*****************************************
ServiceA {
void methodA() {
try {
//savepoint
ServiceB.methodB(); //PROPAGATION_NESTED 級別
} catch (SomeException) {
// 執行其他業務, 如 ServiceC.methodC();
}
}
}
********************************************
也就是說ServiceB.methodB失敗回滾,那麼ServiceA.methodA也會回滾到savepoint點上,ServiceA.methodA可以選擇另外一個分支,比如
ServiceC.methodC,繼續執行,來嘗試完成自己的事務。
Spring中常用事務的隔離級別:
- ISOLATION_DEFAULT:用底層數據庫的默認隔離級別,數據庫管理員設置什麼就是什麼
- ISOLATION_READ_UNCOMMITTED(未提交讀):最低隔離級別、事務未提交前,就可被其他事務讀取(會出現幻讀、髒讀、不可重複讀)
- ISOLATION_READ_COMMITTED(提交讀):一個事務提交後才能被其他事務讀取到(該隔離級別禁止其他事務讀取到未提交事務的數據、所以還是會造成幻讀、不可重複讀)、sql server默認級別
- ISOLATION_REPEATABLE_READ(可重複讀):可重複讀,保證多次讀取同一個數據時,其值都和事務開始時候的內容是一致,禁止讀取到別的事務未提交的數據(該隔離基本可防止髒讀,不可重複讀(重點在修改),但會出現幻讀(重點在增加與刪除))(MySql默認級別,更改可通過set transaction isolation level 級別)
- ISOLATION_SERIALIZABLE(序列化):代價最高最可靠的隔離級別(該隔離級別能防止髒讀、不可重複讀、幻讀)
- 丟失更新:兩個事務同時更新一行數據,最後一個事務的更新會覆蓋掉第一個事務的更新,從而導致第一個事務更新的數據丟失,這是由於沒有加鎖造成的;
- 幻讀:同樣的事務操作過程中,不同時間段多次(不同事務)讀取同一數據,讀取到的內容不一致(一般是行數變多或變少)。
- 髒讀:一個事務讀取到另外一個未提及事務的內容,即爲髒讀。
- 不可重複讀:同一事務中,多次讀取內容不一致(一般行數不變,而內容變了)。
幻讀與不可重複讀的區別:幻讀的重點在於插入與刪除,即第二次查詢會發現比第一次查詢數據變少或者變多了,以至於給人一種幻象一樣,而不可重複讀重點在於修改,即第二次查詢會發現查詢結果比第一次查詢結果不一致,即第一次結果已經不可重現了。
數據庫隔離級別越高,執行代價越高,併發執行能力越差,因此在實際項目開發使用時要綜合考慮,爲了考慮併發性能一般使用提交讀隔離級別,它能避免丟失更新和髒讀,儘管不可重複讀和幻讀不能避免,但可以在可能出現的場合使用悲觀鎖或樂觀鎖來解決這些問題。
悲觀鎖與樂觀鎖可參考:http://blog.csdn.net/liaohaojian/article/details/62416972
第三部分
關於AOP切入點pointcut中的expression的理解
- <aop:pointcut id="services"
- expression="execution(public* com.pb.service.*.*(..))" />
execution(* com.spring.aop.*.*(..))
這是 com.spring.aop包下所有的類的所有方法。。
第一個*代表所有的返回值類型
第二個*代表所有的類
第三個*代表類所有方法
最後一個..代表所有的參數。
網上其它示例1:
<aop:pointcut id="serviceMethod" expression="execution(* *.*Service.*(..))" />
第一個* 表示任意返回值類型
第二個* 表示以任意名字開頭的package. 如 com.xx.
第三個* 表示 通配 *service下的任意類
第四個* 表示 以任意名字開頭的方法名
最後二個.. 表示通配 方法可以有0個或多個參數
部分轉載於:https://blog.csdn.net/qq525099302/article/details/53996344,
https://blog.csdn.net/wwh578867817/article/details/51736723