我有一个spring应用程序,它使用 @Transactional
方法,并且在同一方法中,我尝试使用 @Async
它是另一个spring应用程序,它从mysql db读取同一实体并更新redis存储中的值。
现在的问题是,每次我更新实体的一些值时,有时在redis中更新,有时不更新。
当我试着调试时,我发现有时第二个应用程序在从mysql读取实体时会选择旧的值而不是更新的值。
有人能告诉我如何避免这种情况,并确保第二个应用程序总是从mysql中选择该实体的更新值吗?
我有一个spring应用程序,它使用 @Transactional
方法,并且在同一方法中,我尝试使用 @Async
它是另一个spring应用程序,它从mysql db读取同一实体并更新redis存储中的值。
现在的问题是,每次我更新实体的一些值时,有时在redis中更新,有时不更新。
当我试着调试时,我发现有时第二个应用程序在从mysql读取实体时会选择旧的值而不是更新的值。
有人能告诉我如何避免这种情况,并确保第二个应用程序总是从mysql中选择该实体的更新值吗?
2条答案
按热度按时间mnowg1ta1#
m的回答。deinum是好的,但是仍然有另一种方法可以实现这一点,根据当前应用程序的状态,这种方法对于您的情况可能更简单。
您可以简单地将对async方法的调用 Package 在一个事件中,该事件将在当前事务提交后处理,以便每次都能正确地从db读取更新的实体。
要做到这一点很简单,让我告诉你:
基本上,这里发生的事情是,我们为当前事务回调提供了一个实现,并且我们只覆盖aftercommit方法—那里还有其他方法可能有用,请检查它们。如果您想在其他部分中使用它或只是简单地使方法更具可读性,那么为了避免键入相同的样板代码,我在helper方法中提取了它。
beq87vna2#
解决方案并不是那么难,显然您希望在数据写入数据库后触发并更新。这个
@Transactional
仅在方法完成执行后提交。如果另一个@Async
方法在方法末尾调用,具体取决于事务可能已提交或未提交的提交(或实际的rest调用)的持续时间。由于事务之外的某些内容只能看到提交的数据,因此它可能会看到更新的数据(如果已经提交),或者仍然是旧的数据。这还取决于事务的序列化级别,但出于性能原因,通常不希望对数据库使用独占锁。
为了解决这个问题
@Async
方法不应从内部调用@Transactional
但就在那之后。这样,数据总是被提交,而另一个服务将看到更新的数据。此服务是非事务性的,因此
service1.update
可以推测,这是@Transactional
将更新数据库。完成后,您可以触发外部同步。