spring注解事务使用总结
在使用spring的注解事务的时候,需要考虑到事务的传播行为、遇到什么类型的异常时,事务才起作用、事务方法之间的嵌套调用时,怎么样才生效等等诸多问题。网上搜到很多的主要还是一堆理论文字描述,我这里给出亲测的代码,是借助公司真实的系统来做测试。
系统之间调用图如下:
事务和异步处理都在server模块里面。
接口如下:
/** * 测试事务行为接口 * * @author plg * */ public interface TestService { public void methodA(); public void methodB(); public void methodC(); . . . }
使用两个表:
CREATE TABLE `mall_order_statistics` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `shop_id` bigint(20) NOT NULL, `order_num` bigint(20) NOT NULL, `order_amount` bigint(20) NOT NULL, `avg_order_amount` bigint(20) NOT NULL, `pay_type` int(11) NOT NULL, `order_type` int(11) NOT NULL', `order_date` date NOT NULL, `create_time` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_shop_id` (`shop_id`) ) ENGINE=InnoDB CREATE TABLE `mall_goods_ranking` ( `id` bigint(20) NOT NULL AUTO_INCREMENT, `shop_id` bigint(20) NOT NULL, `order_date` date NOT NULL, `mall_goods_id` bigint(20) NOT NULL, `goods_name` varchar(20) NOT NULL, `sales_volume` bigint(20) NOT NULL, `sales_amount` bigint(20) NOT NULL, `create_time` datetime NOT NULL, PRIMARY KEY (`id`), KEY `idx_shop_id` (`shop_id`) ) ENGINE=InnoDB
1.事务与异常类型
这里用的是注解式事务@Transactional。
1.1 正常的处理
先来一个正常的处理,事先已把数据库表清空,代码调用如下:
web端代码如下: try { testService.methodA(); } catch (Exception e) { logger.error("========================= " + e); } server端代码如下: @Transactional @Override public void methodA() { MallGoodsRanking mallGoodsRanking = new MallGoodsRanking(); mallGoodsRanking.setShopId(1L); mallGoodsRanking.setOrderDate(new Date()); mallGoodsRanking.setMallGoodsId(1L); mallGoodsRanking.setGoodsName("测试"); mallGoodsRanking.setSalesVolume(1L); mallGoodsRanking.setSalesAmount(1L); mallGoodsRanking.setCreateTime(new Date()); mallGoodsRankingMapper.insert(mallGoodsRanking); MallOrderStatistics mallOrderStatistics = new MallOrderStatistics(); mallOrderStatistics.setShopId(1L); mallOrderStatistics.setOrderNum(1L); mallOrderStatistics.setAvgOrderAmount(1L); mallOrderStatistics.setOrderAmount(1L); mallOrderStatistics.setPayType(1); mallOrderStatistics.setOrderType(1); mallOrderStatistics.setOrderDate(new Date()); mallOrderStatistics.setCreateTime(new Date()); mallOrderStatisticsMapper.insert(mallOrderStatistics); }执行结果:
1.2异常处理-不插入必填字段,抛出RuntimeException
1.3异常处理-不插入必填字段,抛出Exception
@Transactional @Override public void methodA() throws Exception { try { MallGoodsRanking mallGoodsRanking = new MallGoodsRanking(); mallGoodsRanking.setShopId(1L); mallGoodsRanking.setOrderDate(new Date()); mallGoodsRanking.setMallGoodsId(1L); mallGoodsRanking.setGoodsName("测试"); mallGoodsRanking.setSalesVolume(1L); mallGoodsRanking.setSalesAmount(1L); mallGoodsRanking.setCreateTime(new Date()); mallGoodsRankingMapper.insert(mallGoodsRanking); MallOrderStatistics mallOrderStatistics = new MallOrderStatistics(); // mallOrderStatistics.setShopId(1L);必填字段 mallOrderStatistics.setOrderNum(1L); mallOrderStatistics.setAvgOrderAmount(1L); mallOrderStatistics.setOrderAmount(1L); mallOrderStatistics.setPayType(1); mallOrderStatistics.setOrderType(1); mallOrderStatistics.setOrderDate(new Date()); mallOrderStatistics.setCreateTime(new Date()); mallOrderStatisticsMapper.insert(mallOrderStatistics); } catch (Exception e) { logger.error(" ================== " + e); throw new Exception("异常"); } }捕捉异常后,然后 throw new Exception。执行后,抛出异常: 1.3异常处理-不插入必填字段,抛出Exception
java.lang.Exception: 异常 at yunnex.saofu.mall.service.impl.TestServiceImpl.methodA(TestServiceImpl.java:55) at yunnex.saofu.mall.service.impl.TestServiceImpl$$FastClassBySpringCGLIB$$8fcf06b.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:717)执行结果:
看到了吗,第一条SQL还是插入成功了,第二条语句插入出错,抛出Exception异常,但是事务并没有回滚。 接下来测试一下@Transactional(rollbackFor=Exception.class)这种情况。
1.4异常处理-不插入必填字段,抛出Exception,@Transactional指定异常类型
1.4异常处理-不插入必填字段,抛出Exception,@Transactional指定异常类型 由于篇幅问题,这里补贴代码了,和1.3不同的就是事务注解改成:@Transactional(rollbackFor = Exception.class),运行之后,事务生效:数据库表没有插入数据。 对于service方法中使用注解事务,要么service中的方法中不做异常捕获,要么捕捉异常后throw new RuntimeException(),这样出现异常时,都会使事务回滚。如果需要捕捉特定类型的异常来回滚事务,则需要用@Transactional(rollbackFor=特定类型异常.class)来指定。 ================================================================================================================================= 2.事务方法嵌套使用