【问题标题】:Advice about spring transaction management redesign关于 Spring 事务管理重新设计的建议
【发布时间】:2012-10-27 13:18:16
【问题描述】:

我将尝试描述我要解决的问题。我意识到我开发的一个应用程序的 Spring 事务管理实现得很差。我在 DAO 接口方法 (CRUD) 上定义事务,而不是在服务层方法上使用声明性方法。它是一个 Web 应用程序,它执行某种消息处理,并且多个线程同时对同一个消息实例进行操作。以下是典型顺序中的步骤:

  1. 消息在 T1(事务 1)中创建并放入出站队列。 T1 已终止。
  2. 消息由不同的线程从队列中取出,发送并更新发送时间和一些附加信息。设置消息对象的属性并调用 dao.update(m),t2 开始。
  3. 在 t2 提交之前,收到传递报告,Tread3 开始处理相同的消息对象,方法是在 db 中找到它(保存在步骤 1 中),更新它的 state 属性并调用 dao.upate(m),因此 t3 在 t2 仍然存在时开始进行中。
  4. 另一个线程(线程 4)通过在 t4 中再次更改其状态来进一步处理相同的消息对象。

时不时出现的结果是t2的变化丢失,db中的发送时间为null。 我需要帮助来弄清楚如何改进应用设计并通过阻止并发处理同一条消息来消除此问题。

  1. 我应该专注于事务重新设计(在服务级别而不是 dao 上使用它)并使用可序列化的隔离级别(或其他)还是

  2. 我应该使用 JPA 实体管理器锁定吗?

应用使用 Spring 3 和 JPA2 以及休眠实现。

【问题讨论】:

  • 消息是如何发送的? JMS?网络服务?其他?您能否将这部分作为全局分布式事务(在 JMS 的情况下)?如果不是,您不应该在 T2 完成后简单地发送消息,从而确保在收到传递报告时 T2 已经结束?
  • 消息通过第三方网络服务发送。 T2 在发送消息之前无法执行,因为消息已随发送结果更新。

标签: java spring hibernate jpa-2.0


【解决方案1】:

是的,我会将事务转移到服务级别,但我会重新考虑整个设计,看看您是否可以将整个流程集中到一个线程中。如果我没记错的话,Spring 的事务管理是基于线程的——我怀疑你是否能够拥有跨线程的事务。

另外,如果可能的话,尽量简化一些事情,这样你就只访问数据库一次。 如果您确实需要四个单独的更新,请在同一线程的同一事务中按顺序运行它们。否则,您将不会有好的时间尝试让交易正常进行。

显式锁定也需要一个伤害世界 - 你很可能会因为这样做而陷入死锁。

编辑:回应 OP 的评论:

我建议找到一种方法将 T3 更新与 T2 更新分开,并在进行 T3 更新之前让 T2 事务提交。

也许将传递报告放在消息队列中。 然后想出一个策略,在 T3 中找到该项目,如果存在则进行更新,如果不存在则稍后再试。

如果您知道从收到交货报告到 T2 交易结束之间有最短或平均时间,也许您可​​以将该延迟量添加到处理交货收据中以创建 T3 更新。

【讨论】:

  • 不幸的是,我无法避免多个线程,因为传递报告是通过 HTTP 接收的。我对事务隔离的主题进行了一些研究,并且似乎 RDMS 负责事务处理而不是 Spring。但我想知道如果我为 T2 和 T3 设置可序列化隔离会发生什么? T2 将获取表上的锁,当 t3 尝试执行相同操作时,它会等待锁释放还是会失败并抛出异常?
猜你喜欢
  • 1970-01-01
  • 2011-10-09
  • 2018-05-24
  • 2018-05-30
  • 2015-12-09
  • 2016-06-16
  • 2020-02-16
  • 2015-07-16
相关资源
最近更新 更多