SpringData Jpa Update

반영환·2023년 5월 27일
0

스프링 이모저모

목록 보기
4/12
post-thumbnail

Spring Data Jpa Update

JPA는 기본적으로 주어진 메서드로 쿼리문을 작성할 수 있게 해준다.

@Query

만일 일반 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);
    
}

객체 파라미터 사용에 집중하자

@Transactional / @Modifying

@Modifying

여러 건의 연산을 수행할 경우 영속성 콘텍스트에 있는 1차 캐시를 사용하지 않고 DB에 직접 쿼리를 날리기 때문에 @Modifying을 Repository에 붙여줘야 한다.

에러를 막기 위해 항상 1차 캐시를 비워주어야 하므로 @Modifying 을 붙이는 것!
연산이 끝난 후 자동으로 1차 캐시를 비우기 위해선 clearAutomatically = true 옵션을 넣어주어야 한다.

@Modifying(clearAutomatically = true)

@Transactional

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(readOnly=true)

@Transactional은 Spring에서 제공하는 어노테이션을 사용해야 한다.

예상치 못한 엔티티의 등록, 변경, 삭제를 예방하고, 성능을 최적화할 수 있다.

왜 성능이 좋아지니?

readOnly가 true면 스프링 프레임워크가 하이버네이트 세션 플러시 모드MANUAL로 설정한다.

이렇게 하면 강제로 플러시를 호출하지 않는 한 플러시가 일어나지 않는다.

따라서 영속성 컨텍스트의 불필요한 플러시가 발생하지 않아 등록, 수정, 삭제가 동작하지 않고 읽기전용으로 영속성 컨텍스트는 변경 감지를 위한 스냅샷을 보유하지 않기 때문에 성능이 향상된다.

그럼 필요한 곳에만 쓰면?

서비스단에서 클래스단에 @Transaction을 걸어주고, Read만 하는 서비스에는 이 옵션을 걸어주면 코드 관리가 편리해지기 때문에!

profile
최고의 오늘을 꿈꾸는 개발자

0개의 댓글