Spring事务之Junit单测事务回滚

在spring+spring mvc +mybatis中进行Junit单元测试时,事务的回滚情况。

一:存在事务传播的情况下的事务回滚

存在事务传播,即:在A类的方法中调用B类上的方法。本例是在UserServiceImpl类中的insertUser()方法调用UserServiceTestTransactionImpl类的insertUser()方法。

@Transactional注解默认的事务的传播行为REQUIRED。

导入javax.transaction.Transactional或者org.springframework.transaction.annotation.Transactional包的

@Transactional注解均可,但要使Spring包的@Transactional注解失效,不再使用@Rollback(false),直接删除@Transactional注解即可

测试代码如下:

UserServiceImpl类:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring/spring-application.xml"})
@Transactional  //在junit测试时,@Transactional注解默认不提交事务,即默认回滚事务,防止污染数据库
@Rollback(false)//关闭回滚
@Service
public class UserServiceImpl implements UserService {

    private static final Logger logger = Logger.getLogger(UserServiceImpl.class);

    @Autowired
    private UserServiceTestTransactionImpl userServiceTestTransaction;

    public void insertUser(User user) throws Exception{
        userServiceTestTransaction.insertUser(user);
    }

    @Test
    public void test() throws Exception {
        logger.info("调用insert(User user)方法");
        insertUser(new User(11, "格格"));
    }
UserServiceTestTransactionImpl类:
@Transactional
@Service
public class UserServiceTestTransactionImpl {

    @Autowired
    private UserMapper userMapper;

    public void insertUser(User user) throws Exception {
        userMapper.inserUser(user);
        //throw new RuntimeException();
        throw new IOException();
    }

}

情况一:只要在UserServiceImpl类上加上@Transactional注解,即开启事务

在测试中,无论UserServiceTestTransactionImpl类上有无@Transactional注解,UserServiceTestTransactionImpl类的insertUser()方法不抛出异常、抛出不可查异常RuntimeException及抛出可查异常IOException,这三种情况都会回滚事务,数据库不会插入数据。

情况二:在UserServiceImpl类上加上@Transactional注解的同时加上@Rollback(false),即不开启事务

@Rollback(false)注解,即关闭事务回滚,即使@Transactional注解默认的回滚失效

这种情况相当于注解@Transactional与@Rollback(false)均被注释掉了

在测试中,关闭回滚,UserServiceTestTransactionImpl类的insertUser()方法不抛出异常和抛出可查异常IOException,这两种情况的事务会提交,不再回滚事务,相应的数据库中会插入数据。抛出不可查异常RuntimeException,事务回滚,数据库不会插入数据。

 

二:不存在事务的传播行为情况下的事务回滚

不存在事务的传播,即:同一个类中方法相互调用,本例是在同一个UserServiceImpl类中,test()方法调用insertUser()方法。

测试代码如下:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:spring/spring-application.xml"})
@Transactional  //在junit测试时,@Transactional注解默认不提交事务,即默认回滚事务,防止污染数据库
@Rollback(false)//关闭回滚
@Service
public class UserServiceImpl implements UserService {

    private static final Logger logger = Logger.getLogger(UserServiceImpl.class);

    @Autowired
    private UserMapper userMapper;

    public void insertUser(User user)throws Exception {
        userMapper.inserUser(user);
        throw new RuntimeException();
    }

    @Test
    public void test() throws Exception {
        logger.info("调用insert(User user)方法");
        insertUser(new User(11, "么么"));

        boolean exist = userMapper.exist(11);
        System.out.println("exist:  " + exist);
    }
}

情况一:在类上只加上@Transactional注解

@Transactional注解,会默认回滚事务,防止污染数据库。

在测试中,不抛出异常、抛出不可查异常RuntimeException及抛出可查异常IOException,这三种情况都会回滚事务,数据库不会插入数据。

情况二:在类上加上@Transactional注解的同时加上@Rollback(false)

@Rollback(false)注解,即关闭事务回滚

在测试中,关闭回滚,与情况一相反,不抛出异常、抛出不可查异常RuntimeException及抛出可查异常IOException,这三种情况的事务会提交,不再回滚,相应的数据库中会插入数据。

总结:

在单元测试时,只要测试类开启了事务,所有的操作,无论抛出什么类型的异常,无论是否存在事务的传播行为,无论被调用的类上是否有@Transactional注解,还有无论是否捕获异常,都会回滚事务。

在单元测试时,测试类不开启事务,如果被调用的类上有@Transactional注解(开启事务),此时若被调用类的被调用方法发生不可查异常(RuntimeException及其子类或者error),则事务会回滚,其他操作不会回滚。 解释:虽然单元测试没有开启事务,但是被调用的类本身存在事务,所以会出现事务回滚的情况。

在单元测试时,测试类不开启事务,如果被调用的类不开启事务(即类上没有@Transactional注解),被调用类中的方法不抛出异常、抛出不可查异常RuntimeException及抛出可查异常IOException,这三种情况都不会回滚事务。解释:因为都不存在事务,自然不会有事务回滚。

因此,我们最好在测试类上开启事务,导入 javax.transaction.Transactional包或者org.springframework.transaction.annotation.Transactional的@Transactional注解,避免污染数据库。

注意:

解决Transactional注解不回滚
1、检查你方法是不是public的

2、你的异常类型是不是unchecked异常 
如果我想check异常也想回滚怎么办,注解上面写明异常类型即可@Transactional(rollbackFor=Exception.class) 
类似的还有norollbackFor,自定义不回滚的异常

3、数据库引擎要支持事务,如果是MySQL,注意表要使用支持事务的引擎,比如innodb,如果是myisam,事务是不起作用的

4、是否开启了对注解的解析 <tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true"/>

5、spring是否扫描到你这个包,如下是扫描到org.test下面的包<context:component-scan base-package="org.test" ></context:component-scan>

6、检查是不是同一个类中的方法调用(如a方法调用同一个类中的b方法) 
7、异常是不是被你catch住了
 

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值