被我忽略的事务的传播性
今天在回顾之前学的事务时,有一个点完全遗忘了。那就是事务的传播性,事务的 propagation 属性。
举个例子:
上淘宝买东西,我买本 【Spring 揭秘】,就在下单的时候,我支付宝钱不够,支付失败,这个支付的过程肯定带事务的,支付失败就代表之前的操作都会回滚,数据不进入数据库【其实是会进的,在未付款订单里面,等待付款】,我要讲的是,我浏览商品的这个记录也应该在这个支付事务里面,事务被回滚了,那这个浏览商品的记录在不在数据库呢?结果是肯定的,肯定会记录在数据库,要不然接下来的几天,淘宝怎么给你推荐你想买的宝贝呢?
这就涉及到了事务的传递特性,事务中嵌套事务,外层事务和内层事务的关系。
【 其实我上面的例子说不过去,我的理解肯定是有问题的。不管你买不买,只要你浏览了,淘宝就会给你推荐类似的宝贝,不管你下没下单。但我暂时只能想到这个不合适的例子了 】
下面这段话摘录自【深入浅出事务之传播属性】
在用 SSH 开发项目的时候,一般都是将事务设置在 Service 层 那么当调用 Service 层的一个方法的时候它能够保证我们的这个方法中执行的所有的对数据库的更新操作保持在一个事务中,在事务层里面调用的这些方法要么全部成功,要么全部失败。那么事务的传播特性也是从这里说起的。
如果你在你的 Service 层的这个方法中,除了调用了 Dao 层的方法之外,还调用了本类的其他的 Service 方法,那么在调用其他的 Service 方法的时候,这个事务是怎么规定的呢,我必须保证我在我方法里掉用的这个方法与我本身的方法处在同一个事务中,否则如果保证事物的一致性。事务的传播特性就是解决这个问题的,“事务是会传播的”在 Spring 中有针对传播特性的多种配置我们大多数情况下只用其中的一种: PROPGATION_REQUIRED:这个配置项的意思是说当我调用 service 层的方法的时候开启一个事务 ( 具体调用那一层的方法开始创建事务,要看你的 aop 的配置 ) ,那么在调用这个 service 层里面的其他的方法的时候,如果当前方法产生了事务就用当前方法产生的事务,否则就创建一个新的事务。这个工作使由 Spring 来帮助我们完成的。以前没有 Spring 帮助我们完成事务的时候我们必须自己手动的控制事务,例如当我们项目中仅仅使用 Hibernate,而没有集成进 spring的时候,我们在一个 service 层中调用其他的业务逻辑方法,为了保证事物必须也要把当前的 hibernate session 传递到下一个方法中,或者采用 ThreadLocal 的方法,将 session 传递给下一个方法,其实都是一个目的。现在这个工作由 spring 来帮助我们完成,就可以让我们更加的专注于我们的业务逻辑。而不用去关心事务的问题。
下面是事务传递性的表格:(我没有大写,写的是加粗斜体,应该是要大写的)
T 代表携带事务。【 这里的传播属性修饰的是内层,但是多层嵌套时外层也是内层,在于理解 】
传播属性 |
事务管理者(外层) | 事务协调者(内层) |
required | T1 | T1 (加入到父事务中) |
无 | T2 (自己创建子事务) |
|
requires_new | T1 | T2 (自己创建子事务) |
无 | T2 (自己创建子事务) |
|
supports | T1 | T1 (加入到父事务) |
无 | 无 | |
not_supported | T1 | 无 |
无 | 无 | |
mandatory | T1 | T1 (加入到父事务) |
无 | error (报错) |
|
never | T1 | error (报错) |
无 | OK | |
nested | 设置savepoint,一旦事务回滚,事务将回滚到 savepoint 处, 交由客户响应提交 / 回滚 |