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>

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