행이 다른 트랜잭션에 의해 업데이트 또는 삭제되었습니다(또는 저장되지 않은 값 매핑이 잘못되었습니다).
웹 서버에서 실행되는 자바 프로젝트가 있습니다.나는 항상 이 예외를 친다.
이 예외를 방지하는 최선의 방법은 비관적인 잠금(또는 낙관적인 잠금)을 사용하는 것입니다.
하지만 사용법을 설명하는 명확한 예를 찾을 수 없었습니다.
방법은 다음과 같습니다.
@Transactional
public void test(Email email, String subject) {
getEmailById(String id);
email.setSubject(subject);
updateEmail(email);
}
한편:
Email
는, 휴지 상태 )입니다.getEmailById(String id)
는 을 입니다.email
이에는 ( 없음)이 .@Transactional
)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
일반적으로 비관적인 잠금 기능은 권장되지 않으며 데이터베이스 측 성능 측면에서 매우 비용이 많이 듭니다.몇 가지 (코드 부분)를 언급하고 있는 문제는 다음과 같이 명확하지 않습니다.
- 여러 스레드가 동시에 코드에 액세스 하고 있는 경우.
- 은 어떻게 합니까?
session
오스스 ( 스스스스스스스스스 )
휴지 상태 세션 개체는 스레드 세이프가 아닙니다.따라서 동일한 세션에 액세스하여 동일한 데이터베이스 엔티티를 업데이트하려고 하는 여러 스레드가 있는 경우 코드에는 다음과 같은 오류가 발생할 수 있습니다.
엔티티를 의 스레드가 때 된 것을 를 던집니다.StaleObjectStateException
.
편집:
휴지 상태에서 비관적인 잠금을 사용하는 방법이 있습니다.이 링크를 확인해 주세요.하지만 이 메커니즘에 문제가 있는 것 같습니다.그런데 우연히 휴지 상태(HHH-5275)의 버그를 투고하고 있었습니다.이 버그에 기재되어 있는 시나리오는 다음과 같습니다.
두 스레드가 동일한 데이터베이스 레코드를 읽고 있습니다.이들 스레드 중 하나는 비관적인 잠금을 사용하여 다른 스레드를 차단합니다.그러나 두 스레드 모두 데이터베이스 레코드를 읽을 수 있기 때문에 테스트가 실패합니다.
이것은 당신이 직면하고 있는 것과 매우 유사합니다.이것이 작동하지 않을 경우 이 방법을 시도해 보십시오. 제가 생각할 수 있는 유일한 방법은 postgres 데이터베이스에서 비관적인 잠금을 달성할 수 있는 네이티브 SQL 쿼리를 사용하는 것입니다.SELECT FOR UPDATE
데이터를 폴링하여 처리용으로 핸들러에 제공하는 큐 매니저가 있습니다. 선택하지 않도록 큐 .LOCKED
discloss.discloss.conf.
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()
이치노
문제가 해결되었고 이제 좋아 보입니다.낙관적인 잠금 예외는 혼란스럽고 디버깅이 어렵기 때문에 공유하려고 합니다.
데이터베이스에서 검색한 전자 메일을 실제로 사용하는 것이 아니라 매개 변수로 받은 이전 복사본을 사용하는 것으로 나타납니다.행에서 버전 제어에 사용되는 항목이 이전 버전을 가져온 시점과 업데이트를 수행하는 시점 사이에 변경되었습니다.
코드 모양은 다음과 같습니다.
@Transactional
public void test(String id, String subject) {
Email email = getEmailById(id);
email.setSubject(subject);
updateEmail(email);
}
나는 내 프로젝트에서 이 문제를 가지고 있었다.
낙관적인 잠금을 구현한 후 동일한 예외가 발생했습니다.내 실수는 내가 그 필드가 된 세터를 제거하지 않았다는 것이다.@Version
Java 공간에서 setter를 호출하고 있었기 때문에 필드의 값이 DB에서 생성된 값과 일치하지 않게 되었습니다.따라서 기본적으로 버전 필드가 일치하지 않게 되었습니다.은 다음과 같은가 되었습니다.
org.internate 를 선택합니다.StaleObjectStateException:행이 다른 트랜잭션에 의해 업데이트 또는 삭제되었습니다(또는 저장되지 않은 값 매핑이 잘못되었습니다).
메모리 DB와 휴지 상태에서 H2를 사용하고 있습니다.
이 예외는 아마도 낙관적인 잠금(또는 코드의 버그)으로 인해 발생합니다.아마 모르고 사용하고 있을 거예요.또한 의사 코드(문제를 진단하려면 실제 코드로 대체해야 함)가 잘못되어 있습니다.휴지 상태에서는 모든 수정 내용이 연결된 엔티티에 자동으로 저장됩니다.연결된 엔티티에서 업데이트, 병합 또는 저장 OrUpdate를 호출해서는 안 됩니다.그냥 해
Email email = session.get(emailId);
email.setSubject(subject);
업데이트를 호출할 필요가 없습니다.휴지 상태에서는 트랜잭션을 커밋하기 전에 변경 내용이 자동으로 플러시됩니다.
여러 Spring 프로젝트에서 동일한 오류로 인해 문제가 발생했습니다.일반적인 해결책은 서비스 메서드를 분할하는 것입니다.각 액션에 대해 INSERT, UPDATE 및 DELETE를 @Transactional로 하는 독자적인 메서드를 얻는 것입니다.이 문제는 내부 Spring 관리와 관련이 있다고 생각합니다.이 관리에서는 메서드의 마지막에 데이터베이스 상호작용이 실행되며, 반대로 여기서 예외가 트리거됩니다.
업데이트 및 추가 솔루션.
문제는 @Entity Class 객체를 쿼리하고 값을 저장하지 않고 변경한 것입니다.이는 엄밀히 말하면 다른 쿼리(스코프 외)에 의해 갱신되었기 때문입니다만, 이 오브젝트는 현재 맵 내의 세션 내부이기 때문에 다음 요구는 이 메시지로 차단되었습니다.
그래서 변수를 만들고 거기에 새 값을 저장한 후 UpdateQuery로 전송했습니다.그러면 Hibernate는 저장되지 않은 변경을 등록하지 않고 회선을 갱신할 수 있게 됩니다.휴지 상태에서는 @Entity 클래스의 오브젝트가 변경될 때마다 데이터베이스로 lock 스테이트먼트를 송신하거나 적어도 프라이머리 키로 로컬로 행을 송신합니다.
같은 문제가 있었습니다만, 엔티티 오브젝트의 일부 필드 타입에서 문제가 발견되지 않았거나 실장이 잘못되어 있었습니다.커밋 시 휴지 상태는 세션에 로드된 모든 엔티티를 검사하여 더러움이 없는지 확인합니다.엔티티 중 하나가 더러우면 저장 작업이 요청된 실제 개체가 다른 엔티티와 관련이 없는 경우에도 휴지 상태가 유지됩니다.
엔티티 은 주어진 엔티티 더러움(Entity dirtness)의 .UserType.equals
있는 「」가 .org.Hibernate.UserType
.
하나 주석을 하여)@Transactional
), 는 단일 있었다 (단일 를 다루었다.Hibernate가 저장되는 엔티티와 무관한 임의의 엔티티에 대해 불평하고 있습니다.제가 깨달은 것은 REST 컨트롤러 레벨에서 가장 바깥쪽에 트랜잭션이 있기 때문에 세션 범위가 너무 커서 요청 처리의 일부로 로드된 모든 객체가 더러움을 검사한다는 것입니다.
언젠가 누군가 도움이 되길 바랍니다.
Thanks Rags
혹시나 누군가 이 스레드를 확인했는데 나와 같은 문제가 생겼을 때를 대비해서...
행이 다른 트랜잭션에 의해 업데이트 또는 삭제되었습니다(또는 저장되지 않은 값 매핑이 잘못되었습니다).
NHIbernate를 사용하고 있는데 오브젝트를 만드는 동안 동일한 오류가 발생했습니다.
키를 수동으로 전달하고 매핑에 GUID 생성기도 지정했습니다...
휴지 상태에서도 동일한 오류가 발생합니다.그래서 GUID를 삭제하고 필드를 비워두면 모든 것이 정상적으로 종료됩니다.
이 답변은 도움이 되지 않을 수 있지만, 같은 오류로 인해 스레드를 방금 본 저 같은 사람에게 도움이 될 것입니다.
개체가 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;
}
나는 내 프로젝트의 다른 맥락에서 같은 문제를 경험했고 다음과 같은 다른 시나리오가 있습니다.
- object is accessed from various source like (server side and client)
- without any interval accessing the same object from a different place
첫 번째 경우
서버 cal을 발행할 때 해당 오브젝트를 js에서1개의 콜을 저장하고 저장하려고 하면 js 콜이 2, 3회 진행됩니다(콜바인딩이 문제의 원인인 것 같습니다).
나는 해결했다
e.preventDefault()
두 번째 케이스는
object.lock()
저도 이러한 예외를 받고 있습니다만, 문제는 엔티티 식별자에 있었습니다.하고 .UUID
그리고 스프링이 그들과 함께 일하는 방식에 몇 가지 문제가 있다.그래서 엔티티 ID에 다음 행을 추가했는데 작동하기 시작했습니다.
@Column(columnDefinition = "BINARY(16)")
여기서 좀 더 자세한 정보를 찾을 수 있습니다.
이 오류는 2개의 다른 세션에서 같은 행을 업데이트하려고 할 때 발생했습니다.두 번째가 열려 있는 동안 한 브라우저의 필드를 업데이트하고 세션에 원래 개체를 이미 저장했습니다.이 두 번째 "stale" 세션에서 업데이트를 시도하면 오래된 개체 오류가 나타납니다.이 문제를 해결하려면 업데이트할 값을 설정하기 전에 데이터베이스에서 업데이트할 개체를 다시 페치한 다음 정상적으로 저장합니다.
새 행을 만든 후 기존 행을 업데이트하려고 할 때도 이 오류가 발생했고, 트랜잭션과 버전 로직을 뒤적거리면서 오랫동안 머리를 긁적거리다가 주 키열 중 하나에 잘못된 유형을 사용했다는 것을 알게 되었습니다.
하였습니다.LocalDate
when when when when when when when when when when LocalDateTime
엔티티를 할 수 이 것 .- 이 에러는, 휴지 상태가 되어 버렸습니다.
를 'a'로 한 후LocalDateTime
에러는 해소되었습니다.에는 갱신할 수 에, 이 개별의 , 매핑에 관한 수 .이전에는 갱신할 행을 찾을 수 없었습니다.또, 이 개별의 문제를 테스트한 결과, 프라이머리 키 매핑에 관한 결론을 얻을 수 있었습니다.
★★★★★★★★★★★★★★★★를 설정하지 말아 주세요Id
[ ] Id
됩니다.
같은 문제가 있었습니다만, 저는 Spring Data JPA를 사용하고 있었는데 엔티티 클래스에 @Entity 및 @Table 주석이 붙어 있었습니다.ID 필드에는 @Id 주석이 있었지만 DB 테이블에 자동 증분 ID 필드가 있었기 때문에 @GeneratedValue 추가를 놓쳤습니다.
그러나 이 문제는 이러한 엔티티에 대해 일괄 삽입을 수행할 때 발생했으며 ID 필드에 제너레이터가 지정되어 있지 않기 때문에 모든 엔티티에 ID 필드로 기본값(0)이 지정되었습니다.이 예외를 부여하기 시작했습니다.
javax.contractence를 클릭합니다.OptimisticLockException:행이 다른 트랜잭션에 의해 업데이트 또는 삭제되었습니다(또는 저장되지 않은 값 매핑이 올바르지 않습니다). [dao.entity]Order Assignment Report Entity #0]
@GeneratedValue(전략=GenerationType)를 추가하였습니다.ID)와 @Id를 조합하여 동작했습니다.
저도 같은 문제가 있었어요.버그는 컬렉션 필드의 getter 메서드를 덮어쓰는 것이었습니다.그러면 항상 다른 스레드에 있는 컬렉션의 새 버전이 반환됩니다.
class Entity {
List collection
List getCollection() {
return collection.unique()
}
}
해결방법은 getter 메서드의 이름을 변경하는 것입니다.
class Entity {
List collection
List getUniqueCollection() {
return collection.unique()
}
}
Drop Wizard에서 휴지 상태를 사용하는 경우 ID를 자동 생성으로 사용하면 이 문제가 발생할 수 있습니다.@GeneratedValue 삭제
1. 에러의 이유
또 다른 상황이 있습니다.에러 데이터
@Column(name = "ID", unique = true, nullable = false, length = 32)
private String id;
데이터 중 하나가 공백이거나 null이다.프런트 엔드 값이 저장되면
{
"cause": {
"cause": null,
"message": "Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xxx#]"
},
"message": "Object of class [com.xxx] with identifier []: optimistic locking failed; nested exception is org.hibernate.StaleObjectStateException: Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect) : [com.xxx#]"
}
2. 해결
에러 데이터를 삭제합니다.
이 문제는 같은 인스턴스이지만 다른 List/Hash/ 등에서 취득한 오브젝트를 다른 서브스레드에서 바로 갱신하려고 할 때 발생합니다.
방지하기 StaleObjectStateException
의 「」에서는, 「」를 참조해 주세요.hbm
" " " 드드에드래에 。
<timestamp name="lstUpdTstamp" column="LST_UPD_TSTAMP" source="db"/>
org. Import를 삭제합니다.제거하다@Transactinal
에서 가장 은 엔티티 클래스입니다.@GeneratedValue(strategy=GenerationType.AUTO)
작성id를 는 안 을 id를 삭제합니다.최종 결론은 패스 ID 파일(예: PK)을 작성하려면 삭제해야 합니다.@GeneratedValue
엔티티 클래스의
휴지 상태에서는 버전 관리를 사용하여 수정된 개체가 현재 유지되고 있는 개체보다 오래된 개체임을 알 수 있습니다.
따라서 엔티티를 업데이트할 때 원하지 않는 경우 json 본문에 버전을 포함하지 마십시오.버전 컬럼에 @Version으로 주석을 달기만 하면 됩니다.
어플리케이션 중 하나에서 이 문제가 발생했습니다.이것이 오래된 스레드라는 것을 알고 있습니다만, 여기 해결책이 있습니다.저는 디버거 내의 데이터를 보고 Hibernate가 실제로 데이터베이스를 업데이트하려고 했을 때(실제로 다른 스레드로 실행하려고 했을 때), JVM이 실제로 데이터베이스를 로드하지 않았다는 것을 알게 되었습니다.그래서 en의 모든 필드에 volatile 키워드를 추가했습니다.tities. 퍼포먼스에 문제가 있지만 무거운 물체가 날아다니기 보다는...
언급URL : https://stackoverflow.com/questions/8645694/row-was-updated-or-deleted-by-another-transaction-or-unsaved-value-mapping-was
'sourcecode' 카테고리의 다른 글
eslint: 반복기(react/jsx-key) 요소에 대한 "키" 프로펠러가 없습니다. (0) | 2023.02.27 |
---|---|
Jest에서 TypeScript를 사용한 모의 의존 관계 (0) | 2023.02.27 |
WordPress 로그인 화면에서 reCAPTCHA v3 구현 (0) | 2023.02.22 |
JSON.parse: 속성 이름 또는 '}'이(가) 필요합니다. (0) | 2023.02.22 |
Angular에서 두 필드를 합산하는 방법결과를 레이블로 표시합니까? (0) | 2023.02.22 |