JPA는 기본적으로 주어진 메서드로 쿼리문을 작성할 수 있게 해준다.
만일 일반 SQL문을 써야하는 경우 Repository에서 @Query문을 사용해 작성해주면 된다.
@Repository
public interface IUsrRepository extends JpaRepository<Usr, String> {
// 일반 JPA
Usr findById(String id);
// 일반 SQL 사용
@Query(value="select * from user u where u.id=?1", nativeQuery=true)
Usr findUsr1(String id);
// 일반 SQL에 파라미터 지정 사용
@Query(value="select * from user u where u.id=:id", nativeQuery=true)
Usr findUsr2(@Param(value=id)String id);
// 일반 SQL에 객체 파라미터 사용
@Query(value="select * from user u where u.id=:#{#userInfo.id}", nativeQuery=true)
Usr findUsr3(@Param(value=userInfo) UserInfo info);
// JPQL 사용
@Query("select * from from Usr u where u.id=?1")
Usr findUsr4(String id);
// JPQL 사용에 파라미터 지정 사용
@Query("select * from from Usr u where u.id=:id")
Usr findUsr5(@Param(value=id)String id);
// JPQL 사용에 객체 파라미터 사용
@Query(value="select * from Usr u where u.id=:#{#userInfo.id}")
Usr findUsr6(@Param(value=userInfo)UserInfo info);
}
객체 파라미터 사용에 집중하자
여러 건의 연산을 수행할 경우 영속성 콘텍스트에 있는 1차 캐시를 사용하지 않고 DB에 직접 쿼리를 날리기 때문에 @Modifying
을 Repository에 붙여줘야 한다.
에러를 막기 위해 항상 1차 캐시를 비워주어야 하므로 @Modifying
을 붙이는 것!
연산이 끝난 후 자동으로 1차 캐시를 비우기 위해선 clearAutomatically = true
옵션을 넣어주어야 한다.
@Modifying(clearAutomatically = true)
DB를 update하거나 delete할 때 표기해줘야 정상 시행된다. 이는 사용 서비스단에서 선언해도 되나 결국 repository가 영속성을 가져가 사용하기 때문에 repository 단에서 선언해도 된다.
하지만 @Query
를 사용한 부분에만 따로 붙이기는 번거롭기 때문에 service 단에서 처리하자.
Repository
public interface BoardRepository extends JpaRepository<Board, Long> {
Optional<Board> findByBoardId(Long boardId);
@Modifying
@Query("update Board set title = #(#paramBoard.title), content = #(#paramBoard.content), applyLimit = #(#paramBoard.applyLimit), dueDate = #(#paramBoard.dueDate)")
Optional<Board> updateBoard(@Param(value = "paramBoard") Board board);
}
Service
@Service
@RequiredArgsConstructor
@Transactional
public class BoardServiceImpl implements BoardService{
private final BoardRepository boardRepository;
...
}
@Transactional
은 Spring에서 제공하는 어노테이션을 사용해야 한다.
예상치 못한 엔티티의 등록, 변경, 삭제를 예방하고, 성능을 최적화할 수 있다.
readOnly
가 true면 스프링 프레임워크가 하이버네이트 세션 플러시 모드
를 MANUAL
로 설정한다.
이렇게 하면 강제로 플러시를 호출하지 않는 한 플러시가 일어나지 않는다.
따라서 영속성 컨텍스트의 불필요한 플러시가 발생하지 않아 등록, 수정, 삭제가 동작하지 않고 읽기전용으로 영속성 컨텍스트는 변경 감지를 위한 스냅샷을 보유하지 않기 때문에 성능이 향상된다.
서비스단에서 클래스단에 @Transaction
을 걸어주고, Read만 하는 서비스에는 이 옵션을 걸어주면 코드 관리가 편리해지기 때문에!