How to solve org.hibernate.StaleObjectStateException when copying data from one database to another?

I am trying to copy data from one database to another. Everything works fine until one of the rows in the source database is modified (stack trace below). Adding new rows to the target database works as expected.

I have a context file for each database connection (mysql and hsqldb) consisting of the following beans:

<bean id="mysqlDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="${mysql.driver}" /> <property name="url" value="${mysql.url}" /> <property name="username" value="${mysql.username}" /> <property name="password" value="${mysql.password}" /> </bean> <bean id="mysqlTransactionManager" class="org.springframework.orm.jpa.JpaTransactionManager"> <property name="entityManagerFactory" ref="mysqlEntityManagerFactory" /> <property name="dataSource" ref="mysqlDataSource" /> </bean> <bean id="mysqlEntityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"> <property name="dataSource" ref="mysqlDataSource" /> <property name="jpaVendorAdapter" ref="mysqlVendorAdaptor" /> <property name="packagesToScan" value="my.packages.to.scan"/> </bean> <bean id="mysqlEntityManager" class="org.springframework.orm.jpa.support.SharedEntityManagerBean"> <property name="entityManagerFactory" ref="mysqlEntityManagerFactory"/> </bean> <bean id="mysqlVendorAdaptor" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" > <property name="showSql" value="true" /> <property name="generateDdl" value="true" /> <property name="databasePlatform" value="${mysql.dialect}" /> </bean> 

In my @Service I create a JpaRepository for each database connection:

 @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 very simple:

 public interface MyRepository extends JpaRepository<MyClass, byte[]>{ } 

I am connecting 2 service methods together using Spring Integration. Service methods are as follows:

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

I tried to detach the list from EntityManager and deeply clone the list before saving with the same error. So I think this has something to do with how I set up transactions / noun.

Any help was appreciated.

Stack trace:

 [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(<generated>) 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(<generated>) 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 
+6
source share
2 answers

You have an optimized lock configured on your entities using the @Version annotated field. The principle of optimistic locking is to allow row updates only if the version stored in the row has the same meaning as the one stored in the merged object. Otherwise, you will get an exception.

So, if you want to get around this check, you will have to get the version from the object to update, copy it to the combined object, which will be merged (as if you downloaded this object from the target database), and then merge the object.

+21
source

I was stuck in a similar situation, and my steps that helped me were:

  • Comments on @version annotation from an object column
  • And create a column update and create to track the last updated time.

code:

 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()); } } 
+2
source

Source: https://habr.com/ru/post/945760/


All Articles