복붙노트

[SPRING] 행이 다른 트랜잭션에 의해 업데이트되거나 삭제되었습니다 (또는 저장되지 않은 값 매핑이 잘못되었습니다).

SPRING

행이 다른 트랜잭션에 의해 업데이트되거나 삭제되었습니다 (또는 저장되지 않은 값 매핑이 잘못되었습니다).

웹 서버에서 실행되는 Java 프로젝트가 있습니다. 나는 항상이 예외를 쳤다.

나는 약간의 문서를 읽고, 비관적 인 잠금 (또는 낙관적이지만, 나는 비관적 인 것을 더 잘 읽는다)이 예외를 막는 가장 좋은 방법이라는 것을 알았다.

그러나 나는 그것을 사용하는 방법을 설명하는 명확한 예를 찾을 수 없었다.

내 방법은 다음과 같습니다.

@Transactional
Public void test(Email email, String Subject){
   getEmailById(String id);
   email.setSubject(Subject);
   updateEmail(email);
}

동안:

참고 : 저장, 업데이트 등을 위해 최대 절전 모드를 사용합니다 (예 : session.getcurrentSession.save (email)).

예외 :

ERROR 2011-12-21 15:29:24,910 Could not synchronize database state with session [myScheduler-1]
org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [email#21]
    at org.hibernate.persister.entity.AbstractEntityPersister.check(AbstractEntityPersister.java:1792)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2435)
    at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2335)
    at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2635)
    at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:115)
    at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
    at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
    at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
    at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:50)
    at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1027)
    at org.hibernate.impl.SessionImpl.managedFlush(SessionImpl.java:365)
    at org.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:137)
    at org.springframework.orm.hibernate3.HibernateTransactionManager.doCommit(HibernateTransactionManager.java:656)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
    at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
    at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
    at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
    at $Proxy130.generateEmail(Unknown Source)
    at com.admtel.appserver.tasks.EmailSender.run(EmailNotificationSender.java:33)
    at com.admtel.appserver.tasks.EmailSender$$FastClassByCGLIB$$ea0d4fc2.invoke(<generated>)
    at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
    at org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:688)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
    at org.springframework.aop.aspectj.AspectJAfterThrowingAdvice.invoke(AspectJAfterThrowingAdvice.java:55)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
    at org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:50)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
    at org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:50)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:161)
    at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:89)
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
    at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:621)
    at com.admtel.appserver.tasks.EmailNotificationSender$$EnhancerByCGLIB$$33eb7303.run(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.util.MethodInvoker.invoke(MethodInvoker.java:273)
    at org.springframework.scheduling.support.MethodInvokingRunnable.run(MethodInvokingRunnable.java:65)
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:51)
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)
    at java.util.concurrent.FutureTask$Sync.innerRunAndReset(FutureTask.java:317)
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:150)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$101(ScheduledThreadPoolExecutor.java:98)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.runPeriodic(ScheduledThreadPoolExecutor.java:180)
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:204)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)
    at java.lang.Thread.run(Thread.java:680)
ERROR 2011-12-21 15:29:24,915 [ exception thrown < EmailNotificationSender.run() > exception message Object of class [Email] with identifier [211]: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect): [Email#21] with params ] [myScheduler-1]
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Object of class [Email] with identifier [21]: optimistic locking failed; nested exception is 

해결법

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

    1.비관적 잠금은 일반적으로 권장되지 않으며 데이터베이스 측면에서 성능 측면에서 비용이 많이 듭니다. 당신이 언급 한 (코드 부분) 몇 가지 사항은 다음과 같이 명확하지 않습니다.

    비관적 잠금은 일반적으로 권장되지 않으며 데이터베이스 측면에서 성능 측면에서 비용이 많이 듭니다. 당신이 언급 한 (코드 부분) 몇 가지 사항은 다음과 같이 명확하지 않습니다.

    Hibernate Session 객체는 스레드로부터 안전하지 않습니다. 따라서 동일한 세션에 액세스하는 여러 스레드가 있고 동일한 데이터베이스 엔터티를 업데이트하려고하면 코드가 다음과 같은 오류 상황이 될 수 있습니다.

    따라서 하나 이상의 스레드가 동일한 엔티티를 업데이트하려고 시도 할 때 하나의 스레드가 성공하고 다음 스레드가 데이터를 커밋하려고하면 이미 수정 된 스레드를보고 StaleObjectStateException을 던집니다.

    편집하다:

    Hibernate에서 Pessimistic Locking을 사용하는 방법이있다. 이 링크를 확인하십시오. 그러나이 메커니즘에는 몇 가지 문제가있는 것으로 보입니다. 그러나 나는 Hibernate (HHH-5275) 버그를 게시했다. 이 버그에 언급 된 시나리오는 다음과 같습니다.

    이것은 당신이 직면 한 것에 매우 가깝습니다. 이것이 작동하지 않으면 이것을 시도하십시오. SELECT FOR UPDATE 쿼리를 사용하여 postgres 데이터베이스에서 비관적 잠금을 얻을 수있는 네이티브 SQL 쿼리를 사용할 수있는 유일한 방법입니다.

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

    2.실제로 데이터베이스에서 검색하는 전자 메일을 사용하고 있지는 않지만 매개 변수로받은 이전 복사본을 사용하고있는 것처럼 보입니다. 행의 버전 제어에 사용되는 것은 이전 버전을 검색했을 때와 업데이트를 수행 할 때 사이에 변경되었습니다.

    실제로 데이터베이스에서 검색하는 전자 메일을 사용하고 있지는 않지만 매개 변수로받은 이전 복사본을 사용하고있는 것처럼 보입니다. 행의 버전 제어에 사용되는 것은 이전 버전을 검색했을 때와 업데이트를 수행 할 때 사이에 변경되었습니다.

    아마도 코드를 다음과 같이 보길 원할 것입니다.

    @Transactional
    Public void test(String id, String subject){
       Email email = getEmailById(id);
       email.setSubject(subject);
       updateEmail(email);
    }
    
  3. ==============================

    3.나는 이것이 오래된 질문이라는 것을 알고있다. 그러나 우리 중 일부는 여전히 그것을 치고 하늘을 방황하는 것을 본다. 내가 직면 한 한 가지 문제가있다.

    나는 이것이 오래된 질문이라는 것을 알고있다. 그러나 우리 중 일부는 여전히 그것을 치고 하늘을 방황하는 것을 본다. 내가 직면 한 한 가지 문제가있다.

    우리는 데이터를 폴링하고 처리를 위해 핸들러에주는 큐 관리자를 가지고 있습니다. 동일한 이벤트를 다시 선택하지 않으려면 큐 관리자가 LOCKED 상태의 데이터베이스에 레코드를 잠급니다.

       void poll() {
            record = dao.getLockedEntity();
            queue(record);
         }
    

    이 메소드는 트랜잭션 적이 아니지만 dao.getLockedEntity ()는 'REQUIRED'와 (과) 트랜잭션 적입니다.

    생산에 몇 달이 지난 후에도 좋은 결과를 얻었지만 낙관적 인 잠금 예외로 인해 실패했습니다.

    디버깅을 많이하고 세부적인 내용을 확인한 후에 어떤 코드가 이런 코드를 변경했다는 것을 알 수있었습니다.

    @Transactional(propagation=Propagation.REQUIRED, readOnly=false)
    void poll() {
            record = dao.getLockedEntity();
            queue(record);              
         }
    

    따라서 레코드는 dao.getLockedEntity ()의 트랜잭션이 폴링 메소드의 동일한 트랜잭션을 사용하기 전에 큐에 대기하고 객체는 poll () 메소드 트랜잭션이 얻을 때까지 핸들러 (다른 스레드)에 의해 변경되었습니다. comitted.

    우리는 문제를 해결했고 이제는 좋아 보인다.

    낙관적 인 락 예외는 혼란스럽고 디버깅하기 어렵 기 때문에 공유하는 것을 고려했습니다. 어떤 사람들은 제 경험으로 인해 많은 도움을받을 것입니다.

    문안 인사 리 주

  4. ==============================

    4.이 예외는 낙관적 인 잠금 (또는 코드의 버그)으로 인한 것일 수 있습니다. 아마 모르는 사이에 그것을 사용하고있을 것입니다. 그리고 의사 코드 (문제를 진단 할 수있는 실제 코드로 대체되어야 함)는 잘못되었습니다. Hibernate는 첨부 된 엔티티들에 대한 모든 수정을 자동적으로 저장한다. 첨부 된 엔티티에서 update, merge 또는 saveOrUpdate를 호출해서는 안됩니다. 그냥 해

    이 예외는 낙관적 인 잠금 (또는 코드의 버그)으로 인한 것일 수 있습니다. 아마 모르는 사이에 그것을 사용하고있을 것입니다. 그리고 의사 코드 (문제를 진단 할 수있는 실제 코드로 대체되어야 함)는 잘못되었습니다. Hibernate는 첨부 된 엔티티들에 대한 모든 수정을 자동적으로 저장한다. 첨부 된 엔티티에서 update, merge 또는 saveOrUpdate를 호출해서는 안됩니다. 그냥 해

    Email email = session.get(emailId);
    email.setSubject(subject);
    

    업데이트를 호출 할 필요가 없습니다. Hibernate는 트랜잭션을 커밋하기 전에 자동적으로 변경을 플러시한다.

  5. ==============================

    5.내 프로젝트에서이 문제가 발생했습니다.

    내 프로젝트에서이 문제가 발생했습니다.

    낙관적 인 잠금을 구현 한 후에도 동일한 예외가 발생했습니다. 저의 실수는 @Version이 된 분야의 세터를 제거하지 않았다는 것입니다. setter가 java 공간에서 호출 될 때 필드의 값이 더 이상 DB에서 생성 된 값과 일치하지 않습니다. 그래서 기본적으로 버전 필드는 더 이상 일치하지 않습니다. 이 시점에서 엔티티에 대한 수정은 다음과 같이 나타납니다.

    H2 메모리 데이터베이스와 최대 절전 모드에서 사용하고 있습니다.

  6. ==============================

    6.객체가 존재하는지 또는 존재하지 않는지를 DB에 확인합니다. 존재하는 경우 객체를 가져 와서 새로 고칩니다.

    객체가 존재하는지 또는 존재하지 않는지를 DB에 확인합니다. 존재하는 경우 객체를 가져 와서 새로 고칩니다.

    if (getEntityManager().contains(instance)) {
        getEntityManager().refresh(instance);
        return instance;
    }
    

    위의 조건을 만족하지 못하는 경우 ... DB에있는 ID를 가진 객체를 찾으십시오. 필요한 작업을 수행하십시오.이 경우 정확하게 변경 사항이 반영됩니다.

    if (....) {
        } else if (null != identity) {
            E dbInstance = (E) getEntityManager().find(instance.getClass(), identity);
            return dbInstance;
        }
    
  7. ==============================

    7.나는 내 프로젝트의 다른 맥락에서 경험이있는 동일한 문제를 겪었고, 다른 시나리오가있다.

    나는 내 프로젝트의 다른 맥락에서 경험이있는 동일한 문제를 겪었고, 다른 시나리오가있다.

     - object is accessed from various source like (server side and client)
     - without any interval accessing the same object from a different place
    

    첫 번째 경우

    내가 서버 cal을 발행 할 때, js로부터 하나의 호출을 저장하고 다른 곳을 저장하려고 할 때, js 호출은 두 번, 세 번 가고있다. (나는 바인딩 물건을 호출하는 것이 문제 다.)

    나는 해결했다.

    e.preventDefault()
    

    두 번째 경우,

    object.lock()
    
  8. ==============================

    8.나는 동일한 문제가 있었고 제 경우에는 문제가 누락되었고 / 또는 잘못된 것은 엔티티 객체의 일부 필드 유형에 대한 구현과 동일합니다. 커밋 할 때, Hibernate는 세션에로드 된 모든 엔티티가 더러운지를 검사한다. 엔티티 중 하나라도 더티가 있으면 최대 절전 모드는 저장 작업이 요청 된 실제 객체가 다른 엔티티와 관련이 없다는 사실에 상관없이 객체를 유지하려고 시도합니다.

    나는 동일한 문제가 있었고 제 경우에는 문제가 누락되었고 / 또는 잘못된 것은 엔티티 객체의 일부 필드 유형에 대한 구현과 동일합니다. 커밋 할 때, Hibernate는 세션에로드 된 모든 엔티티가 더러운지를 검사한다. 엔티티 중 하나라도 더티가 있으면 최대 절전 모드는 저장 작업이 요청 된 실제 객체가 다른 엔티티와 관련이 없다는 사실에 상관없이 객체를 유지하려고 시도합니다.

    엔티티 dirtiness는 주어진 객체의 모든 프라퍼티 (equals 메소드와 비교)를 비교하거나, 프로퍼티가 연관된 org.Hibernate.UserType을 가지고 있다면 UserType.equals를 비교함으로써 수행됩니다.

    놀랐던 또 다른 일은 (Spring 어노테이션 @Transactional을 사용하여) 트랜잭션에서 하나의 엔티티를 다루는 것이 었습니다. Hibernate는 저장된 엔티티와 관련이없는 임의의 엔티티에 대해 불평했다. 내가 깨달은 것은 REST 컨트롤러 레벨에서 가장 바깥 쪽 트랜잭션을 생성했기 때문에 세션의 범위가 너무 커서 요청 처리의 일부로로드 된 모든 객체가 더러움을 검사 받게됩니다.

    희망이 누군가를 도울, 언젠가.

    감사합니다 Rags

  9. ==============================

    9.누군가가이 스레드를 확인하고 내 것과 같은 문제가있는 경우를 대비해 ...

    누군가가이 스레드를 확인하고 내 것과 같은 문제가있는 경우를 대비해 ...

    NHibernate를 사용하고 있는데, 객체를 생성하는 동안 같은 오류가 발생합니다 ...

    나는 수동으로 키를 전달하고 매핑에 GUID 생성기를 지정했다. 그래서 최대 절전 모드는 나를 위해 똑같은 에러를 발생시킨다. 그래서 일단 GUID를 제거하고 필드를 비워두면 모든 것이 잘되었습니다.

    이 대답은 당신을 도울 수는 없지만 나 같은 사람을 도울 것입니다.

  10. ==============================

    10.이 오류는 2 개의 다른 세션에서 동일한 행을 업데이트하려고 할 때 발생했습니다. 초가 열린 상태에서 한 브라우저에서 필드를 업데이트하고 세션에 원래 객체를 저장했습니다. 이 두 번째 "오래된"세션에서 업데이트하려고 시도했을 때 부실 객체 오류가 발생합니다. 이 값을 수정하기 위해 업데이트 할 값을 설정하기 전에 데이터베이스에서 업데이트 할 개체를 다시 가져온 다음 정상적으로 저장합니다.

    이 오류는 2 개의 다른 세션에서 동일한 행을 업데이트하려고 할 때 발생했습니다. 초가 열린 상태에서 한 브라우저에서 필드를 업데이트하고 세션에 원래 객체를 저장했습니다. 이 두 번째 "오래된"세션에서 업데이트하려고 시도했을 때 부실 객체 오류가 발생합니다. 이 값을 수정하기 위해 업데이트 할 값을 설정하기 전에 데이터베이스에서 업데이트 할 개체를 다시 가져온 다음 정상적으로 저장합니다.

  11. ==============================

    11.나는 grails 프로젝트에서 같은 문제를 겪었다. 버그는 컬렉션 필드의 getter 메서드를 덮어 쓴다는 것이 었습니다. 이것은 항상 다른 스레드에서 컬렉션의 새 버전을 반환했습니다.

    나는 grails 프로젝트에서 같은 문제를 겪었다. 버그는 컬렉션 필드의 getter 메서드를 덮어 쓴다는 것이 었습니다. 이것은 항상 다른 스레드에서 컬렉션의 새 버전을 반환했습니다.

    class Entity {
        List collection
    
        List getCollection() {
            return collection.unique()
        }
    }
    

    해결 방법은 getter 메서드의 이름을 바꾸는 것입니다.

    class Entity {
        List collection
    
        List getUniqueCollection() {
            return collection.unique()
        }
    }
    
  12. ==============================

    12.StaleObjectStateException을 방지하려면 hbm 파일에서 다음 코드를 작성하십시오.

    StaleObjectStateException을 방지하려면 hbm 파일에서 다음 코드를 작성하십시오.

    <timestamp name="lstUpdTstamp" column="LST_UPD_TSTAMP" source="db"/>
    
  13. ==============================

    13.나는 또한이 문제에 직면했다. 먼저 수입을 확인하고, 세션을 사용할 때, 트랜잭션은 org.hibernate이어야합니다. @Transactinal 주석을 제거합니다. @GeneratedValue (strategy = GenerationType.AUTO) 또는 anyother를 사용한 경우 모델 객체 생성 / 엔티티 객체 생성시 ID를 생성해서는 안되며 Entity 클래스에서 가장 중요합니다. 최종 결론은 패스 ID가 적용된 (PK), 즉 엔티티 클래스에서 @GeneratedValue를 제거하려는 경우입니다.

    나는 또한이 문제에 직면했다. 먼저 수입을 확인하고, 세션을 사용할 때, 트랜잭션은 org.hibernate이어야합니다. @Transactinal 주석을 제거합니다. @GeneratedValue (strategy = GenerationType.AUTO) 또는 anyother를 사용한 경우 모델 객체 생성 / 엔티티 객체 생성시 ID를 생성해서는 안되며 Entity 클래스에서 가장 중요합니다. 최종 결론은 패스 ID가 적용된 (PK), 즉 엔티티 클래스에서 @GeneratedValue를 제거하려는 경우입니다.

  14. ==============================

    14.내 애플 리케이션 중 하나 에서이 문제가 있었는데, 지금,이 오래된 스레드지만, 여기에 내 솔루션을 알고; 나는 디버거 내부의 데이터를보고 Hibernate가 데이터베이스를 업데이트하려고 할 때 JVM이 실제로로드하지 않았다는 것을 알아 냈다. (그것은 실제로 다른 스레드에서 수행되었다.) 그래서 모든 필드에 키워드 "volatile"을 추가했다. 엔티티의 그것은 약간의 퍼포먼스 이슈를 가지고 있지만 헤비 오브젝트는 던져 버리는 것보다 ...

    내 애플 리케이션 중 하나 에서이 문제가 있었는데, 지금,이 오래된 스레드지만, 여기에 내 솔루션을 알고; 나는 디버거 내부의 데이터를보고 Hibernate가 데이터베이스를 업데이트하려고 할 때 JVM이 실제로로드하지 않았다는 것을 알아 냈다. (그것은 실제로 다른 스레드에서 수행되었다.) 그래서 모든 필드에 키워드 "volatile"을 추가했다. 엔티티의 그것은 약간의 퍼포먼스 이슈를 가지고 있지만 헤비 오브젝트는 던져 버리는 것보다 ...

  15. from https://stackoverflow.com/questions/8645694/row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was by cc-by-sa and MIT license