UUID v7 생성기 추가 - Hibernate IdentifierGenerator 구현
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled

This commit is contained in:
Rinjae
2026-07-27 18:28:09 +09:00
parent 6a64d35a94
commit 94724d3952
@@ -0,0 +1,66 @@
package com.eactive.apim.portal.jpa;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.id.IdentifierGenerator;
import java.io.Serializable;
import java.security.SecureRandom;
/**
* UUID version 7 (time-ordered, RFC 9562) 생성기.
*
* <p>상위 48비트에 Unix epoch 밀리초 타임스탬프를 두어 생성 시각 순으로 정렬되므로,
* 무작위 v4 대비 인덱스(B-Tree) 삽입 지역성이 좋아 PK 인덱스 단편화를 줄인다.
* canonical 36자 문자열로 반환하여 기존 {@code VARCHAR2(36)} 컬럼과 호환된다.</p>
*
* <p>레이아웃(128비트): unix_ts_ms(48) | ver=0b0111(4) | rand_a(12) | var=0b10(2) | rand_b(62)</p>
*
* <p>Java 8 호환(java.util.UUID + SecureRandom). Hibernate {@link IdentifierGenerator} 구현이며
* 엔티티에서 {@code @GenericGenerator(strategy = "...UuidV7Generator")} 로 지정한다.</p>
*/
public class UuidV7Generator implements IdentifierGenerator {
private static final SecureRandom RANDOM = new SecureRandom();
@Override
public Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException {
return generateString();
}
/** UUID v7 을 canonical 36자 문자열로 생성한다. */
public static String generateString() {
long timestamp = System.currentTimeMillis();
byte[] value = new byte[16];
// 상위 48비트: unix epoch millis (big-endian)
value[0] = (byte) ((timestamp >>> 40) & 0xFF);
value[1] = (byte) ((timestamp >>> 32) & 0xFF);
value[2] = (byte) ((timestamp >>> 24) & 0xFF);
value[3] = (byte) ((timestamp >>> 16) & 0xFF);
value[4] = (byte) ((timestamp >>> 8) & 0xFF);
value[5] = (byte) (timestamp & 0xFF);
// 나머지 10바이트는 난수로 채운다.
byte[] rand = new byte[10];
RANDOM.nextBytes(rand);
System.arraycopy(rand, 0, value, 6, 10);
// version 7: value[6] 상위 니블을 0111 로 설정
value[6] = (byte) ((value[6] & 0x0F) | 0x70);
// variant 10xx: value[8] 상위 2비트를 10 으로 설정
value[8] = (byte) ((value[8] & 0x3F) | 0x80);
long msb = 0L;
for (int i = 0; i < 8; i++) {
msb = (msb << 8) | (value[i] & 0xFFL);
}
long lsb = 0L;
for (int i = 8; i < 16; i++) {
lsb = (lsb << 8) | (value[i] & 0xFFL);
}
return new java.util.UUID(msb, lsb).toString();
}
}