Java-JPA-@Version 주석


118

@VersionJPA에서 주석은 어떻게 작동합니까?

다음과 같은 다양한 답변을 찾았습니다.

JPA는 항목의 버전 필드를 사용하여 동일한 데이터 저장소 레코드에 대한 동시 수정을 감지합니다. JPA 런타임이 동일한 레코드를 동시에 수정하려는 시도를 감지하면 마지막 커밋을 시도하는 트랜잭션에 예외가 발생합니다.

그러나 나는 그것이 어떻게 작동하는지 여전히 잘 모르겠습니다.


또한 다음 줄에서와 같이 :

버전 필드를 변경할 수없는 것으로 간주해야합니다. 필드 값을 변경하면 결과가 정의되지 않습니다.

버전 필드를 다음과 같이 선언해야 함을 의미합니까 final?


1
모든 업데이트 쿼리에서 버전을 확인 / 업데이트하기 만하면됩니다 : UPDATE myentity SET mycolumn = 'new value', version = version + 1 WHERE version = [old.version]. 누군가 레코드를 업데이트하면 old.versionDB 의 레코드와 더 이상 일치하지 않으며 where 절은 업데이트가 발생하지 않도록합니다. '업데이트 된 행'은 0JPA가 감지하여 동시 수정이 발생했다는 결론을 내릴 수 있습니다.
Stijn de Witt

답변:


189

하지만 여전히 어떻게 작동하는지 잘 모르겠습니까?

엔티티 MyEntity에 주석이 달린 version속성 이 있다고 가정 해 보겠습니다 .

@Entity
public class MyEntity implements Serializable {    

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @Version
    private Long version;

    //...
}

업데이트시 다음과 같이 주석이 추가 된 필드 @Version가 증분되고 WHERE절에 추가됩니다 .

UPDATE MYENTITY SET ..., VERSION = VERSION + 1 WHERE ((ID = ?) AND (VERSION = ?))

WHERE절이 레코드와 일치하지 않으면 (동일한 엔터티가 이미 다른 스레드에 의해 업데이트 되었기 때문에) 지속성 공급자가 OptimisticLockException.

버전 필드를 최종적으로 선언해야 함을 의미합니까?

아니요.하지만 호출해서는 안되는 세터를 보호하는 것을 고려할 수 있습니다.


5
Long이 null로 초기화되기 때문에이 코드에서 null-pointer 예외가 발생했습니다. 아마도 0L로 신속하게 초기화되어야합니다.
Markus

2
자동 언 박싱 long또는 호출에만 의존하지 마십시오 longValue(). 명시적인 null검사 가 필요 합니다. 이 필드는 ORM 공급자가 관리해야하므로 명시 적으로 직접 초기화하지 않습니다. 0LDB에 처음 삽입 할 때 설정되어 있다고 생각 하므로 이렇게 설정 null하면이 레코드가 아직 유지되지 않았 음을 의미합니다.
Stijn de Witt

이렇게하면 엔티티 생성이 두 번 이상 생성 (시도)되는 것을 방지 할 수 있습니까? JMS 토픽 메시지가 엔티티 생성을 트리거하고 애플리케이션의 여러 인스턴스가 메시지를 수신한다고 가정합니다. 고유 한 제약 조건 위반 오류를 피하고 싶습니다.
Manu

죄송합니다. 이것이 오래된 스레드라는 것을 알고 있지만 @Version은 클러스터 환경의 더티 캐시도 고려합니까?
Shawn Eion Smith

3
SpringData JPA를 사용하는 경우 필드에 Long대한 기본 형식보다는 래퍼를 사용하는 것이 더 나을 수 있습니다 . 왜냐하면 null 버전 필드를 엔티티가 새로운 표시기로 취급 할 가능성이 높기 때문 입니다. 엔티티가 새로운 경우 (버전이 null로 표시됨) Spring은 . 그러나 버전에 값이 있으면 . 이것이 래퍼 유형으로 선언 된 버전 필드를 초기화하지 않은 상태로 두어야하는 이유이기도합니다. long@VersionSimpleJpaRepository.save(entity)em.persist(entity)em.merge(entity)
rdguam

33

@Pascal 답변은 완벽하게 유효하지만 내 경험상 아래 코드가 낙관적 잠금을 달성하는 데 도움이된다는 것을 알았습니다.

@Entity
public class MyEntity implements Serializable {    
    // ...

    @Version
    @Column(name = "optlock", columnDefinition = "integer DEFAULT 0", nullable = false)
    private long version = 0L;

    // ...
}

왜? 때문에:

  1. 로 주석이 달린 필드 가 실수로로 설정된 경우 낙관적 잠금 이 작동하지 않습니다 .@Versionnull
  2. 이 특별한 필드가 반드시 오해의 소지를 피하기 위해 객체의 비즈니스 버전, 아니므로, 내가 좋아하는 뭔가 같은 필드 이름을 선호 optlock하기보다는 version.

첫 번째 요점은 JPA 공급 업체가 생성시 필드에 적용 하기 때문에 데이터베이스에 데이터를 삽입하는 데 JPA 사용하는 경우에는 중요하지 않습니다 . 그러나 거의 항상 일반 SQL 문도 사용됩니다 (적어도 단위 및 통합 테스트 중).0@version


사용자가 인간이거나 정의 된 (자동화 된) 프로세스 / 엔티티 / 앱 (따라서 추가로 저장하는 것도 의미가있을 수 있음u_lmod )이 될 수있는 (사용자 마지막 수정) 이라고 부릅니다 u_lmod_id. (제 생각에는 매우 기본적인 비즈니스 메타 속성입니다). 일반적으로 그 값을 UTC로 DATE (TIME) (연도 ... 밀리에 대한 정보를 의미)로 저장합니다 (편집기의 시간대 "위치"가 시간대와 함께 저장하는 것이 중요한 경우). 또한 DWH 동기화 시나리오에 매우 유용합니다.
Andreas Dietrich

7
정수 대신 bigint를 db 유형에 사용하여 긴 Java 유형과 일치시켜야한다고 생각합니다.
Dmitry

좋은 점 Dmitry, 감사합니다. IMHO 버전 관리에 관해서는 실제로 중요하지 않습니다.
G. Demecki

9

데이터베이스에서 엔티티가 업데이트 될 때마다 버전 필드가 1 씩 증가합니다. 데이터베이스의 엔터티를 업데이트하는 모든 작업이 WHERE version = VERSION_THAT_WAS_LOADED_FROM_DATABASE쿼리에 추가 됩니다.

작업의 영향을받는 행을 확인할 때 jpa 프레임 워크는로드와 지속 사이에 버전 번호가 증가하면 쿼리가 데이터베이스에서 엔티티를 찾지 못하기 때문에 엔티티를로드하고 유지하는 사이에 동시 수정이 없는지 확인할 수 있습니다.


JPAUpdateQuery를 통하지 않습니다. 따라서 "데이터베이스의 엔티티를 업데이트하는 모든 작업은 쿼리에 WHERE 버전 = VERSION_THAT_WAS_LOADED_FROM_DATABASE를 추가합니다."는 사실이 아닙니다.
Pedro Borges

2

한 번에 하나의 업데이트 만 보장하는 데 사용되는 버전입니다. JPA 공급자는 버전을 확인합니다. 예상 버전이 이미 증가하면 다른 사람이 이미 엔티티를 업데이트하므로 예외가 발생합니다.

따라서 엔티티 값을 업데이트하는 것이 더 안전하고 낙관적입니다.

값이 자주 변경되는 경우 버전 필드를 사용하지 않는 것이 좋습니다. 예를 들어 "카운터 필드가있는 엔티티, 웹 페이지에 액세스 할 때마다 증가합니다"


0

정보를 조금 더 추가하세요.

JPA는 내부적으로 버전을 관리하지만을 통해 레코드를 업데이트 할 때는 그렇게하지 않습니다.이 JPAUpdateClause경우 쿼리에 버전 증분을 수동으로 추가해야합니다.

JPQL을 통한 업데이트에 대해서도 마찬가지입니다. 즉, 엔티티에 대한 단순한 변경이 아니라 최대 절전 모드에서 수행하더라도 데이터베이스에 대한 업데이트 명령입니다.

페드로


3
무엇입니까 JPAUpdateClause?
Karl Richter

좋은 질문, 간단한 대답은 다음과 같습니다. 나쁜 예 :) JPAUpdateClause는 QueryDSL에 특화되어 있습니다. 단순히 코드에서 엔티티의 상태에 영향을 미치는 것이 아니라 JPQL로 업데이트를 실행한다고 생각하십시오.
Pedro Borges
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.