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

Java 将数据从一个数据库复制到另一个数据库时,如何解决org.hibernate.StaleObjectStateException?,java,database,spring,hibernate,jpa,Java,Database,Spring,Hibernate,Jpa,我正在尝试将数据从一个数据库复制到另一个数据库。在修改源数据库中的一行(下面的堆栈跟踪)之前,一切正常。向目标数据库添加新行的工作方式与预期相同 我为每个数据库连接(mysql和hsqldb)提供了一个上下文文件,其中包括以下bean: <bean id="mysqlDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name

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

我为每个数据库连接(mysql和hsqldb)提供了一个上下文文件,其中包括以下bean:

    <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>
MyRepository
非常简单:

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

您已使用
@Version
注释字段在实体上配置了乐观锁定。乐观锁定的原则是,仅当存储在行中的版本与存储在合并实体中的版本具有相同的值时,才允许更新行。否则,将抛出您得到的异常


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

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

  • 从我的实体的列中注释掉@version注释
  • 并创建列update和create以跟踪上次更新的时间
  • 代码:


    谢谢你的回答,我得等到星期二回去工作后再试试这个。我确实在其他地方看到了这个,并检查了我的模型,但没有找到
    @Version
    IIRC。我使用Hibernate工具对数据库中的java类进行反向工程,所以可能遗漏了一些东西。。。再次感谢谢谢你,这就是问题所在。注释为
    @Version
    的字段实际上不是一个版本,逆向工程过程添加了注释。删除了注释,没有问题……但是,绕过检查是个坏主意,因为它可能导致更新丢失。我认为onUpdate()方法上正确的注释是@PreUpdate。
    public interface MyRepository extends JpaRepository<MyClass, byte[]>{ }
    
    @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();
    }
    
    [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
    
    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());
        }
    }