java - ObjectOptimisticLockingFailureException 和 RollbackException

标签 java hibernate jpa

我在使用 hibernate 和 jpa 时遇到问题。

我有一个定期调用的方法,用于从数据库中的表中检索数据并将其发送到另一台服务器。

这是该方法的代码:

protected List<MessagingMessage> getNewMessages() throws NoMessageAvailableException {
    return messagingPublisher.getNewMessages(application);
}

这是发布者的代码:

@Override
@Transactional(noRollbackFor = {ObjectOptimisticLockingFailureException.class})
public List<MessagingMessage> getNewMessages(String application) throws NoMessageAvailableException {
    List<GpsDataToSend> allGpsDatas = gpsDataToSendService.findByapplicationIgnoreCase(application);
    List<MessagingMessage> allMessages = new ArrayList<>();
    for (GpsDataToSend gpsDataToSend : allGpsDatas) {
        MessagingMessage message = convertToMessagingMessage(gpsDataToSend);
        // Ajout dans les messages à envoyer au TMS
        allMessages.add(message);
        try {
            // Suppression des données de la base
            gpsDataToSendService.deleteGpsDataToSend(gpsDataToSend.getId());
        } catch (ObjectOptimisticLockingFailureException oolfa) {
            // Si l'exception est levée, c'est que la donnée a été supprimée, donc déjà été envoyée au TMS
            allMessages.remove(message);
            Long idGpsDataToSend = ((GpsDataToSend) message.getObject()).getId();
            log.info("The GPS message was already sent because the data doesn't exists anymore in database (id : {})", idGpsDataToSend);
        }
    }
    return allMessages;
}

发布者检索数据,将其转换为消息,然后从数据库中删除数据,以确保它只发送一次。

问题是我有 2 台服务器处于负载平衡状态,执行相同的代码,因此这 2 台服务器可能同时检索相同的数据。有时,在删除时,我会发生 ObjectOptimisticLockingFailureException 异常,告诉我没有可删除的数据。 我刚刚处理了这个异常,以确保它不会干扰其余的执行。

但是现在,当发生 ObjectOptimisticLockingFailureException 时,在下一次执行时:

protected List<MessagingMessage> getNewMessages() throws NoMessageAvailableException {
    return messagingPublisher.getNewMessages(application);
}

我得到这个异常:

2018-04-24 15:58:09 ERROR [pool-3-thread-1] c.g.m.m.w.WepSphereMqQueuePusher [WepSphereMqQueuePusher.java:76] Error getting new message to send org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:526) ~[spring-orm-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:761) ~[spring-tx-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:730) ~[spring-tx-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:518) ~[spring-tx-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:292) ~[spring-tx-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:96) ~[spring-tx-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) ~[spring-aop-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) ~[spring-aop-4.3.14.RELEASE.jar:4.3.14.RELEASE]
at com.sun.proxy.$Proxy75.getNewMessages(Unknown Source) ~[na:na]
at com.geodisbm.mobility.messaging.websphere.WepSphereMqQueuePusher.getNewMessages(WepSphereMqQueuePusher.java:101) [messaging-1.0-SNAPSHOT.jar:na]
at com.geodisbm.mobility.messaging.websphere.WepSphereMqQueuePusher.sendAllMessages(WepSphereMqQueuePusher.java:71) [messaging-1.0-SNAPSHOT.jar:na]
at com.geodisbm.mobility.messaging.websphere.WepSphereMqQueuePusher.access$000(WepSphereMqQueuePusher.java:16) [messaging-1.0-SNAPSHOT.jar:na]
at com.geodisbm.mobility.messaging.websphere.WepSphereMqQueuePusher$1.run(WepSphereMqQueuePusher.java:63) [messaging-1.0-SNAPSHOT.jar:na]
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) [na:1.8.0_45]
at java.util.concurrent.FutureTask.runAndReset$$$capture(FutureTask.java:308) [na:1.8.0_45]
at java.util.concurrent.FutureTask.runAndReset(FutureTask.java) [na:1.8.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) [na:1.8.0_45]
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) [na:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_45]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_45]
at java.lang.Thread.run(Thread.java:745) [na:1.8.0_45]
Caused by: javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.hibernate.jpa.internal.TransactionImpl.commit(TransactionImpl.java:58) ~[hibernate-entitymanager-5.1.12.Final.jar:5.1.12.Final]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:517) ~[spring-orm-4.3.14.RELEASE.jar:4.3.14.RELEASE]
... 20 common frames omitted

看来,如果发生 ObjectOptimisticLockingFailureException,事务将被标记为 rollbackonly。所以我试图让事务不回滚这个异常(通过注释),但它不起作用。

你知道为什么它不起作用吗?

谢谢。

最佳答案

发生此问题的原因很可能是 getNewMessages 调用了一些事务性方法,并且事务管理器的属性 globalRollbackOnParticipationFailure 设置为 true(这是默认)。

这是 javadoc 的相关内容:

 Set whether to globally mark an existing transaction as rollback-only
 after a participating transaction failed.
 <p>Default is "true": If a participating transaction (e.g. with
 PROPAGATION_REQUIRES or PROPAGATION_SUPPORTS encountering an existing
 transaction) fails, the transaction will be globally marked as rollback-only.
 The only possible outcome of such a transaction is a rollback: The
 transaction originator <i>cannot</i> make the transaction commit anymore.
 <p>Switch this to "false" to let the transaction originator make the rollback
 decision. If a participating transaction fails with an exception, the caller
 can still decide to continue with a different path within the transaction.
 However, note that this will only work as long as all participating resources
 are capable of continuing towards a transaction commit even after a data access
 failure: This is generally not the case for a Hibernate Session, for example;
 neither is it for a sequence of JDBC insert/update/delete operations.

您已在外部事务上设置noRollbackFor,但是

  1. getNewMessages 永远不会抛出 ObjectOptimisticLockingFailureException
  2. 更重要的是,只有当其他方法(我猜 deleteGpsDataToSend@Transactional 注释)抛出该异常时,事务才会被标记为回滚。

关于java - ObjectOptimisticLockingFailureException 和 RollbackException,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50015947/

相关文章:

java - Injectind 在运行时通过 CDI 自动实现

java - Hibernate 泛型

java - 指定 jre 绝对路径时 Oracle setup.exe 空间敏感度

java - 如何平移和缩放 JComponents?

java - 从 Hibernate 映射创建对象

java - PagingAndSortingRepository 查询返回与一组实体匹配的实体

java - 为什么我的 H2 数据库/Spring 启动应用程序会收到 JdbcSQLException(非十六进制字符)?

java - JPA EntityTransaction 抛出 java.lang.IllegalStateException

java - 泛型和 Play 框架

java - leetcode上字符串中反向词的一行代码序列