当前位置: 首页 > 知识库问答 >
问题:

Spring数据-乐观重试机制工作不正常

冯嘉荣
2023-03-14

我的一个服务中有以下代码:

@Override
@Transactional
@RetryConcurrentOperation(exception = Exception.class, retries = 12)
public void test() {

Player player = this.playerRepository.findPlayerById(1L);
player.setFirstName("SomeName");
}

我使用的重试机制是在这里描述的:http://josiahgore.blogspot.co.il/2011/02/using-spring-aop-to-retry-failed.html

问题是,当我获得乐观重试(第二次重试)时,我得到了一个异常:

Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [xxx]
// THIS WORKS: 
@Override
@RetryConcurrentOperation(exception = Exception.class, retries = 12)
public void test() {
 execute();

}   

@Override
@Transactional
public void execute() {
Player player = this.playerRepository.findPlayerById(1L);
player.setFirstName("SomeName");
}

当从事务性函数调用时,为什么这个方面重试机制不成功?

共有1个答案

高宏峻
2023-03-14

从非事务test()调用@transactionalexecute()时,将不应用execute()中的@transactional。这是因为它是从对象的一个方法直接调用到另一个方法,绕过事务代理。

有关代理如何工作以及使用this调用事务性函数时@transactional不工作的更多详细信息,请参阅此答案。

还可以看看Spring RetryTemplate,它是针对这个问题的基于Spring的解决方案。

关于重试机制,它在使用版本化实体(带有@version列)的情况下不起作用,在抛出StaleObjectStateException的情况下就是这种情况。

原因是有另一个线程正在更新数据库上的实体,增加了version列。

解决方案是refresh()实体(加载最新版本),重新应用修改,然后重试。重试几次相同的修改只会在非版本化实体的情况下起作用,而且这可能不是您想要的,因为一个线程所做的更改会被另一个线程静默地覆盖。

 类似资料:
  • 我们决定在web应用程序中使用乐观锁定,以增加并发性,而不使用悲观锁定。 我们在web上看到的解决方案之一是使用带有注释的重试拦截器将方法标记为可重试。 问题是,我们希望对带有@Transactional注释的方法进行注释,但拦截器由于某种原因未能重试它们。(拦截器完全重试非事务性方法。) 所以:

  • > 我在SpringJira上发现了关于使用@Version属性进行乐观锁定的问题。 在实现这一点之前,我如何使用典型的存储库模式来处理这个问题?

  • 我使用的是Spring Boot 2和Spring数据JPA。 我有一个带有@Transactional annotation的服务,它从存储库中读取记录,如果记录不存在,则添加记录并保存所有记录。我创建了一个测试方法,并行执行服务方法5次。由于我使用的是@Lock(LockModeType.悲观写入),我希望其中一个线程在读取可用性时会得到锁,而其他4个线程必须等待事务(createReserv

  • 我不确定方法的设计是否恰当。 我们使用乐观锁定,将增量版本放置在每个实体上。这种实体的每次更新都是通过比较和交换算法执行的,该算法的成功与否取决于其他客户端是否同时更新实体。经典的乐观锁定,如hibernate。 我们还需要采取重新尝试的方法。我们使用基于< code>http的存储(etcd ),某些更新请求可能会超时。 这就是问题所在。如何结合乐观锁定和重试?这是我面临的具体问题。 假设我有一

  • 我有一个如下的路由,它将根据url中的数据显示配置文件: 我在主页上有一个表单,它由一个输入框和区域选择器组成。我将此数据发布到: 问题是,我不知道如何将表单数据(如召唤者名称和区域)转换为url格式,在该格式中,用户将与配置文件页面一起显示,url将为/{Region}/{courdername}。我应该在控制器内部使用重定向::吗?我觉得那样做很糟糕。有什么建议吗? 现在,当我发布数据时,ur

  • 当我在discord内部运行以下脚本(“cmd中的node musicbot.js”)和“!play ytlink”时,bot加入语音通道,并在控制台中记录命令和链接。然而,音乐并没有开始播放。我安装了ffmpeg、ytdl核心和discord。js。 有人能帮我吗?我不知道是哪一部分搞砸了。