java - 应用程序服务器线程和 JPA/Hibernate 乐观锁定 - OptimisticLockException

标签 java multithreading spring hibernate jpa

我有一个 Spring MVC 应用程序在应用程序服务器上运行。对应用程序的每个请求都会导致 Hibernate 调用entityManager.merge() 来更新数据库中的一行。

我今天运行了一个测试,发送了多个请求,并注意到我收到以下错误:

javax.persistence.OptimisticLockException
        at org.jboss.resteasy.core.SynchronousDispatcher.handleApplicationException(SynchronousDispatcher.java:340) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.handleException(SynchronousDispatcher.java:214) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.handleInvokerException(SynchronousDispatcher.java:190) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.getResponse(SynchronousDispatcher.java:540) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:502) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:119) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:208) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:55) [resteasy-jaxrs-2.3.1.GA.jar:]
        at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:50) [resteasy-jaxrs-2.3.1.GA.jar:]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:847) [jboss-servlet-api_3.0_spec-1.0.0.Final.jar:1.0.0.Final]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:329) [jbossweb-7.0.10.Final.jar:]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:248) [jbossweb-7.0.10.Final.jar:]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:275) [jbossweb-7.0.10.Final.jar:]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:161) [jbossweb-7.0.10.Final.jar:]
        at org.jboss.as.jpa.interceptor.WebNonTxEmCloserValve.invoke(WebNonTxEmCloserValve.java:50) [jboss-as-jpa-7.1.0.Final.jar:7.1.0.Final]
        at org.jboss.as.web.security.SecurityContextAssociationValve.invoke(SecurityContextAssociationValve.java:154) [jboss-as-web-7.1.0.Final.jar:7.1.0.Final]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155) [jbossweb-7.0.10.Final.jar:]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102) [jbossweb-7.0.10.Final.jar:]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) [jbossweb-7.0.10.Final.jar:]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:368) [jbossweb-7.0.10.Final.jar:]
        at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:877) [jbossweb-7.0.10.Final.jar:]
        at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:671) [jbossweb-7.0.10.Final.jar:]
        at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:930) [jbossweb-7.0.10.Final.jar:]
        at java.lang.Thread.run(Thread.java:619) [rt.jar:1.6.0_20]

为了能够解决上述问题,我需要了解以下内容:

  • 应用程序服务器如何处理请求?是不是每个请求都由自己的线程处理?

  • 查看错误,我注意到它们被称为(http--10.10.4.16-8080-1)和(http--10.10.4.16-8080-7)。末尾的数字是处理请求的线程号吗?

  • optimistiLockException 表明在 JPA/Hibernate 发出提交之前尝试更新相同的消息。如果我将相关代码放在同步块(synchronized block)中,如何确保请求传入的顺序是同步块(synchronized block)可用时处理请求的顺序?

  • 有没有办法指示 JPA/Hibernate 在存在未提交的更改时不要尝试更新消息?

谢谢

最佳答案

您可用的修复取决于您构建层的方式以及您要合并的实体的来源。分离的实体是由 Spring Data Binder 组装的,还是存储在 Web session 中,或者您是否从数据库中获取实体并在请求到达时对其进行更改?

How are the requests handled on the application server? Is the case that each request is processed by its own thread?

它们由线程池处理。因此,每个请求不会获得“自己的”线程,但在任何给定时间,每个 Activity 请求都由一个单独的线程处理,是的。 (或者在队列中等待空闲。)

Looking at the error i noticed that they were referred to as (http--10.10.4.16-8080-1) and (http--10.10.4.16-8080-7). Is the number at the end the thread number that processed the request?

整个内容就是线程的名称。 Tomcat 将数字放在末尾以使其唯一,但是除了由 tomcat 分配的任意顺序字符串之外,# 没有任何特定含义。

The optimistiLockException suggests that there was an attempt to update the same message before JPA/Hibernate issued a commit. If i put the relevant code in a synchronized block, how do i ensure that the order the requests came in is the order they are processed when the synchronized block is available?

如果顺序很重要,您需要在处理之前将它们放入某种队列中。同步不保证等待线程的执行顺序。如果此过程不能失败,请考虑在数据库中使用悲观锁,而不是在应用程序服务器上同步。使用该表的其他一些线程可能不会打扰同步并导致异常。

Is there a way to instruct JPA/Hibernate to not attempt to update the message if there are uncommitted changes?

事实并非如此,没有任何直接的方法可以检查实体在内存缓存中的其他 session 中是否有挂起的更新。 OptimisticLock 检查是了解其他人是否进行更改的机制。

关于java - 应用程序服务器线程和 JPA/Hibernate 乐观锁定 - OptimisticLockException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10837020/

相关文章:

multithreading - memcache 和 redis 的内部工作方式有何不同

c++ - `volatile` 在线程之间同步变量

java - 在事务之外使用的 JPA Spring Data 实体

java - 在有效日志级别检查的上下文中,Log4j2 中的替换参数和 Java lambda 表达式有什么区别?

java - 单击按钮使 JInternalFrame 即使在最小化时也出现一次

java - 使用 Spring EL 分割字符串

java - 多个 JAX RS 路径触发错误的方法

c# - 程序在访问消息队列时挂起

java - 使用 Aspectj 时可以在 args 中使用我自己的对象吗?

java - 升级到 Thymeleaf 3 并在 Spring 中重新实现富 HTML 电子邮件