@Version JPA 및 Hibernate로 데이터베이스 동시성 방지
새로운 개발자에게는 혼란스러울 것 같지만 피하는 것은 매우 쉽습니다.
JPA(Java Persistence API)에는 데이터베이스 레코드가 업데이트된 횟수를 확인하는 데 도움이 되는 주석이 있습니다.
이 간단한 테이블과 엔터티를 살펴보겠습니다.
create table device
(
id integer not null constraint device_pk primary key,
serial integer,
name varchar(255),
version integer
)
그리고 엔티티
package com.vominh.example.entity;
import javax.persistence.*;
@Entity
@Table(name = "device")
public class DeviceWithVersionEntity {
@Id
@Column(name = "id")
private Integer id;
@Column(name = "serial")
private Integer serial;
@Column(name = "name")
private String name;
@Version
@Column(name = "version")
private int version;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public Integer getSerial() {
return serial;
}
public void setSerial(Integer serial) {
this.serial = serial;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getVersion() {
return version;
}
public void setVersion(int version) {
this.version = version;
}
}
이 부분은 "누군가 업데이트 작업을 수행하면 이 필드가 1씩 증가합니다"와 같이 이해할 수 있습니다.
@Version
@Column(name = "version")
private int version;
메인 클래스
package com.vominh.example;
import com.vominh.example.entity.DeviceWithVersionEntity;
import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;
import java.util.Random;
import java.util.concurrent.CompletableFuture;
public class ConcurrencyControl {
private static final SessionFactory sessionFactory;
private static final ServiceRegistry serviceRegistry;
static {
Configuration configuration = new Configuration();
configuration.configure("hibernate.cfg.xml");
// Since Hibernate Version 4.x, ServiceRegistry Is Being Used
serviceRegistry = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()).build();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
}
public static void main(String[] args) {
Session session = sessionFactory.openSession();
Query deleteAllDevice = session.createQuery("delete from DeviceWithVersionEntity");
try {
session.beginTransaction();
deleteAllDevice.executeUpdate();
DeviceWithVersionEntity device = new DeviceWithVersionEntity();
device.setId(1);
device.setSerial(8888);
device.setName("Dell xps 99");
session.save(device);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
session.getTransaction().rollback();
} finally {
session.close();
}
// open 50 session in 50 thread to update one record
for (int i = 0; i < 50; i++) {
CompletableFuture.runAsync(() -> {
var s = sessionFactory.openSession();
try {
s.beginTransaction();
DeviceWithVersionEntity d = (DeviceWithVersionEntity) s.load(DeviceWithVersionEntity.class, 1);
d.setName((new Random()).nextInt(500) + "");
s.save(d);
s.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
s.getTransaction().rollback();
} finally {
s.close();
}
});
}
}
}
실행 결과는 많은 org.hibernate.StaleObjectStateException을 발생시킵니다.
예외 메시지는 이미 어떤 일이 발생하는지 설명하고 있지만 언제 어떻게 발생합니까?
Row was updated or deleted by another transaction (or unsaved-value mapping was incorrect)
Entity(숫자)의 필드에 추가하면 생성/업데이트 작업이 실행될 때 Hibernate는 필드의 값을 설정/증가합니다.
UPDATE device set name = 'new name', version = version + 1
다음 UPDATE가 발생하면 Hibernate는 WHERE 절에 조건을 추가하여 버전이 일치하는지 확인합니다.
UPDATE device SET name = 'new name', version = version + 1
WHERE id = ? AND version = **CURRENT_VERSION**
다른 세션이 이미 레코드를 업데이트하고 버전이 증가한 경우 WHERE 절이 일치하지 않고 예외가 발생합니다.
이 방법은 낙관적 잠금이라고도 하며 JPA 및 Hibernate(무거운 논리를 처리함)로 구현하기 쉽습니다.
소스 코드: https://github.com/docvominh/java-example/tree/master/hibernate-jpa
나는 maven, hibernate 4.3 및 postgres SQL을 사용합니다.
읽어주셔서 감사합니다!
Reference
이 문제에 관하여(@Version JPA 및 Hibernate로 데이터베이스 동시성 방지), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/docvominh/prevent-database-concurrency-with-version-jpa-and-hibernate-5c8l텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)