快速业务通道

事务策略: 了解事务陷阱-在Java平台中实现事务时要注意的常见错误 - 编程入门网

作者 佚名技术 来源 NET编程 浏览 发布时间 2012-06-14
表示在这个工作单元中,该对象缓存不应与数据库同步。不过,REQUIRED 传播模式会覆 盖所有这些内容,允许事务启动并工作,就好像没有设置只读标志一样。

这令我想到了另一个我经常碰到的主要陷阱。阅读了前面的所有内容后,您认为如果只对 @Transactional 注释设置只读标志,清单 8 中的代码会得到什么结果呢?

清单 8. 使用只读标志 — JPA

@Transactional(readOnly = true) public TradeData getTrade(long tradeId) throws Exception { return em.find(TradeData.class, tradeId); }

事务策略: 了解事务陷阱-在Java平台中实现事务时要注意的常见错误(6)

时间:2011-10-21 IBM Mark Richards

清单 8 中的 getTrade() 方法会执行以下哪一种操作?

A.启动一个事务,获取交易订单,然后提交事务

B.获取交易订单,但不启动事务

正确的答案是 A。一个事务会被启动并提交。不要忘了,@Transactional 注释的默认传播模式是 REQUIRED。这意味着事务会在不必要的情况下启动。根据使用的数据库,这会引起不必要的共享锁,可能 会使数据库中出现死锁的情况。此外,启动和停止事务将消耗不必要的处理时间和资源。总的来说,在使 用基于 ORM 的框架时,只读标志基本上毫无用处,在大多数情况下会被忽略。但如果您坚持使用它,请 记得将传播模式设置为 SUPPORTS(如清单 9 所示),这样就不会启动事务:

清单 9. 使用只读标志和 SUPPORTS 传播模式进行选择操作

@Transactional(readOnly = true, propagation=Propagation.SUPPORTS) public TradeData getTrade(long tradeId) throws Exception { return em.find(TradeData.class, tradeId); }

另外,在执行读取操作时,避免使用 @Transactional 注释,如清单 10 所示:

清单 10. 删除 @Transactional 注释进行选择操作

public TradeData getTrade(long tradeId) throws Exception { return em.find(TradeData.class, tradeId); }

REQUIRES_NEW 事务属性陷阱

不管是使用 Spring Framework,还是使用 EJB,使用 REQUIRES_NEW 事务属性都会得到不好的结果并 导致数据损坏和不一致。REQUIRES_NEW 事务属性总是会在启动方法时启动一个新的事务。许多开发人员 都错误地使用 REQUIRES_NEW 属性,认为它是确保事务启动的正确方法。考虑清单 11 中的两个方法:

清单 11. 使用 REQUIRES_NEW 事务属性

@Transactional (propagation=Propagation.REQUIRES_NEW) public long insertTrade(TradeData trade) throws Exception {...} @Transactional(propagation=Propagation.REQUIRES_NEW) public void updateAcct(TradeData trade) throws Exception {...}

注意,清单 11 中的两个方法都是公共方法,这意味着它们可以单独调用。当使用 REQUIRES_NEW 属 性的几个方法通过服务间通信或编排在同一逻辑工作单元内调用时,该属性就会出现问题。例如,假设在 清单 11 中,您可以独立于一些用例中的任何其他方法来调用 updateAcct() 方法,但也有在 insertTrade() 方法中调用 updateAcct() 方法的情况。现在如果调用 updateAcct() 方法后抛出异常, 交易订单就会回滚,但帐户更新将会提交给数据库,如清单 12 所示:

清单 12. 使用 REQUIRES_NEW 事务属性的多次更新

@Transactional (propagation=Propagation.REQUIRES_NEW) public long insertTrade(TradeData trade) throws Exception { em.persist(trade); updateAcct(trade); //exception occurs here! Trade rolled back but account update is not! ... }

之所以会发生这种情况是因为 updateAcct() 方法中启动了一个新事务,所以在 updateAcct() 方法 结束后,事务将被提交。使用 REQUIRES_NEW 事务属性时,如果存在现有事务上下文,当前

凌众科技专业提供服务器租用、服务器托管、企业邮局、虚拟主机等服务,公司网站:http://www.lingzhong.cn 为了给广大客户了解更多的技术信息,本技术文章收集来源于网络,凌众科技尊重文章作者的版权,如果有涉及你的版权有必要删除你的文章,请和我们联系。以上信息与文章正文是不可分割的一部分,如果您要转载本文章,请保留以上信息,谢谢!

分享到: 更多

Copyright ©1999-2011 厦门凌众科技有限公司 厦门优通互联科技开发有限公司 All rights reserved

地址(ADD):厦门软件园二期望海路63号701E(东南融通旁) 邮编(ZIP):361008

电话:0592-5908028 传真:0592-5908039 咨询信箱:web@lingzhong.cn 咨询OICQ:173723134

《中华人民共和国增值电信业务经营许可证》闽B2-20100024  ICP备案:闽ICP备05037997号