1. ๊ฐ์
public Member saveMember(){
// Member ๊ฐ์ฒด ์์ฑ
Member member = createMember();
// ์ ์ฅ
return memberRepository.save(member);
}
์์ ๊ฐ์ด save๋ฉ์๋๋ฅผ ํธ์ถ ๋ฐ ๋ฆฌํดํ ๋ ์์ฑ๋ ๊ฐ์ฒด์ ๋์ผํ ๊ฐ์ฒด๊ฐ ๋ฆฌํด๋๋์ง, ์๋๋ฉด ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด์ ๋ฆฌํด์ํค๋์ง ๊ถ๊ธํด์ก๋ค. ๊ถ๊ธ์ฆ ํด๊ฒฐ์ ์ํด ํด๋น ๋ฉ์๋์ ๋์ ์๋ฆฌ๋ฅผ ํ์ ํด๋ณด์!
2. ๊ตฌํ์ฒด ๋ถ์
package org.springframework.data.repository;
/**
* Interface for generic CRUD operations on a repository for a specific type.
*/
@NoRepositoryBean
public interface CrudRepository<T, ID> extends Repository<T, ID> {
/**
* Saves a given entity. Use the returned instance for further operations as the save operation might have changed the
* entity instance completely.
*
* @param entity must not be {@literal null}.
* @return the saved entity; will never be {@literal null}.
* @throws IllegalArgumentException in case the given {@literal entity} is {@literal null}.
* @throws OptimisticLockingFailureException when the entity uses optimistic locking and has a version attribute with
* a different value from that found in the persistence store. Also thrown if the entity is assumed to be
* present but does not exist in the database.
*/
<S extends T> S save(S entity);
}
save() ๋ฉ์๋๋ CrudRepository์ ์ ์ธ๋์ด ์๋ค. ๊ตฌํ์ด ๋์ด ์๋ ์ํ๊ฐ ์๋๊ธฐ ๋๋ฌธ์ ์ด๋ป๊ฒ ๋์ํ๋์ง ํ์ ์ด ์ด๋ ต๋ค.
package org.springframework.data.jpa.repository.support;
/**
* Default implementation of the {org.springframework.data.repository.CrudRepository} interface.
* This will offer you a more sophisticated interface than the plain {EntityManager}.
*/
@Repository
@Transactional(readOnly = true)
public class SimpleJpaRepository<T, ID> implements JpaRepositoryImplementation<T, ID> {
@Override
@Transactional
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null");
if (entityInformation.isNew(entity)) {
entityManager.persist(entity);
return entity;
} else {
return entityManager.merge(entity);
}
}
}
CrudRepository์ ๊ตฌํ์ฒด์ธ SimpleJpaRepository๋ก ์ด๋ํด์ ํ์ธํด๋ณด์.
entity.isNew ์ด๋ฉด entityManager.persist ๋ฅผ ํธ์ถํ๊ณ , ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ ์ํฐํฐ ๊ฐ์ฒด๋ฅผ ๊ทธ๋๋ก ๋ฐํํ๋ ๊ฒ์ ์ ์ ์๋ค. entity.isNew๊ฐ ์๋๋ฉด entityManager.merge ๋ฅผ ํธ์ถํ๊ณ , ํ๋ผ๋ฏธํฐ๋ก ์ ๋ฌํ ์ํฐํฐ ๊ฐ์ฒด๊ฐ ์๋ ๋ค๋ฅธ ๊ฐ์ฒด๋ฅผ ๋ฆฌํดํ๋ ๊ฒ์ ์ ์ ์๋ค.
merge์ ๊ฒฝ์ฐ, save ๋ฉ์๋๋ฅผ ํตํด ๋ฆฌํด๋ ์ํฐํฐ๋ง ์์์ฑ ์ปจํ ์คํธ๊ฐ ๊ด๋ฆฌํ๋ค. merge๋ ์ค์์ ์ํ์ ์ํฐํฐ๋ฅผ DB์์ ์กฐํํ๊ณ , DB์์ ์กฐํ๋ ์ํฐํฐ๋ฅผ ์์์ฑ ์ปจํ ์คํธ์ ๋ฃ๊ณ ํด๋น ์ํฐํฐ๋ฅผ ๋ฐํํ๋ค. ๋ฐ๋ผ์ ๋ฐํ๋ ์ํฐํฐ๋ ์์์ฑ ์ปจํ ์คํธ๊ฐ ๊ด๋ฆฌํ์ง๋ง, ๊ธฐ์กด ์ธ์๋ก ๋๊ฒจ์ค ์ํฐํฐ๋ ์ฌ์ ํ ์ค์์ ์ํ์ด๊ธฐ ๋๋ฌธ์ ์ด๋ฅผ ์ฃผ์ํด์ผ ํ๋ค!
isNew๋ ์ ์ง ์๋ก์ด ์ํฐํฐ์ธ์ง ๊ตฌ๋ณํ๋ ๋ฉ์๋ ์ธ ๊ฒ ๊ฐ์๋ฐ ์ด๋ป๊ฒ ์๋ก์ด ์ํฐํฐ ์ธ์ง ๊ตฌ๋ณํ ์ ์์๊น?
package org.springframework.data.repository.core.support;
/**
* Base class for implementations of {EntityInformation}. Considers an entity to be new whenever
* {getId(Object)} returns {null} or the identifier is a {Java primitive} and
* {getId(Object)} returns zero.
*/
public abstract class AbstractEntityInformation<T, ID> implements EntityInformation<T, ID> {
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));
}
}
์๋ณ์๊ฐ Primitive ํ์ ์ด ์๋ ์ฐธ์กฐ ํ์ (Long, Integer, ...) ์ผ ๋๋ id๊ฐ null์ธ์ง ์๋์ง๋ก ํ๋ณํ๋ค. ๋ง์ฝ id == null ์ด๋ผ๋ฉด ์๋ก์ด ์ํฐํฐ๋ผ๊ณ ํ๋จํ๊ณ true๋ฅผ ๋ฐํํ๋ค.
์๋ณ์๊ฐ ๊ธฐ๋ณธ ํ์ (long, int, ...)์ผ ๊ฒฝ์ฐ์๋ id๊ฐ 0์ธ์ง ์๋์ง๋ก ํ๋ณํ๋ค. ๋ง์ฝ id == 0L ์ด๋ผ๋ฉด ์๋ก์ด ์ํฐํฐ๋ผ๊ณ ํ๋จํ๊ณ true๋ฅผ ๋ฐํํ๋ค.
๊ทธ๋ ๋ค๋ฉด ๋ง์ฝ id๋ฅผ @GenerateValue๊ฐ ์๋, ์ง์ ํ ๋นํ๋ ๊ฒฝ์ฐ์๋ ์ด๋ป๊ฒ ํ ๊น? ์ด๋ฐ ๊ฒฝ์ฐ์๋ merge๊ฐ ํธ์ถ๋๋๋ฐ, merge๋ DB๋ฅผ ํธ์ถํด์ ๊ฐ์ ํ์ธํ๊ณ , DB์ ๊ฐ์ด ์์ผ๋ฉด ์๋ก์ด ์ํฐํฐ๋ก ์ธ์ง๋ฅผ ํ๊ธฐ ๋๋ฌธ์ ์ด๋ ์์ฃผ ๋นํจ์จ์ ์ด๋ค. ๋ฐ๋ผ์ Persistable ๋ฅผ ์ฌ์ฉํ์ฌ ์๋ก์ด ์ํฐํฐ๋ฅผ ํ์ธ๋ฅผ ๋ก์ง์ ์ง๋๊ฒ ๋ ํจ์จ์ ์ด๋ค. @CreatedDate๋ฅผ ๊ฐ์ด ์ฌ์ฉํ์ฌ @CreatedDate์ ๊ฐ์ด ์์ผ๋ฉด ์๋ก์ด ์ํฐํฐ๋ก ํ๋จํ๋ ๋ก์ง์ ์์ฑํ๋ ๋ฐฉ๋ฒ์ด ์๋ค.
// Persistable ์ธํฐํ์ด์ค
package org.springframework.data.domain;
public interface Persistable<ID> {
ID getId();
boolean isNew();
}
// Persistable ๊ตฌํ
@Entity
@EntityListeners(AuditingEntityListener.class)
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Item implements Persistable<String> {
@Id
private String id;
@CreatedDate
private LocalDateTime createdDate;
public Item(String id) {
this.id = id;
}
@Override
public String getId() {
return id;
}
@Override
public boolean isNew() {
return createdDate == null;
}
}
์ฐธ๊ณ
์ธํ๋ฐ ๊น์ํ ๊ฐ์ฌ๋ - "์ค์ ! ์คํ๋ง ๋ฐ์ดํฐ JPA"
'๐ฟ Spring > JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
์์ ,์ญ์ ์ฟผ๋ฆฌ ์ง์ ์์ฑ ์ ์ฃผ์ํด์ผ ํ ์ (0) | 2024.12.12 |
---|