카테고리 없음
Hibernate ID Generator
JUNG_EV
2024. 5. 7. 08:46
Hibernate ID Generator 나만의 JPA @ID 만들기
JPA의 Entity를 구성할때 특수한 상황일 경우 @ID의 값이 Sequence이지만 Long이 아니거나 특별한 ID를 줘야하는 경우가 있습니다.
커스텀 generator를 사용합니다.
커스텀 ID Generator 만들기
이 Generator는 우리 상황에 맞는 ID를 생성할 수 있도록 도와줄 것입니다.
import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.Configurable;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.internal.util.config.ConfigurationHelper;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.Type;
import java.io.Serializable;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
public class IdGenerator implements IdentifierGenerator, Configurable {
// 속성값 처리를 위한 Const
public static final String METHOD = "method";
public static final String SEQUENCE_NAME = "sequence_name";
public static final String INCREMENT_SIZE = "increment_size";
// 전달받은 속성값
private String method; // id 생성 방법
private String sequenceName; // sequenceName 추가
private int incrementSize; // 증가 크기 변수 추가
// 속성값 처리 메소드 override
@Override
public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException {
method = ConfigurationHelper.getString(METHOD, params);
sequenceName = ConfigurationHelper.getString(SEQUENCE_NAME, params); // sequenceName 설정
incrementSize = ConfigurationHelper.getInt(INCREMENT_SIZE, params, 1); // 증가 크기 설정
}
// ID 생성 처리 메소드 override
@Override
public Serializable generate(SharedSessionContractImplementor session, Object obj) {
String sql = null;
Serializable newId = null; // newId 변수 추가
switch (method) {
case "SEQUENCE":
// 시퀀스의 증가 크기를 반영하여 SQL 쿼리 생성
sql = "SELECT " + sequenceName + ".NEXTVAL FROM DUAL";
break;
default:
// 다른 방식에 대한 처리
break;
}
// JDBC Connection
Connection con = null;
try {
con = session.getJdbcConnectionAccess().obtainConnection();
CallableStatement callStatement = con.prepareCall(sql);
callStatement.executeQuery();
ResultSet rs = callStatement.getResultSet();
if (rs.next()) {
newId = rs.getString(1);
}
} catch (SQLException sqlException) {
throw new HibernateException(sqlException);
} finally {
try {
if (con != null && !con.isClosed()) { // null 체크 추가
con.close();
}
} catch (SQLException e) {
e.getStackTrace();
}
}
return newId;
}
}
- IdentifierGenerator 인터페이스 구현: IdGenerator 클래스는 IdentifierGenerator 인터페이스를 구현합니다. 이 인터페이스에는 엔티티의 ID를 생성하기 위한 generate 메서드가 포함되어 있습니다.
- Configurable 인터페이스 구현: IdGenerator 클래스는 또한 Configurable 인터페이스를 구현합니다. 이는 Hibernate에게 이 클래스가 구성 가능한 것임을 알려주는 인터페이스입니다. configure 메서드에서는 속성값을 읽어와서 필요한 초기화 작업을 수행합니다.
- generate 메서드: generate 메서드에서는 주어진 방식에 따라 새로운 ID를 생성합니다. 현재는 "SEQUENCE" 방식만 구현되어 있으며, 시퀀스를 사용하여 ID를 생성합니다. 그런 다음 생성된 ID를 반환합니다.
JPA에 붙이기
이제 @Entity의 @Id에서 사용해 봅니다.
import jakarta.persistence.*;
import *.IdGenerator;
import lombok.Getter;
import org.hibernate.annotations.CreationTimestamp;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import java.util.Date;
@Getter
@Entity
@Table(name = "테이블_이름", schema = "스키마_이름")
public class RandomEntity {
@Id
@GeneratedValue(generator = "RandomEntity_IdGenerator")
@GenericGenerator(name = "RandomEntity_IdGenerator", strategy = "*.IdGenerator", parameters = {
@Parameter(name = IdGenerator.METHOD, value = "SEQUENCE"),
@Parameter(name = IdGenerator.SEQUENCE_NAME, value = "시퀀스_이름"),
})
@Column(name = "SEQ_NO")
private String seqNo;
@Column(name = "USER_ID")
private String userId;
@Column(name = "MONEY", precision = 10, scale = 0)
private Long moneyAmount;
@CreationTimestamp
@Column(name = "SYS_CREATION_DATE")
private Date createdAt;
}
시퀀스의 기본 설정은 1씩 올라가기 때문에 increasement_size는 설정하지 않습니다.
@GeneratedValue의 generator는 고유한 이름을 주는것이 권장되며 @GenericGenerator의 name과 동일해야합니다.
strategy는 decrypted 되었지만 파일의 위치를 명시적으로 보여주고 찾기 위해서 설정합니다.