๐ Spring Data JPA - ์๋ก์ด ์ํฐํฐ ์ฌ๋ถ ํ๋จ ๋ฐ ์ง์ ID ํ ๋น ์ ์ฃผ์์
๐ Spring Data JPA - ์๋ก์ด ์ํฐํฐ ์ฌ๋ถ ํ๋จ ๋ฐ ์ง์ ID ํ ๋น ์ ์ฃผ์์
๐ 1. Spring Data JPA์์ ์ํฐํฐ์ ์ ๊ท ์ฌ๋ถ ํ๋จ
Spring Data JPA์์ ์ํฐํฐ๊ฐ ์๋ก์ด์ง ์ฌ๋ถ๋ฅผ ํ๋จํ๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค.
์ด๊ฒ์ JPA๊ฐ ์ํฐํฐ๋ฅผ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ์ฅํ ๋ persist
๋ฅผ ์ฌ์ฉํ ์ง, ์๋๋ฉด merge
๋ฅผ ์ฌ์ฉํ ์ง๋ฅผ ๊ฒฐ์ ํ๋ ๋ฐ ์ง์ ์ ์ธ ์ํฅ์ ์ค๋๋ค.
Spring Data JPA์์๋ JpaEntityInformation
์ isNew(T entity)
๋ฉ์๋๋ฅผ ์ฌ์ฉํ์ฌ ์ํฐํฐ์ ์ ๊ท ์ฌ๋ถ๋ฅผ ํ๋จํฉ๋๋ค.
์ด ๋ฉ์๋๋ JpaMetamodelEntityInformation
ํด๋์ค๋ฅผ ํตํด ๋์ํ๋ฉฐ, ์ํฐํฐ์ @Version
ํ๋๋ @Id
ํ๋์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ์ ๊ท ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
โ
์ฆ, ์ํฐํฐ๊ฐ ์๋ก์ด ๊ฒฝ์ฐ (isNew()
๊ฐ true
๋ฐํ)
โ persist()
๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด ๋ฐ์ดํฐ๋ก ์ฝ์
โ
์ํฐํฐ๊ฐ ๊ธฐ์กด ๋ฐ์ดํฐ๋ก ํ๋จ๋๋ ๊ฒฝ์ฐ (isNew()
๊ฐ false
๋ฐํ)
โ merge()
๋ฅผ ์ฌ์ฉํ์ฌ ๊ธฐ์กด ๋ฐ์ดํฐ๋ฅผ ์์
๐ 2. ์ง์ ID ํ ๋น ์ ๋ฐ์ํ๋ ๋ฌธ์
์ผ๋ฐ์ ์ผ๋ก JPA์์๋ @GeneratedValue(strategy = GenerationType.IDENTITY)
์ ์ฌ์ฉํ์ฌ ์๋์ผ๋ก ID๋ฅผ ์์ฑํฉ๋๋ค.
๊ทธ๋ฌ๋ ๊ฐ๋ฐ์๊ฐ ์ง์ ์ํฐํฐ์ ID๋ฅผ ์ค์ ํ๋ ๊ฒฝ์ฐ, ์์์น ๋ชปํ ๋ฌธ์ ๊ฐ ๋ฐ์ํ ์ ์์ต๋๋ค.
๐น ๋ฌธ์ ์ํฉ
@Entity
public class User {
@Id
private String id; // ์ง์ ID ํ ๋น
private String name;
public User(String id, String name) {
this.id = id;
this.name = name;
}
}
์์ ๊ฐ์ด @GeneratedValue
์์ด ์ง์ ID๋ฅผ ์ค์ ํ๋ ๊ฒฝ์ฐ,
Spring Data JPA๋ ํด๋น ์ํฐํฐ๋ฅผ ๊ธฐ์กด ๋ฐ์ดํฐ๋ก ์ธ์ํ ์ ์์ต๋๋ค.
๐น ๋ฐ์ํ๋ ๋ฌธ์
User user = new User("123", "John Doe");
userRepository.save(user);
save()
๋ฅผ ํธ์ถํ๋ฉด Spring Data JPA๋ ํด๋น ID(โ123โ)๊ฐ ์กด์ฌํ๋์ง ํ์ธํ๊ธฐ ์ํด ๋จผ์ ์กฐํ ์ฟผ๋ฆฌ๋ฅผ ์คํ- ID๊ฐ ์์ผ๋ฉด
persist()
๋ฅผ ์คํํ์ง๋ง, ID๊ฐ ์กด์ฌํ๋ค๊ณ ํ๋จํ๋ฉด ๋ถํ์ํmerge()
๋ฅผ ์ํ - ์ฆ, ๋ถํ์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์กฐํ๊ฐ ๋ฐ์ํ๋ฉฐ ์ฑ๋ฅ ์ ํ ๊ฐ๋ฅ์ฑ์ด ์์
๐ 3. ํด๊ฒฐ ๋ฐฉ๋ฒ - Persistable
์ธํฐํ์ด์ค ๊ตฌํ
์ง์ ID๋ฅผ ์ค์ ํ๋ ๊ฒฝ์ฐ, Spring Data JPA๊ฐ ์ํฐํฐ์ ์ ๊ท ์ฌ๋ถ๋ฅผ ์ ํํ ํ๋จํ ์ ์๋๋ก Persistable
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ๋ ๊ฒ์ด ์ข์ต๋๋ค.
๐น Persistable
์ ํ์ฉํ ํด๊ฒฐ ๋ฐฉ๋ฒ
import org.springframework.data.domain.Persistable;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.Transient;
@Entity
public class User implements Persistable<String> {
@Id
private String id;
private String name;
@Transient // JPA๊ฐ ์ธ์ํ์ง ์๋๋ก ์ค์
private boolean isNewEntity = false;
public User(String id, String name) {
this.id = id;
this.name = name;
this.isNewEntity = true; // ์ ์ํฐํฐ์์ ํ์
}
@Override
public String getId() {
return id;
}
@Override
public boolean isNew() {
return isNewEntity; // ์ ์ํฐํฐ ์ฌ๋ถ๋ฅผ ์ง์ ๊ด๋ฆฌ
}
}
โ ์ค๋ช
Persistable<T>
์ธํฐํ์ด์ค๋ฅผ ๊ตฌํํ์ฌ Spring Data JPA๊ฐisNew()
๋ฉ์๋๋ฅผ ํธ์ถํ๋๋ก ์ ๋isNew()
๊ฐtrue
์ด๋ฉดpersist()
๊ฐ ์คํ๋๋ฉฐ,false
์ด๋ฉดmerge()
๊ฐ ์คํ๋จ@Transient
์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ์ฌ JPA๊ฐ ๊ด๋ฆฌํ์ง ์๋๋ก ์ค์ (isNewEntity
ํ๋๋ DB์ ์ ์ฅ๋์ง ์์)
๐ 4. isNew()
๋ด๋ถ ๋์ ๋ฐฉ์
Spring Data JPA์์ isNew()
๋ ์ํฐํฐ์ ID ๊ฐ ๋ฐ @Version ๊ฐ์ ํ์ธํ์ฌ ์ ๊ท ์ฌ๋ถ๋ฅผ ๊ฒฐ์ ํฉ๋๋ค.
๊ธฐ๋ณธ์ ์ผ๋ก JpaMetamodelEntityInformation
์ ํตํด ์ํฐํฐ์ ์ํ๋ฅผ ํ์ธํฉ๋๋ค.
@Override
public boolean isNew(T entity) {
if(versionAttribute.isEmpty()
|| versionAttribute.map(Attribute::getJavaType).map(Class::isPrimitive).orElse(false)) {
return super.isNew(entity);
}
BeanWrapper wrapper = new DirectFieldAccessFallbackBeanWrapper(entity);
return versionAttribute.map(it -> wrapper.getPropertyValue(it.getName()) == null).orElse(true);
}
โ ์ค๋ช
@Version
์ด ์๋ ๊ฒฝ์ฐ, ๋๋@Version
์ด primitive ํ์ ์ด๋ฉด ๊ธฐ๋ณธisNew()
๋ฅผ ํธ์ถ@Version
์ด wrapper ํ์ ์ด๋ฉด ํด๋น ํ๋๊ฐnull
์ธ์ง ํ์ธํ์ฌ ์ ๊ท ์ฌ๋ถ๋ฅผ ํ๋จ
๐น AbstractEntityInformation
์์์ ๋์
public boolean isNew(T entity) {
Id id = getId(entity);
Class<ID> idType = getIdType();
if (!idType.isPrimitive()) {
return id == null;
}
if (id instanceof Number) {
return ((Number) id).longValue() == 0L;
}
throw new IllegalArgumentException(String.format("Unsupported primitive id type %s", idType));
}
โ ์ค๋ช
@Version
์ด ์์ผ๋ฉด@Id
ํ๋๋ฅผ ํ์ธ- primitive ํ์
์ด ์๋๋ฉด
null
์ฌ๋ถ, ์ซ์(Number) ํ์ ์ด๋ฉด0
์ฌ๋ถ๋ฅผ ํ์ธํ์ฌ ์ ๊ท ์ฌ๋ถ ํ๋จ
๐ 5. ์ ๋ฆฌ
โ
Spring Data JPA๋ JpaEntityInformation#isNew(T entity)
๋ฅผ ์ฌ์ฉํ์ฌ ์ํฐํฐ์ ์ ๊ท ์ฌ๋ถ๋ฅผ ํ๋จ
โ
ID๋ฅผ ์ง์ ์ค์ ํ๋ฉด JPA๊ฐ ๊ธฐ์กด ์ํฐํฐ๋ก ์ค์ธํ ๊ฐ๋ฅ์ฑ์ด ์์
โ
๋ถํ์ํ SELECT
๋ฐ merge()
๋ฅผ ๋ฐฉ์งํ๊ธฐ ์ํด Persistable
์ธํฐํ์ด์ค๋ฅผ ํ์ฉํ ์ ์์
โ
isNew()
์ ๋ด๋ถ ๋์ ๋ฐฉ์์ @Version
๋ฐ @Id
ํ๋์ ์ํ๋ฅผ ๊ธฐ๋ฐ์ผ๋ก ๊ฒฐ์ ๋จ
๐ ์ด๋ฌํ ๋ด์ฉ์ ๊ณ ๋ คํ์ฌ ID๋ฅผ ์ง์ ํ ๋นํ ๋ JPA์ ๋์์ ์ดํดํ๊ณ ์ต์ ํํ๋ ๊ฒ์ด ์ค์ํฉ๋๋ค. ๐
์ถ์ฒ
๋งค์ผ๋ฉ์ผ : Spring Data JPA์์ ์๋ก์ด Entity์ธ์ง ํ๋จํ๋ ๋ฐฉ๋ฒ์ ๋ฌด์์ผ๊น์?
๋๊ธ๋จ๊ธฐ๊ธฐ