問題
a方法,b方法,都通過aop加上了事物控制,a中調用了b方法,那麼一共幾次事物
準備
1.創建數據庫
-- 創建數據庫
use test;
-- 建表
create table account(
id int not null auto_increment,
name varchar(20) not null ,
money double not null
);
INSERT into account(id,name,money) VALUE
(1,"aaa",1000),
(1,"bbb",1000),
(1,"ccc",1000)
2.xml配置,實例化了兩個 service 類,一個dao類,開啓事務註解驅動
<!--spring事務管理器-->
<bean name="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
<!--配置業務層-->
<bean id="accountDaoImpl" class="com.test.demo4.AccountDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean id="accountServiceImpl" class="com.test.demo4.AccountServiceImpl"></bean>
<bean id="accountServiceImpl2" class="com.test.demo4.AccountServiceImpl2"></bean>
3.dao 類
public class AccountDaoImpl extends JdbcDaoSupport implements AccountDao {
@Override
public void add(String name, double money) {
String sql = "update `account` set money = money + "+money+" where `name` = '"+name+"'";
getJdbcTemplate().execute(sql);
}
@Override
public void reduce(String name, double money) {
String sql = "update `account` set money = money - "+money+" where `name` = '"+name+"'";
getJdbcTemplate().execute(sql);
}
}
4.service 類
// service 1
public class AccountServiceImpl implements AccountService {
@Autowired
private AccountDao accountDao;
@Autowired
private AccountServiceImpl2 accountServiceImpl2;
@Override
public void transfer(String from, String to, double money) {
add(to,money);
try {
//accountServiceImpl2.reduce(from,money);
reduce(from,money);
}catch (Exception e){
System.out.println("1111111");
}
}
public void add(String to, double money){
accountDao.add(to,money);
}
public void reduce(String to, double money){
int i = 1/0;
accountDao.reduce(to,money);
}
}
// service 2
public class AccountServiceImpl2 {
@Autowired
private AccountDao accountDao;
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void reduce(String to, double money){
int i = 1/0;
accountDao.reduce(to,money);
}
}
5.測試類
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext4.xml")
public class TestService {
@Autowired
private AccountService accountService;
@Test
public void test(){
accountService.transfer("aaa","bbb",200);
}
}
測試
1.當 a , b 方法在同一個類中時,兩個方法的 事務傳播行爲都設置爲 Propagation.REQUIRED
即 AccountServiceImpl 中transfer 的內容爲
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
@Override
public void transfer(String from, String to, double money) {
add(to,money);
try {
//accountServiceImpl2.reduce(from,money);
reduce(from,money);
}catch (Exception e){
System.out.println("1111111");
}
}
AccountServiceImpl 中reduce 的內容爲
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void reduce(String to, double money){
int i = 1/0;
accountDao.reduce(to,money);
}
測試結果:
當設置 AccountServiceImpl 中transfer 的傳播行爲是 Propagation.REQUIRED,AccountServiceImpl 中reduce 的傳播行爲是 REQUIRES_NEW 時,
測試結果:
2.當 a , b 方法不在同一個類中時,兩個方法的 事務傳播行爲都設置爲 Propagation.REQUIRED
即 AccountServiceImpl 中transfer 的內容爲
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
@Override
public void transfer(String from, String to, double money) {
add(to,money);
try {
accountServiceImpl2.reduce(from,money);
//reduce(from,money);
}catch (Exception e){
System.out.println("1111111");
}
}
AccountServiceImpl2 中reduce 的內容爲
@Transactional(propagation = Propagation.REQUIRED, readOnly = false)
public void reduce(String to, double money){
int i = 1/0;
accountDao.reduce(to,money);
}
測試結果:,控制檯拋出異常 org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only
當設置 AccountServiceImpl 中transfer 的傳播行爲是 Propagation.REQUIRED,AccountServiceImpl2 中reduce 的傳播行爲是 Propagation.REQUIRES_NEW 時,
測試結果:,控制檯正常
總結:
1.當a,b方法在同一個類中時,不管 b 方法設置何種 傳播行爲,a,b方法都共用一個事務(具體實現方式還未深究)。
2.當a,b方法不在同一個類中時,事務的傳播行爲看 b 方法的註解配置,b 方法配置 Propagation.REQUIRED 是,與a方法共用事務,
當 b 中產生異常,b 方法把 事務 標記 爲回滾,然後把異常拋給 a 方法,a 方法對異常進行了捕獲,所以 a 方法內無異常,a方法會 對事務 進行提交操作,但是b 方法已經把 該事務 標記爲 回滾,所以 會拋出異常。解決這個的辦法就是把 b 方法配置爲 Propagation.REQUIRES_NEW,這樣 b 方法會產生新的 事務,結果就是 b 的事務回滾,a 的事務正常提交
如有說的不對地方,歡迎大家拍磚!
------------------------------------------------------------------------------------------
上面總結中的第一點,經過一番百度,有一篇比較深入的講解博客,附上連接:https://blog.csdn.net/jiesa/article/details/53438342。
但是對於該博客的分析中,我還是有點疑問 :
博文中說 當調用本類方法時,此時的 this 是指向被代理的對象的
測試確實如此,那爲什麼不是 指向 spring 生成的代理類呢?
希望知道的朋友能知導一二,謝謝!
----------------------------------------------------------------------------------------------------------------------------------------
又找到了兩個說的很透徹的鏈接了!
http://www.importnew.com/28793.html
https://my.oschina.net/guangshan/blog/1797461
JDK 動態代理
JdkDynamicAopProxy 類的invoke方法
Cglib動態代理
CglibAopProxy 類中設置了callback 爲 DynamicAdvisedInterceptor 類
我們配置的 aop 切面,實際是以責任鏈的方式執行的,然後調用的*被代理的對象*執行響應的方法,所以在方法中斷點查看this對象,發現不是代理對象,就是當前的類。