将数据从一个数据库复制到另一个数据库时如何解决org.hibernate.StaleObjectStateException?

我正在尝试将数据从一个数据库复制到另一个数据库。 一切正常,直到源数据库中的一行被修改(下面的堆栈跟踪)。 向目标数据库添加新行按预期工作。

我有一个由以下bean组成的每个数据库连接(mysql和hsqldb)的上下文文件:

                       

在我的@Service我为每个数据库连接创建一个JpaRepository

 @Autowired private EntityManager hsqldbEntityManager; @Autowired private EntityManager mysqlEntityManager; private MyRepository hsqldbDao; private MyRepository mysqlDao; public void init() { hsqldbDao = new JpaRepositoryFactory(hsqldbEntityManager).getRepository(MyRepository.class); mysqlDao = new JpaRepositoryFactory(mysqlEntityManager).getRepository(MyRepository.class); } 

MyRepository非常简单:

 public interface MyRepository extends JpaRepository{ } 

我使用Spring Integration将两种服务方法连接在一起。 服务方法如下:

 @Transactional("mysqlTransactionManager") public List findAll() { List list= mysqlDao.findAll(); return list; } @Transactional("hsqldbTransactionManager") public void persist(List list) { hsqldbDao.save(list); hsqldbDao.flush(); } 

我尝试从两个EntityManager分离列表并在保存之前深入克隆列表,但同样的错误。 因此,我认为这与我配置事务/实体管理器的方式有关。

任何帮助赞赏。

堆栈跟踪:

 [task-scheduler-1] ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.integration.MessageHandlingException: javax.persistence.OptimisticLockException at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:76) at org.springframework.integration.handler.MethodInvokingMessageHandler.handleMessageInternal(MethodInvokingMessageHandler.java:59) at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:73) at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:115) at org.springframework.integration.dispatcher.UnicastingDispatcher.dispatch(UnicastingDispatcher.java:102) at org.springframework.integration.channel.AbstractSubscribableChannel.doSend(AbstractSubscribableChannel.java:77) at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:157) at org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:128) at org.springframework.integration.core.MessagingTemplate.doSend(MessagingTemplate.java:288) at org.springframework.integration.core.MessagingTemplate.send(MessagingTemplate.java:149) at org.springframework.integration.endpoint.SourcePollingChannelAdapter.handleMessage(SourcePollingChannelAdapter.java:97) at org.springframework.integration.endpoint.AbstractTransactionSynchronizingPollingEndpoint.doPoll(AbstractTransactionSynchronizingPollingEndpoint.java:82) at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:146) at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:144) at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:236) at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:52) at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:48) at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:49) at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:231) at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:53) at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81) at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) at java.util.concurrent.FutureTask$Sync.innerRun(Unknown Source) at java.util.concurrent.FutureTask.run(Unknown Source) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Unknown Source) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source) at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) at java.lang.Thread.run(Unknown Source) Caused by: javax.persistence.OptimisticLockException at org.hibernate.ejb.AbstractEntityManagerImpl.wrapStaleStateException(AbstractEntityManagerImpl.java:1241) at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1167) at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1148) at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1154) at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:695) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.orm.jpa.SharedEntityManagerCreator$SharedEntityManagerInvocationHandler.invoke(SharedEntityManagerCreator.java:240) at $Proxy21.merge(Unknown Source) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:353) at org.springframework.data.jpa.repository.support.SimpleJpaRepository.save(SimpleJpaRepository.java:384) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.executeMethodOn(RepositoryFactorySupport.java:333) at org.springframework.data.repository.core.support.RepositoryFactorySupport$QueryExecutorMethodInterceptor.invoke(RepositoryFactorySupport.java:318) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.data.jpa.repository.support.LockModeRepositoryPostProcessor$LockModePopulatingMethodIntercceptor.invoke(LockModeRepositoryPostProcessor.java:92) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:90) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202) at $Proxy22.save(Unknown Source) at my.package.MyService.persist(xxxxx) at my.package.MyService$$FastClassByCGLIB$$c484c23b.invoke() at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:191) at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:689) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150) at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110) at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172) at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622) at my.package.MyService$$EnhancerByCGLIB$$ed6874cf.persist() at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.springframework.expression.spel.support.ReflectiveMethodExecutor.execute(ReflectiveMethodExecutor.java:69) at org.springframework.expression.spel.ast.MethodReference.getValueInternal(MethodReference.java:84) at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:57) at org.springframework.expression.spel.ast.SpelNodeImpl.getTypedValue(SpelNodeImpl.java:102) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:102) at org.springframework.integration.util.AbstractExpressionEvaluator.evaluateExpression(AbstractExpressionEvaluator.java:126) at org.springframework.integration.util.MessagingMethodInvokerHelper.processInternal(MessagingMethodInvokerHelper.java:227) at org.springframework.integration.util.MessagingMethodInvokerHelper.process(MessagingMethodInvokerHelper.java:127) at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:73) ... 28 more Caused by: org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [model.MyClass#[B@d76d1e] at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:485) at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:255) at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84) at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:867) at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:851) at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:855) at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:686) ... 71 more 

您可以使用@Version注释的字段在实体上配置乐观锁定。 乐观锁定的原则是,如果存储在行中的版本具有与正在合并的实体中存储的版本相同的值,则仅允许更新行。 否则,抛出您获得的exception。

因此,如果要绕过此检查,则必须从实体获取要更新的版本,将其复制到正在合并的分离实体(就像从目标数据库加载此实体一样),然后合并实体。

我遇到了类似的情况,我帮助我的步骤是:

  1. 从我的实体专栏中删除了@version注释
  2. 并创建了列更新并创建以保持上次更新时间的跟踪。

码:

 public class AuditEntity implements Serializable { private Date created; // @Version private Date updated; public Date getCreated() { return created; } public void setCreated(Date created) { this.created = created; } public Date getUpdated() { return updated; } public void setUpdated(Date updated) { this.updated = updated; } @PrePersist private void onCreate() { setCreated(Date.now()); setUpdated(Date.now()); } @PostUpdate private void onUpdate() { setUpdated(Date.now()); } }