spring this調用方法 事務失效分析

問題

       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對象,發現不是代理對象,就是當前的類。

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章