오늘의 코드카타
Spring Data 구조 및 JpaRepository 원리
2024년 3월 8일 - [프로그래머스 - 자바(JAVA)] 35 : 숫자의 표현
Repository 는 MarkerInterface 로 특별한 기능은 없음
Repository ~ JpaRepository 까지는 @NotRepositoryBean
이 붙어있는 인터페이스이다. → 기능을 확장하기 위한 인터페이스라는 것을 명시
SimpleJpaReository
구현체 빈이 등록된다.@SpringBootApplication
을 통해 자동으로 붙여지는 @EnableJpaRepositories
의 JpaRepositoriesRegistrar 를 통해서 등록된다.기존 Repository vs 새로운 JpaRepository
- 기존 Repository
**@Repository**
을 클래스에 붙인다.- 앞서배운 RawJPA의 Repository 기능만 가진 구현체가 생성된다. (DB별 예외처리 등)
- 새로운 JpaRepository
- JpaRepository<Entity,ID> 인터페이스를 인터페이스에 extends 붙인다.
@NotRepositoryBean
된 **상위 인터페이스들의 기능을 포함한 구현체가 프로그래밍된다. (@NotRepositoryBean
** = 빈생성 막음)- SpringDataJpa 에 의해 엔티티의 CRUD, 페이징, 정렬 기능 메소드들을 가진 빈이 등록된다. (상위 인터페이스들의 기능)
// 변경 전
@Repository
public class UserRepository {
@PersistenceContext
EntityManager entityManager;
public User insertUser(User user) {
entityManager.persist(user);
return user;
}
public User selectUser(Long id) {
return entityManager.find(User.class, id);
}
}
// 변경 후
public interface UserRepository extends JpaRepository<User, Long> {
}
**@RepositoryDefinition**
을 인터페이스에 붙이는법 (가장 많이 쓰임)@RepositoryDefinition(domainClass = Comment.class, idClass = Long.class)
public interface CommentRepository {
Comment save(Comment comment);
List<Comment> findAll();
}
**@NoRepositoryBean**
인터페이스로 한번더 감싸는법@NoRepositoryBean
public interface MyRepository<T, ID extends Serializable> extends Repository<T, ID> {
<E extends T> E save(E entity);
List<T> findAll();
}
💡 delete() 메소드의 내부 기능 확인하기
@Transactional
public void delete(T entity) {
Assert.notNull(entity, "Entity must not be null");
if (!this.entityInformation.isNew(entity)) {
Class<?> type = ProxyUtils.getUserClass(entity);
T existing = this.em.find(type, this.entityInformation.getId(entity));
if (existing != null) {
this.em.remove(this.em.contains(entity) ? entity : this.em.merge(entity));
}
}
}
!em.contains(entity)
) 엔티티를 조회해서 영속성 상태로 바꾼다.public interface MyRepository {
...여기다가 추가할 메소드 선언...
}
public interface MyRepository<T> {
void delete(T entity);
}
@Repository
@Transactional
public class MyUserRepositoryImpl implements MyRepository<User> {
@Autowired
EntityManager entityManager;
@Override
public void delete(User user) {
System.out.println("delete Force");
entityManager.remove(user);
}
}
public interface UserRepository extends JpaRepository<User, Long> {
}
@SpringBootTest
@Rollback(value = false)
public class MyUserRepositoryTest {
@Autowired
UserRepository userRepository;
@Test
void myUserRepositoryDeleteTest() {
// given
User newUser = User.builder().username("name").password("pass").build();
userRepository.save(newUser);
// when
userRepository.delete(newUser);
}
}
MyRepository
public interface MyRepository<T> {
void delete(T entity);
List<String> findNameAll();
}
MyRepositoryImpl
@Repository
@Transactional
public class MyRepositoryImpl implements MyRepository {
@Autowired
EntityManager entityManager;
@Override
public List<String> findNameAll() {
return entityManager.createQuery("SELECT u.username FROM User AS u", String.class).getResultList();
}
}
@Transactional
을 적용하면 트랜직션이 생성이 되면 트랜직션의 범위는 1차캐시와 DB Transaction