복붙노트

[SPRING] 한 데이터베이스에서 다른 데이터베이스로 데이터를 복사 할 때 org.hibernate.StaleObjectStateException을 해결하는 방법은 무엇입니까?

SPRING

한 데이터베이스에서 다른 데이터베이스로 데이터를 복사 할 때 org.hibernate.StaleObjectStateException을 해결하는 방법은 무엇입니까?

한 데이터베이스에서 다른 데이터베이스로 데이터를 복사하려고합니다. 원본 데이터베이스의 행 중 하나가 수정 될 때까지 (모두 아래의 스택 추적) 모든 것이 올바르게 작동합니다. 대상 데이터베이스에 새 행을 추가하면 예상대로 작동합니다.

각 데이터베이스 연결 (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>

내 @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<MyClass, byte[]>{ }

나는 Spring Integration을 사용하여 두 개의 서비스 메소드를 함께 연결하고있다. 서비스 방법은 다음과 같습니다.

@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();
}

EntityManagers에서 목록을 분리하고 같은 오류로 저장하기 전에 목록을 완전히 복제하려고 시도했습니다. 따라서 트랜잭션 / entitymanagers를 구성한 방식과 관련이 있다고 생각합니다.

어떤 도움을 주셔서 감사합니다.

스택 추적 :

[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

해결법

  1. ==============================

    1.@Version annotated 필드를 사용하여 엔티티에 대해 낙관적 잠금을 구성했습니다. 낙관적 잠금의 원칙은 행에 저장된 버전이 병합중인 엔터티에 저장된 것과 동일한 값을 갖는 경우에만 행을 업데이트 할 수 있도록 허용하는 것입니다. 그렇지 않으면 예외가 발생합니다.

    @Version annotated 필드를 사용하여 엔티티에 대해 낙관적 잠금을 구성했습니다. 낙관적 잠금의 원칙은 행에 저장된 버전이 병합중인 엔터티에 저장된 것과 동일한 값을 갖는 경우에만 행을 업데이트 할 수 있도록 허용하는 것입니다. 그렇지 않으면 예외가 발생합니다.

    따라서이 검사를 건너 뛰려면 엔티티에서 업데이트 할 버전을 가져 와서 병합중인 분리 된 엔티티에 복사 한 다음 (대상 데이터베이스에서이 엔티티를로드 한 경우처럼) 엔티티를 병합해야합니다 .

  2. ==============================

    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());
        }
    }
    
  3. from https://stackoverflow.com/questions/16732156/how-to-solve-org-hibernate-staleobjectstateexception-when-copying-data-from-one by cc-by-sa and MIT license