Java 事务方法中的org.springframework.orm.ObjectOptimisticLockingFailureException在Spring作业中使用shedlock和hibernate

Java 事务方法中的org.springframework.orm.ObjectOptimisticLockingFailureException在Spring作业中使用shedlock和hibernate,java,hibernate,spring-boot,transactions,shedlock,Java,Hibernate,Spring Boot,Transactions,Shedlock,我在Spring Boot 2.1服务中获得了许多org.springframework.orm.ObjectOptimisticLockingFailureException。我在Spring的@Scheduled中有一份工作,我用Hibernate在PostgreSQL中保存的地址不多 延迟设置为fixedDelay=5000L,initialDelay=5000L。 我使用的是net.javacrumbs.shedlock,因此锁将持久保存在数据库中,并且只有一个容器将获取锁并调用publ

我在Spring Boot 2.1服务中获得了许多
org.springframework.orm.ObjectOptimisticLockingFailureException
。我在Spring的
@Scheduled
中有一份工作,我用Hibernate在PostgreSQL中保存的地址不多

延迟设置为
fixedDelay=5000L
initialDelay=5000L
。 我使用的是
net.javacrumbs.shedlock
,因此锁将持久保存在数据库中,并且只有一个容器将获取锁并调用
publishBatch()

看起来是这样的:

@服务
@所需参数构造函数
公共类地址发布器{
私有静态最终记录器Logger=LoggerFactory.getLogger(AddressPublisher.class);
专用静态最终int MAX_LOCK_IN_SECONDS=600;
专用最终地址存储库地址存储库;
私人最终地址制作人地址制作人;
私人最终锁提供商锁提供商;
@计划(固定延迟=5000L,初始延迟=15000L)
公共无效publishModifiedAddresses(){
可选锁=lockProvider.lock(lockConfigurationForPublishModifiedAddresses());
如果(!lock.isPresent()){
debug(“未获取发布修改地址的锁”);
返回;
}
UUID jobUUID=UUID.randomUUID();
try(MDCConfig忽略=新MDCConfig(jobUUID)){
做{
如果(publishBatch())中断;
}虽然(正确);
}最后{
lock.get().unlock();
}
}
@交易的
公共布尔publishBatch(){
List ModifiedAddress=addressRepository.FindBylastModifiedfterLastPublished(100);
if(modifiedAddresses.isEmpty()){
debug(“未找到修改的地址。正在休眠”);
返回true;
}
debug(“找到将要发布的{}个修改过的地址。”,modifiedAddresses.size());
modifiedAddress.forEach(addressProducer::sendAddress);
info(“找到并发布了{}个修改过的地址。”,keyValue(“addressCount”,ModifiedAddress.size());
返回false;
}
private LockConfiguration lockConfigurationForPublishModifiedAddresses(){
返回新的锁配置(“publishModifiedAddresses”,Instant.now().plusSeconds(最大锁秒数));
}
}   
@服务
公共类广播制作人{
专用最终地址存储库地址存储库;
公共无效发送地址(地址){
address.setLastPublished(Instant.now());
addressRepository.save(地址);
//做卡夫卡的事
}
}
stacktrace的一部分:

message:  "Unexpected error occurred in scheduled task."
stack_trace:  "org.springframework.orm.ObjectOptimisticLockingFailureException: Object of class [<packagename>.Address] with identifier [aa17cf6e-110e-4b1a-8866-6647b42e9155]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [<packagename>.Address#aa17cf6e-110e-4b1a-8866-6647b42e9155]
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:335)
    at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253)
    at org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.translateExceptionIfPossible(AbstractEntityManagerFactoryBean.java:527)
    at org.springframework.dao.support.ChainedPersistenceExceptionTranslator.translateExceptionIfPossible(ChainedPersistenceExceptionTranslator.java:61)
    at org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
    at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
    at com.sun.proxy.$Proxy178.save(Unknown Source)
    at <packagename>.AddressProducer.sendAddress(AddressProducer.java:91)
消息:“计划任务中出现意外错误。”
堆栈跟踪:“org.springframework.orm.ObjectOptimisticLockingFailureException:标识符为[aa17cf6e-110e-4b1a-8866-6647b42e9155]的类[.Address]的对象:乐观锁定失败;嵌套异常为org.hibernate.StaleObjectStateException:行被另一个事务更新或删除(或未保存的值映射不正确):[地址#aa17cf6e-110e-4b1a-8866-6647b42e9155]
位于org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:335)
在org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateException如果可能(HibernateJpaDialect.java:253)
位于org.springframework.orm.jpa.AbstractEntityManagerFactoryBean.TranslateExceptionIffailable(AbstractEntityManagerFactoryBean.java:527)
在org.springframework.dao.support.ChainedPersistenceExceptionTranslator.TranslateExceptionIfEnabled(ChainedPersistenceExceptionTranslator.java:61)
位于org.springframework.dao.support.DataAccessUtils.translateIfNecessary(DataAccessUtils.java:242)
位于org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:153)
位于org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:186)
位于org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135)
位于org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:186)
位于org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93)
位于org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:186)
位于org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61)
位于org.springframework.aop.framework.ReflectiveMethodInvocation.procedue(ReflectiveMethodInvocation.java:186)
位于org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212)
位于com.sun.proxy.$Proxy178.save(未知来源)
AddressProducer.sendAddress(AddressProducer.java:91)
我试图不保存每个地址,而是收集列表,然后调用
saveAll()
。我还了解到这可能是一个刷新问题,但我无法测试它,因为我没有获得
EntityManager
,也找不到手动刷新的方法。此外,如果是事务性的,我认为应该正确处理它

谢谢大家!


问候语

@如果方法(或类)未被代理,则事务性方法不起作用。您可以从同一个类调用“publishBatch”。好的,在
AddressPublisher
中,我现在只有作业配置(
@Scheduled
annotation)。然后我调用
@Transactional
annotated方法
publishBatch()
移动到
AddressProducer
。它们的I锁,调用
sendAddress
方法,在该方法中修改实体,但不保存它们。I
saveAll<