上一章我们简单的介绍了swagger相关的实现,毕竟我都是直接贴代码了,确实也是挺简单的,哈哈哈。 这一章我们主要介绍在springboot中的事物控制。
本项目的GitHub:https://github.com/pc859107393/Go2SpringBoot.git
有兴趣交流springboot进行快速开发的同学可以加一下下面的企鹅群。
在传统的Spring项目中,我们经典三层中主要在service层进行事物控制,常见的配置是什么呢?具体实现如图3.1所示。
在传统的Spring项目中,我们的事物控制需要考虑如下几点:
既然我们知道了传统的事物控制我们需要做的事情,理解了这一点,我们也就可以在springboot项目中推测我们需要哪些东西。 ①. 事物控制相关依赖资源 ②. 事物管理开启 ③.事物读写规则控制 ④.事物读写的实现.
在前面我们构建项目的时候已经加入了 spring-boot-starter-aop
,所以依赖资源不是问题。接着我们需要编写代码来实现相关的规则、开启事物和实现事物。
首先我们可以上网查询一下springboot相关的事物,无外乎都是懒人办法直接在service方法上面添加注解 @Transactional
和在入口类上面使用 @EnableTransactionManagement
,这样就能在项目中指定的方法上面开启事物了。
但是有没有一种更懒得方式呢?一定是有的,估计也是和Spring项目中类似。我们检验的标准是什么?肯定是在service对应的方法内发生异常引起回滚操作。其他的原理不必解释太多,先上码。
@SpringBootApplication @EnableWebMvc @EnableSwagger2 @MapperScan(value = ["cn.acheng1314.base.dao"]) @Configuration @EnableTransactionManagement class BaseApplication : WebMvcConfigurer { //事物类型参数 fun transactionAttributeSource(): TransactionAttributeSource { val source = NameMatchTransactionAttributeSource() //只读或可写事物 val readOnlyTx = RuleBasedTransactionAttribute() readOnlyTx.isReadOnly = true readOnlyTx.propagationBehavior = TransactionDefinition.PROPAGATION_SUPPORTS //可写事物 val requiredTx = RuleBasedTransactionAttribute(TransactionDefinition.PROPAGATION_REQUIRED , Collections.singletonList(RollbackRuleAttribute(Exception::class.java))) val txMap = HashMap<String, TransactionAttribute>() txMap["add*"] = requiredTx txMap["save*"] = requiredTx txMap["insert*"] = requiredTx txMap["update*"] = requiredTx txMap["delete*"] = requiredTx txMap["get*"] = readOnlyTx txMap["query*"] = readOnlyTx txMap["find*"] = readOnlyTx source.setNameMap(txMap) return source } /*事务拦截器*/ @Bean(value = ["txInterceptor"]) fun getTransactionInterceptor(tx: PlatformTransactionManager): TransactionInterceptor { return TransactionInterceptor(tx, transactionAttributeSource()) } /**切面拦截规则 参数会自动从容器中注入 */ @Bean fun pointcutAdvisor(txInterceptor: TransactionInterceptor): AspectJExpressionPointcutAdvisor { val pointcutAdvisor = AspectJExpressionPointcutAdvisor() pointcutAdvisor.advice = txInterceptor pointcutAdvisor.expression = "execution (* cn.acheng1314.base.service.*ServiceImpl.*(..))" return pointcutAdvisor } //省略其他代码 }
在上面的事物规则参数中我们设置了两边倒事物(readOnlyTx,使用了 TransactionDefinition.PROPAGATION_SUPPORTS
设置为两边倒事物)和可写入事物(requiredTx)。接着我们在UserServiceImpl中写一个发生异常的方法,测试是否能够产生事物回滚,代码片段如下:
// @Transactional @Throws(Exception::class) fun addUser() { val user = User() user.duty = "aaa" user.loginName = "aaa" user.name = "aaa" user.password = "aaa" user.createDate = Date() baseMapper.insert(user) throw Exception("测试事物") }
我们来一点点代码进行单元测试,如下:
@RunWith(SpringJUnit4ClassRunner::class) @SpringBootTest(classes = [BaseApplication::class]) class UserServiceImplTest { @Autowired private lateinit var userService: UserServiceImpl @Test fun addUserTest() { userService.addUser() } }
最后运行测试代码后,我们可以发现在数据库中并没有aaa这个用户信息存在,所以我们事物控制成功了。具体效果不用上图了,大家都能在各自的数据库工具中看到。