UUID v7 생성기 추가 - Hibernate IdentifierGenerator 구현
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
eapim-portal CI (from elink-portal-common) / build (push) Has been cancelled
This commit is contained in:
@@ -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();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user