Spring事務容易踩的坑

一:目標對象的內部調用無法實施切面      

二:實驗

1.接口定義


public interface UserManager {

    Integer insert(User user);

    void updateUser(User user);

}

2.實現類


@Component("userManager")
public class UserManagerImpl implements UserManager {

    @Resource
    private UserDao userDao;

    @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insert(User user) {
        insert = userDao.insert(user);
        updateUser(user);
       
        return insert;
    }

    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public void updateUser(User user) {
        userDao.update(user);
        System.out.println(1 / 0);
    }

}

爲了方便測試,update的執行sql如下,更新一下修改人,如下

UPDATE tb_user SET update_user = '1026' where id = #{id,jdbcType=BIGINT}

3.測試方法

@Test
public void testInsert() {
    User user = new User();
    user.setUserName("201808232313");
    user.setPassWord("201808232313");
    user.setTelPhone("201808232313");
    user.setEmail("[email protected]");
    user.setCreateUser("201808232313");
    user.setUpdateUser("蒼生1");
    Integer insert = userManager.insert(user);
    logger.debug("testInsert" + insert);
}

4.執行結果,msyql默認可重複讀隔離級別,猜測測試方法執行過後數據庫的情況,

  1. 數據插入失敗
  2. 數據插入成功,更新失敗
  3. 數據插入成功,更新成功

5.執行test方法,數據庫沒有插入記錄。到此還沒結束,不過一般我們這樣寫不會什麼問題。

三:修改實現類的方法,測試其他情況

1.insert方法中,對update的方法,異常進行處理,沒有把異常再次拋出

 @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insert(User user) {
        Integer insert = 0;
        insert = userDao.insert(user);
        try {
            //對方法進行異常處理
            updateUser(user);
        } catch (Exception e) {
            e.printStackTrace();
//            throw new RuntimeException(e);
        }
        return insert;
    }
	

結果發現update方法居然執行成功了,數據被更新,事務失效了。

2.再次修改實現類的方法

 @Override
    @Transactional(propagation = Propagation.REQUIRED)
    public Integer insert(User user) {
        Integer insert = 0;
        insert = userDao.insert(user);
        try {
            //對方法進行異常處理
//            updateUser(user);
            ((UserManager) AopContext.currentProxy()).updateUser(user);
        } catch (Exception e) {
            e.printStackTrace();
//            throw new RuntimeException(e);
        }
        return insert;
    }

結果發現update方法的數據被回滾了

3.修改配置文件,在原有的<tx:annotation-driven/> 後增加一句 <aop:config expose-proxy="true"></aop:config>

如下

 <tx:annotation-driven/>
    <!--配置文件增加下面一行-->
 <aop:config  expose-proxy="true"></aop:config>

測試發現insert和update都被回滾了

四:總結

事務控制,最簡單的方式就是加了註解的方法不對異常處理,發生異常就回滾數據。如果事務比較複雜,就需要考慮事務調用方法,異常處理和事務配置。防止目標對象內部的方法調用失效。

使用AopContext.currentProxy() 配置文件 <aop:config  expose-proxy="true"></aop:config>

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