我将尝试描述我要解决的问题。我意识到,我开发的一个应用程序的Spring事务管理实施不佳。我在DAO接口方法(CRUD)而不是服务层方法上使用事务声明式方法。这是一个Web应用程序,它执行某种消息处理,并且多个线程同时在同一个消息实例上运行。以下是典型顺序中的步骤:
在T1(事务1)中创建消息,并将其放入出站队列。 T1终止。
消息是由另一个线程从队列中提取的,并随着发送时间和一些其他信息进行发送和更新。设置消息对象的属性并调用dao.update(m),t2开始。
在提交t2之前,将收到传递报告,并且Tread3通过在db中找到它(在步骤1中保存),更新它的状态属性并调用dao.upate(m)来开始处理同一消息对象,因此t3在t2仍在进行时开始。
另一个线程(线程4)通过在t4中再次更改其消息对象的状态来进一步处理该消息对象。
不时发生的结果是丢失了从t2开始的更改,并且发送时间在db中为空。
我需要帮助您弄清楚如何改善应用程序设计并通过防止并发处理同一条消息来消除此问题。
我应该集中精力进行事务重新设计(在服务级别而不是dao上使用它),以及使用可序列化的隔离级别(或其他级别),还是
我应该使用JPA实体管理器锁定吗?
App使用带有休眠实现的spring 3和JPA2。
最佳答案
是的,我会将事务移到服务级别,但是我会重新考虑整个设计,然后看看是否可以将整个过程整合到一个线程中。如果我没记错的话,Spring的事务管理是基于线程的-我怀疑您将能够拥有一个跨线程的事务。
另外,如果可能,请尝试简化操作,以使您仅打一次数据库。
如果确实需要四个单独的更新,请在同一线程中的同一事务中依次运行它们。否则,您将不会有足够的时间尝试使事务正常运行。
显式锁定还要求世界受到伤害-您很可能在这样做时会遇到死锁。
编辑:针对OP的评论:
我建议找到一种将T3更新与T2更新分开的方法,并让T2事务在执行T3更新之前提交。
也许将传递报告放在消息队列中。
然后提出一种策略,用于在T3中找到该项目并进行更新(如果存在),或者稍后再尝试(如果不存在)。
如果您知道在收到交付报告到T2事务结束之间有最短或平均的时间,也许您可以在处理交付收据以创建T3更新时建立一定的延迟量。