关于抛异常事务回滚的测试

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于抛异常事务回滚的测试相关的知识,希望对你有一定的参考价值。

TestController.java 代码如下***:
/**
 * 测试异常回滚.
 * @return
 */
@RequestMapping(value = "/testExceptionRollBack")
@ResponseBody
public String testExceptionRollBack() {
    List<String> idList = Lists.newLinkedList();
    idList.add("1111111111");
    idList.add("2222222222");
    idList.add("3333333333");
    try {
        return orderService.testUpdateStatus(idList);
    } catch (Exception e) {
        logger.error("执行失败", e);
        return "执行失败";
    }
}

TestService.java 代码如下***:
public String testUpdateStatus(List<String> idList) throws Exception {
    List<Order> orderList = orderDao.listByIds(idList);
    if (!orderList.isEmpty()) {
        int index = 1;
        for (Order order : orderList) {
            try {
                requestDataService.insert("URL",
                        "ttt", "测试异步", "测试成功", Common.FLAG_Y, 1, order.getOrderCode());
                if ("PO1805060174".equals(order.getOrderCode())) {
                    throw new RuntimeException("测试此单据抛异常事务回滚");
                } else {
                    TestOccupation occu = new TestOccupation();
                    occu.setStorageAreaId(order.getStorageAreaId());
                    occu.setCommodityCode("TT" + index);
                    occu.setDocumentCode(order.getOrderCode());
                    occu.setOccupiedQty(order.getTotalQty());
                    occu.setCreateDate(new Date());
                    occu.setCreateUserId(OpmUser.INTERFACE_USER_ID);
                    occu.setDocumentId(order.getOrderId());
                    occu.setDocumentDetailId(order.getOrderId() + "" + index);
                    testOccupationDao.add(newDocumentOccupation);
                }
                index++;
            } catch (Exception e) {
                logger.error("执行异常", e);
            }
        }
    }
    return null;
}

结论: 经过测试发现, 程序在运行的时候抛出一个运行时异常, 事务并不会回滚, 请求信息依然保存到了DB.
接下来看另一种现象, TestController还是不变, 将TestService的
【throw new RuntimeException("测试此单据抛异常事务回滚");】 修改如下:
【entityService.testException("PO1805060174");】
EntityService.java 代码如下***:
public void testException(String code) throws Exception {
    if (TextUtils.isNotEmpty(code)) {
        throw new RuntimeException("测试在另一个service发出一个异常");
    }
}

结论: 经过测试发现, 程序运行中执行到抛异常后整个事务会回滚, 请求信息都没有保存到DB中, 
这就意味着调用的子方法在另外一个service中的时候抛异常即便捕获了仍然会抛异常.接下来再将
requestDataRecordService的方法 insert 加个异步的注解, 代码如下***:

@Async
public void insert(***) {
}

结论: 经过再次测试得出, requestDataService.insert 存入到DB中了,但是inventoryDocumentOccupationDao.add 没有存入DB, 
证明加了异步方法的注解标识后, 此方法不会被回滚.接下来再将EntityService代码修改如下***:

public void testException(String code) throws Exception {
    try {
        if (TextUtils.isNotEmpty(code)) {
            throw new RuntimeException("测试在另一个service发出一个异常");
        }
    } catch (Exception e) {
        logger.error("测试异常", e);
    }
}

结论: 再继续测试, 发现在【原始抛异常的地方进行捕获】后事务就不会回滚, 请求信息被存入了DB中. 

备注: 测试的项目使用的框架: SpringMVC + Spring + mybatis

以上是关于关于抛异常事务回滚的测试的主要内容,如果未能解决你的问题,请参考以下文章

关于Spring事务回滚的问题

JPA中事务回滚的问题

spring的@Transactional失效原因分析

spring配置了事务,抛出异常不回滚

关于项目中遇到的问题-- trycatch 手动回滚事务

Java事务不回滚的原因总结