📖Identifiers in Hibernate/JPA
strategies of id generations
https://www.baeldung.com/hibernate-identifiers
AUTO Generation strategy
- 숫자 타입
- the primary key value들은 database level에서 unique하게 됨
- based on a sequence or table generator
- @Entity public class Student { @Id @GeneratedValue private long studentId; // ... }
- UUID 타입
- Hibernate 5부터 추가된 UUIDGenerator를 이용
- Hibernate will generate an id of the form “8dd5f315-9788-4d00-87bb-10eed9eff566”.
- @Entity public class Course { @Id @GeneratedValue private UUID courseId; // ... }
**IDENTITY Generation
@Entity
public class Student {
@Id
@GeneratedValue (strategy = GenerationType.IDENTITY)
private long studentId;
// ...
}
- IdentityGenerator를 이용
- database의 identity column을 이용해서 값을 생성함 = auto-incremented 라는 뜻
- One thing to note is that IDENTITY generation disables batch updates.
**SEQUENCE Generation
@Entity
public class User {
@Id
@GeneratedValue(generator = "sequence-generator")
@GenericGenerator(
name = "sequence-generator",
strategy = "org.hibernate.id.enhanced.SequenceStyleGenerator",
parameters = {
@Parameter(name = "sequence_name", value = "user_sequence"),// sequence에 이름을 지정
@Parameter(name = "initial_value", value = "4"), //-> 4부터 값이 시작됨
@Parameter(name = "increment_size", value = "1")
}
)
private long userId;
// ...
}
- SequenceStyleGenerator class를 이용
- 만약 사용하는 database가 sequence기능을 지원한다면 sequence를 사용함, 지원하지 않는다면 table generation으로 전환됨
- @GenericGenerator annotation : to customize the sequence name
- SEQUENCE is the generation type recommended by the Hibernate documentation.
- The generated values are unique per sequence. If we don’t specify a sequence name, Hibernate will reuse the same hibernate_sequence for different types
TABLE Generation
@Entity
public class Department {
@Id
@GeneratedValue(strategy = GenerationType.TABLE,
generator = "table-generator")
@TableGenerator(name = "table-generator",
table = "dep_ids",
pkColumnName = "seq_id",
valueColumnName = "seq_value")
private long depId;
// ...
}
- TableGenerator 를 이용 → TableGenerator가 identifier generation values를 보유하는 database table를 이용함
- 단점 : 성능을 저하시키고 확장이 잘 되지 않는다
Custom Generator
- IdentifierGenerator interface를 implement 하면 Custom id generator를 만들 수 있음!
예시) String prefix와 number를 포함하는 identifiers 만들기
public class MyGenerator
implements IdentifierGenerator, Configurable {
private String prefix;
@Override
public Serializable generate(
SharedSessionContractImplementor session, Object obj)
throws HibernateException {
String query = String.format("select %s from %s",
session.getEntityPersister(obj.getClass().getName(), obj)
.getIdentifierPropertyName(),
obj.getClass().getSimpleName());
Stream ids = session.createQuery(query).stream();
Long max = ids.map(o -> o.replace(prefix + "-", ""))
.mapToLong(Long::parseLong)
.max()
.orElse(0L);
return prefix + "-" + (max + 1);
}
@Override
public void configure(Type type, Properties properties,
ServiceRegistry serviceRegistry) throws MappingException {
prefix = properties.getProperty("prefix");
}
}
override the generate() method from the IdentifierGenerator interface.
override Configurable interface 의 configure() method
- prefix-XX에서 존재하는 primary key중에 가장 큰 값을 찾아옴
- 가장 큰 primary key값에 1을 더한 후 prefix property 를 붙여줌
- Configurable interface 의 configure() method를 사용해서 prefix property value를 설정해줌
- @GenericGenerator annotation 를 이용해서 custom generator를 entity에 달아줌
@Entity
public class Product {
@Id
@GeneratedValue(generator = "prod-generator")
@GenericGenerator(name = "prod-generator",
parameters = @Parameter(name = "prefix", value = "prod"),
strategy = "com.baeldung.hibernate.pojo.generator.MyGenerator")
private String prodId;
// ...
}
이 예제에서는 prefix parameter를 “prod”로 설정함
테스트코드가 있음
@Test
public void whenSaveCustomGeneratedId_thenOk() {
Product product = new Product();
session.save(product);
Product product2 = new Product();
session.save(product2);
assertThat(product2.getProdId()).isEqualTo("prod-2");
}
Here the first value generated using the “prod” prefix was “prod-1”, followed by “prod-2”.
→ 이후는 전에 해봤던 복합키!