
Entity์ ๊ธฐ๋ณธํค (primary key)๋ฅผ ์์ฑํ๋ ๋ฐฉ๋ฒ์ผ๋ก ๋ณดํต Auto Increment ๋ฐฉ์์ด๋ UUID ๋ฐฉ์์ ๋ง์ด ์ฌ์ฉํ๋ค.
- Auto Increment
: ๊ตฌํ์ด ๊ฐ๋จํ๊ณ ์ฌ์ ๋ ฌ์ด ํ์์๋ค(์์๊ฐ ๋ณด์ฅ๋๋ค.)
: ํ๋์ DB์์ ์์ฑํ๊ธฐ ๋๋ฌธ์ ์ค์ผ์ผ์์์ ํตํ ํ์ฅ์ด ๋ถ๊ฐ๋ฅํ๋ค. (์ฒ๋ฆฌ ์ฑ๋ฅ ํ์ ์ด ์ด๋ ค์)
: insert ํ์์ผ PK ๊ฐ์ ์์ฑํ ์ ์๋ค.
: ๋ณดํต bigint๋ก ๊ตฌํ.
: ์ธ๋ถ์ ๋ ธ์ถ๋ ๊ฒฝ์ฐ ์ฌ์ฉํ๋ฉด ์๋๋ค. (๋ค๋ฅธ id๋ฅผ ์ ์ถ ๊ฐ๋ฅํ๊ธฐ ๋๋ฌธ์)
- UUID
: ๋คํธ์ํฌ ์์์ ๊ณ ์ ์ฑ์ด ๋ณด์ฅ๋๋ ID๋ฅผ ๋ง๋ค๊ธฐ ์ํ ํ์ค ๊ท์ฝ
: 128 bit ๋ฐ์ดํฐ๋ก ํํ (16 Byte)
: ๋ฉํฐ ํ๊ฒฝ์์๋ ๋ณ๋ ฌ๋ก ๋์ํ์ฌ ์ ์ผํ ID๋ฅผ ์์ฑํ ์ ์๋ค.
: 128bit๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ง์ ๊ณต๊ฐ์ ์ฐจ์งํ๋ฉฐ ์ธ๋ฑ์ค ๊ตฌ์ถ์ ์ ํฉํ์ง์๋ค.
: ํค์ ์๋ฏธ๋ฅผ ๊ฐ๊ธฐ ์ด๋ ต๋ค.
- SnowFlake
: Twitter์์ OSS๋ก ๊ณต๊ฐํ๊ณ ์๋ ID ์์ฑ๊ธฐ
: Time-base๋ก ํ ID
(1๋ฐ๋ฆฌ์ด ์ด๋ด์ ๋์์ ์์ฑ๋ ์ผ๋ จ๋ฒํธ๋ฅผ ํฌํจํ์ฌ, ๊ฐ์ ์๊ฐ, ๊ฐ์ ๋จธ์ ์์ ์ค๋ณต๋๋๋ ๊ฒ์ ๋ฐฉ์ง - 12bit)
: 64 Bit์ Long ๊ฐ์ผ๋ก ๋ฐ์ดํฐ๋ก ํํ

: ๋ฉํฐ ํ๊ฒฝ์์๋ ๋ณ๋ ฌ๋ก ๋์ํ์ฌ ์ ์ผํ ID๋ฅผ ์์ฑํ ์ ์๋ค.
: timestamp ๊ฐ์ ๊ธฐ์ด๋ก ํ๊ธฐ ๋๋ฌธ์ ID ์ ๋ ฌ์ด ๊ฐ๋ฅํ๋ค.
: id๋ฅผ ํตํด ์์ฑ์๋ฅผ timestamp ๊ฐ์ผ๋ก ๋ณต์๊ฐ๋ฅํ๋ค.
: OS์ ์๊ฐ ์ฐจ์ด์ ์ฝํ๋ฉฐ ์๊ฐ์ด ์๋ชป ์ญ์ ๋ ๊ฒฝ์ฐ ๊ณ ์ฅ์ด ๋ฐ์ํ ์ ์๋ค.
(๋ถ์ฐ ์์คํ ์ ์๋ ๋ชจ๋ ์ธ์คํด์ค๊ฐ ๊ฐ์ ์์คํ ์ ์๊ฐ์ ๋ณด์ฅํ ์ ์์ด์ผํ๋ค.)
generate_id : https://github.com/callicoder/java-snowflake
Twitter์์ ์ ๊ณตํ SnowFlake ๋ฐฉ์์ UUID ๋ณด๋ค ์์ ํฌ๊ธฐ๋ก ๋๋คํ ๊ฐ์ ์ ๊ณตํ๊ธฐ๋๋ฌธ์ ์ข์๋ณด์ด์ง๋ง git repo์ ์ ๋ฐ์ด๋๊ฐ ์๋์ง ๊ฝค ๋๊ฒ์ผ๋ก ๋ณด์ ์ง๊ธ ์ฌ์ฉํ๊ธฐ๋ ํ๋ค์ด๋ณด์ธ๋ค.
โ Custom ID
๋ณดํต UUID ๊ฐ์ ๋ง์ด ์ฌ์ฉํ์ง๋ง ํน์ ๋ฐฉ์์ผ๋ก ํค๊ฐ์ ๊ด๋ฆฌํด์ผํ๋ ๊ฒฝ์ฐ๊ฐ ์์ ์ ์๋ค. ์๋ฅผ ๋ค์ด ์ฃผ๋ฌธ ๋ฒํธ์ฒ๋ผ ์ผ์ ํจํด์ผ๋ก ์์ฑํ๋ ๊ฐ์ ํค ๊ฐ์ผ๋ก ์ฌ์ฉํ๋ ๊ฒฝ์ฐ๊ฐ ์์ ์ ์๋ค.

JPA Hibernate์์๋ Custom ID ์์ฑ๋ฅผ ์์ฑํ ์ ์๋ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํ๋ค.
๊ธฐ๋ณธ ์ ๋ต์ ์ฌ์ฉํ๊ณ ์ถ์ง ์์๋, ์ด๋ฅผ ์ํด IdentifierGenerator ์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ฌ ์ฌ์ฉ์ ์ง์ ์์ฑ๊ธฐ๋ฅผ ์ ์ํ ์ ์๋ค.
public class MyGenerator implements IdentifierGenerator {
private String prefix;
// ํค๋ฅผ ์์ฑํ๋ ๋ก์ง์ ๊ฐ์ง๋ ๋ฉ์๋
@Override
public Serializable generate(
SharedSessionContractImplementor session, Object obj)
throws HibernateException {
return prefix + System.currentTimeMillis() + (int)(Math.random() * 1000);
}
// ํค๋ฅผ ์์ฑํ๋ ํ๋ก์์ ์ ๊ฐ์ ๋๊ฒจ์ฃผ๊ธฐ์ํ ๋ฉ์๋. ์ ๋ฌ๋ฐ์ ํ๋ผ๋ฏธํฐ๊ฐ ์๋ค๋ฉด Overrideํ์ง ์์๋ ๋๋ค.
@Override
public void configure(Type type, Properties properties,
ServiceRegistry serviceRegistry) throws MappingException {
prefix = properties.getProperty("prefix");
}
}
์ค๋ณต Id๋ฅผ ์์ฑํ์ง ์๋ ๊ฒ์ด ์ค์ํ๊ธฐ ๋๋ฌธ์ currentTimeMillis์ ๋๋ค ๊ฐ์ ๋ํด ๊ตฌํํด ๋ณด์์ต๋๋ค. millisecond์์ ์ผ๋ง๋ ๋ง์ ์์ฒญ์ด ๋ค์ด์ฌ์ง๋ ๋ชจ๋ฅด๊ฒ ์ง๋ง random๊ฐ์ ์ค๋ณต์ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ํฌ๋ฐํ ํ๋ฅ ๋ก ์ค๋ณต๊ฐ์ด ๋์ฌ์๋ ์์ ๊ฒ ๊ฐ์ต๋๋ค.
- IdentifierGenerator ์ธํฐํ์ด์ค๊ตฌํ ํด๋์ค๋ ๋ฐ๋์ public์ผ๋ก ์ ์ธ๋ ๊ธฐ๋ณธ ์์ฑ์๊ฐ ์์ด์ผ ํฉ๋๋ค.
- Properties ํด๋์ค์ getProperty() ๋ฉ์๋๋ String ๊ฐ๋ง์ ๋ฐํํ์ง๋ง, ConfigurationHelper ํด๋์ค์๋ getString(), getBoolean() ๋ฑ์ ๋ค์ํ ๊ฐ์ ๋ฐํํ๋ ๋ฉ์๋๋ค์ด ์์ด์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
prefix = ConfigurationHelper.getString(SEQ_GENERATOR_PARAM_KEY, params);
- ๋งค๊ฐ๋ณ์ session์ ์ด์ฉํด์ ์ฟผ๋ฆฌ๋ฅผ ์คํํ๋ ํํ๋ก ์์ฑํ ์ ์๋ค. connetction์ ๊ฐ์ ธ์ฌ ์ ์์ง๋ง ์ด Connection ์ Hibernate ๊ฐ ๊ด๋ฆฌํ๊ธฐ ๋๋ฌธ์ ์ง์ close๋ ํ์ง ๋ง๊ฒ.
Connection connection = session.connection();
ํด๋น Generator๋ @GenericGenerator ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ modifier์ ๊ตฌํ ํด๋์ค ๋ช ์ ์ ์ธํด์ฃผ๋ฉด ์ฌ์ฉ๊ฐ๋ฅํ๋ค.
@Id
@GeneratedValue(generator = "order-generator")
@GenericGenerator(name = "orderId-generator",
strategy = "com.prgrms.bdbks.domain.order.MyGenerator")
private String orderId;
ํ๋ผ๋ฏธํฐ๋ฅผ ์ ๋ฌํ ๊ฒฝ์ฐ
@Id
@GeneratedValue(generator = "order-generator")
@GenericGenerator(name = "orderId-generator",
parameters = @Parameter(name = "prefix", value = "prod"),
strategy = "com.prgrms.bdbks.domain.order.MyGenerator")
private String orderId;
๋ค๋ฅธ ์์ ๋ค์ ์ดํด๋ณด์
public class StockCodeGenerator
implements IdentifierGenerator {
@Override
public Serializable generate(
SessionImplementor session, Object object)
throws HibernateException {
String prefix = "M";
Connection connection = session.connection();
try {
PreparedStatement ps = connection
.prepareStatement("SELECT nextval ('seq_stock_code') as nextval");
// ๋ค์ ์ํ์ค ๊ฐ์ ๊ฐ์ ธ์จ๋ค.
ResultSet rs = ps.executeQuery();
if (rs.next()) {
int id = rs.getInt("nextval");
String code = prefix + StringUtils.leftPad("" + id,3, '0');
return code;
}
} catch (SQLException e) {
log.error(e);
throw new HibernateException(
"Unable to generate Stock Code Sequence");
}
return null;
}
}
https://kwonnam.pe.kr/wiki/java/hibernate/id_generator
prefix๋ฅผ ํ๋ผ๋ฏธํฐ๊ฐ ์๋ ๊ณ ์ ๊ฐ์ผ๋ก ์ง์ ํ์๊ณ , DB์ ์ ๊ทผํ์ฌ ์ํ์ค ๊ฐ์ ๊ฐ์ ธ์จ๋ค์ ๋ค์ ์ํ์ค ๊ฐ์ prefix์ ํฉํ์ฌ id๋ก ๋ฐํํด์ค๋ค.
public class MyGenerator
implements IdentifierGenerator {
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");
}
}
https://www.baeldung.com/hibernate-identifiers
QueryDSL์ ์ด์ฉํ ๊ตฌํ์ธ๊ฒ ๊ฐ๋ค. id๊ฐ์ ๊ฐ์ ธ์ 'prefix-'๋ฅผ ์ ๊ฑฐํ ํ max+1 ํด์ ๋ค์ prefix๋ฅผ ๋ถ์ฌ์ ๋ฐํ.
์ค๋ณต์ ์ ๊ฑฐํ ์ ์๋ ๋ฐฉ์์ผ๋ก ๋ค์ํ๊ฒ ์ปค์คํ ํ ์ ์์ ๊ฒ๊ฐ๋ค.
http://www.gisdeveloper.co.kr/?p=5623
https://toshi15shkim.github.io/articles/2019-10/java-unique-id
reference.
https://www.baeldung.com/hibernate-identifiers
https://zet-it-story.tistory.com/1
https://techblog.woowahan.com/2607/
https://kapentaz.github.io/jpa/Hibernate์์-Custom-ID-์์ฑํ๊ธฐ/#
์๋ชป๋ ์ ๋ณด๊ฐ ์๋ค๋ฉด ๋๊ธ์ ํตํด ์๋ ค์ฃผ์ธ์. ๊ฐ์ฌํฉ๋๋ค.
'Back-end ๋ฐ๋ธ์ฝ์ค > Clone Project' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[Spring] Map Struct ์ฌ์ฉํ๊ธฐ (0) | 2023.01.21 |
---|
๋๊ธ