Spring 事务,你真的用对了吗(上篇)?
开篇
事务是什么, 提到事务你一定会想到数据库事务,没错,它就是我们今天的主角。但今天的事务有些特别,并不是通过数据库的事务来保证ACID。而是通过Spring提供的事务。本文不讲解事务的传播机制,而是单纯的用实际的例子说明如何我们想把一系列的数据库操作在一个事务中完成,该如何使用Spring中的事务。
Spring中事务的使用
说到这大家一定会觉得这个简单, Spring框架已经帮我们都做好了,加上@Transactional 注解就好了, 那我们就试试这个注解到底能不能帮我们解决事务问题。
为了进行实验, 我们建一张表, 结构如下:
那我们就插入一条数据试试,我写了如下的代码, 为了验证@Transactional的作用, 我们先不加注解试试:
查询数据库, 结果如下:
接下来我们加上注解, 再试一下,正如我们期望的, 抛出了异常:
查询数据库可知, 两条数据都没有插入成功, 看来@Transactional注解确实起到了事务的作用。那这就简单了,既然框架都给我解决了,我以后需要事务的时候直接加上注解就好了嘛。于是我就愉快的开始用了,在实际的业务中, 我们的代码逻辑可能会很复杂, 为了代码的简洁,我会把第二部分抽出一个方法,代码就变成这样了:
运行后发现两条数据都没有插入成功,哈, 还真是方便呀, 有一天又一个场景, 我只想在抛出异常时回滚第二条数据, 我心想这还不简单, 我把@Transactonal注解放到第二个方法上就好了嘛, 于是代码就变成这样:
此时我发现, 编译器给我提示了一个错误, 点开看看,这是不让我用private呀, 还说使用@Transactional必须要是overridable的, 这是心理就犯嘀咕了, 为什么, 为啥啊????哎呀, 下不管了, 既然不让我用private, 我就所性改成public的试试。果然不提示错误了,运行吧。
哎, 为啥我两条数据都插进去了, 没有回滚啊。这个时候你就不得不借助理论知识了, 不管你是度娘也好, 谷爹也好, 书也好, 去找吧,我就找到下面这篇文章:https://www.marcobehler.com/guides/spring-transaction-management-transactional-in-depth他解析了事务的的原理, 并提示你有陷阱:
原来@Transactional 注解是基于代理来的, 都知道AOP是代理,所以在实际中是创建了service代理, 并在方法运行前开启事务,运行后提交事务。而我的第二个方法是我service内部的, 不会再有更多的代理了。自然事务也就不好用了。这下我们知道了,要想使用@Transactional注解,还是要放在service的入口方法,像我们刚刚的需求,就要再创建一个新的service了。于是代码变成这样:
然后我们再去运行以下代码会发现,两条数据都没有成功插入,完美解决了我们的需求。不知道大家有没有注意到,我在最后的例子中,为@Transactional注解中加入一个参数, propagation = Propagation.REQUIRED, 为什么要加这个, 加这个的作用是什么呢?这个我们会在事务的第二篇进行分析。
版权声明: 本文为 InfoQ 作者【双儿么么哒】的原创文章。
原文链接:【http://xie.infoq.cn/article/b00a66611ad8bb4df24df50cb】。文章转载请联系作者。
评论