P4-1] Ch08&9. 영속성 전이 & 쿼스텀 쿼리

uuuu.jini·2022년 2월 1일
0
post-thumbnail

github 링크

목차

  1. Cascade
  2. 고아제거속성
  3. @Query
  4. Native 쿼리
  5. Converter 사용

1. Cascade ?

영속성 전이이다. 작은 폭포라는 의미이다. 물을 받으면 흘려보내는 것처럼 영속성전이는 하나의 객체로 부터 다음객체로 영속성을 흘려 보낸다는 의미이다. 연관관계가 있는 경우에 설정할 수 있다. 연관관계 엔티티로 영속성을 전이시킬 수 있다.

CascadeType

연관을 맺은 엔티티에 영속성을 전이시킬 지의 여부를 enum type으로 정해놓은 것이다. 연관관계가 있는 객체에 영속성 처리를 자동으로 진행해주는 기능이다. 직접 repository 호출하지 않아도 cascade를 사용하는 경우가 꽤 많다. all속성은 모든 경우에 영속성 전이를 전파하도록 처리한다. 잘 모르겟는 경우 all옵션을 사용하기도 한다. defulat 값은 빈배열{} 이다. 기본상태에서는 어떠한 영속성도 전이하지 않는다.

  • Persist : 해당 객체가 insert가 될때 연관을 맺은 객체도 insert를 하겠다는 의미이다. 연관관계만 맺어줘도 해당 객체가 자동으로 생성된다.
  • Merge : merge에 대해 전이를 실행
  • Detach : 영속성을 관리하지 않고 분리하는 옵션이다. detach 시점에 연관관계를 맺고 있는 엔티티도 영속성 컨텍스트에서 제거한다.
  • Refresh : 연관관계 맺은 엔티티도 함께 재로딩

2. 고아 제거 속성

CascadeType.REMOVE 타입은 해당 객체가 삭제될경우 연관을 맺은 엔티티도 모두 삭제가 전이되는 옵션이다. 즉 연관을 맺은 객체를 모두 삭제하기 위해서는 해당 옵션을 사용하여야 한다.

Orphan Removal

연관관계가 없는 엔티티를 제거하는 속성이다. 연관관계를 끊기 위해서는 setter를 통해서 null을 주입하게 된다. remove cascade와 비슷하지만 연관관계가 끊어지면 remove이벤트가 발생하지 않는다. 연관관계가 전혀 없는 엔티티를 살려둘 것이라면 orphanRemoval을 false로 하고 필요없으면 true로 하여 제거한다.
만약 set으로 null을 실행하여 관련 엔티티가 디비에서 자동으로 제거해야 한다면 orphanRemoval을 null로 했지만 디비에서 자동으로 제거할것이 아니라면 removeCascade를 사용하면 된다. (이해 안됨 )

Soft Delete

현업에서 많이 사용하는 부분이다. 데이터 삭제와 관련된 기능이다. 위와 같은 방법은 delete쿼리를 사용한다. 하지만 일반 상용에서는 delete를 주로 사용하지 않는다. 일종의 플래그를 사용하여 지웠다라고 인식을 하게된다. 예로, boolean deleted 라는 변수를 두고 해당 속성이 true이면 지웠다 false이면 지우지않았다 를 지정하여 사용한다. 문제는 이런 플래그 사용시 일반적인 조회에서 true값이 출력이 되면 안된다. 삭제하였다고 간주하기 때문이다. 그럼 일일히 repository에서 해당 true값은 출력을 하지 않는 조건을 넣어야한다. 번거롭기 때문에 @Where라는 어노테이션을 엔티티클래스에 붙여주어 사용한다. 해당 어노테이션의 clause 속성의 값으로 조건을 넣어주면 해당 조건은 항상 포함이되어 쿼리를 실행한다.


3. @Query

쿼리메소드만으로도 일반적인 조회쿼리를 사용할 수 있다.

@Query는 밑의 두가지 상황에서 유용하다.

1. 쿼리 메소드의 가독성 문제 - 쿼리메소드의 이름이 길어지는 경우

List<Book> findByCategoryIsNullAndNameEqualsAndCreateAtGreaterThanEqualAndUpdateAtGreaterThanEqual(String name, LocalDateTime createdAt, LocalDateTime updatedAt);
@Query를 사용하여 가독성있는 이름을 만들수 있다. 기존에 사용하였던 이름을 짧고 가독성있게 만들수 있다.

Jpql : jpl의 entity 로 생성해주는 쿼리문이다. 장점은 방언을 통해서 데이터베이스의 종류에 따라 서로다른 쿼리를 자동으로 생성해준다. native query와는 차이가 있다. 쿼리메서드로 만드는 것과 비슷한 과정으로 생성이 된다.


위의 코드에서 value 속성으로 있는 값은 문자열로서 쿼리를 만들때는 동적으로 변경되는 파라미터 값들이 필요하다. 포맷팅을 하여 넣는 방법에는 ?1,?2 .. 로 ?와 숫자를 사용하는 방법과(메소드 인자 순서대로 쿼리문을 작성할 필요는 없고 순서로 맵핑한다. 지양하는 방법이다. ) name기반의 파라미터 매핑 으로 @Param을 사용하여 name을 지정한다.

2. 엔티티에 연결되지 않는 쿼리가 가능하다.

현업에서 필요한 쿼리들만 추려서 조회를 할수 있게 한다. 즉 엔티티에 필요한 값만 추출해서 처리를 하고 싶은 경우 사용한다.

dto형식의 구체 클래스를 사용할수도 있다.

3. 페이징 기능

메세지 오버로딩 : 파라미터가 다른 인자를 메소드의 이름이 동일한 메소드를 사용
페이징 처리도 간단하게 수행할 수 있다. (원하는 엔티티의 속성만 페이징 처리 하기 )


4. Native Query

@Query 어노테이션에서 native query 속성만 true로 해주면 된다. 엔티티의 이름과 필드의 이름을 데이터베이스에 정해놓은 동일한 이름을 사용해야 한다. native query 인 경우에는 지정한 sql문이 동일하게 수행된다.

    @Query(value= "select * from book",nativeQuery = true)
    List<Book> findAllCustom();

@Query 어노테이션의 value속성의 값인 sql문을 그대로 실행하게 된다.

사용하는 이유

1. 성능에 대한 문제의 해결

JPA 레포지토리의 메소드 중 deleteAllInBatch는 findAll을 수행하여 id값으로 각 레코드값의 delete를 수행한다. deleteInBatch 조건없이 모든것을 삭제한다. deletequery는 모든 레코드 조회하지 않고 한번에 처리가 가능하지만 updata 쿼리는 그런것이 존재하지 않고 하나하나 조회하여 save하도록 기능을 제공한다. 하나씩 조회를 하는경우 성능 이슈가 있다. 대량의 데이터인 경우 속도저하를 가져온다. ( 많은 데이터의 업데이트 위해 전부 가져온후 일일히 id로 업데이트를 하기 때문에 ) 한번의 쿼리로 실행을 위해 native query 를 사용한다.
update문 수행후에는 반환값으로 영향을 받은 로우수를 반환한다. 이럴 경우는 @Modifying 어노테이션과 @Transactional 어노테이션이 필요하다. @Where로 설정했던 값도 무시를 하고 설정한 sql문 그대로 실행을 하게 된다.

@Transaction 어노테이션은 구체 클래스에 사용하도록 권장한다. ( interface base proxy 도 가능하다 -> repostiory 는 가능함 안심 ! ) 해당 어노테이션을 메소드에 사용하지 못할 경우에는 사용처에서 처리를 해주어야 한다.

2. JPA에서 기본적으로 지원하지 않는 기능의 사용


5. Converter 활용

쿼리를 통해 가져온 데이터를 객체로 맵핑시 커스터마이징 하는 방식.
JPA에는 ORM이라는 인터페이스가 있다. 데이터베이스의 레코드를 자바의 객체화 시켜준다. 객체화 시 디비 데이터와 형식이 다른 경우 맵핑하는 방법을 알아본다. @Converter를 통하여 데이터 가져오는 즉시 정보변경하여 엔티티에서는 원래 그런 값이 있었던 것처럼 해준다. JPA에서 ENUM데이터를 가져오는 경우 Converter를 사용한다. 문자열을 받아서 enum의 네임으로 맵핑을 하여 변환해준다.

converter 가 완전하게 구현되어있지 않는 경우 실제 데이터가 유실되는 현상이 발생하게 된다. 이런식의 문제가 발생할 수 있으므로 converter구현시에는 필요하던 필요하지 않던 정방향 데이터 모두 정상적으로 동작하도록 모두 구현하여 사용해야 한다.

Converter 자주사용시 AutoApply옵션을 사용하는 것이 좋다. @Converter의 autoApply 속성을 true로 설정한다. 해당 엔티티 필드에 @Convert를 없애도 해당 타입이 엔티티의 필드로 선언이 되어잇으면 자동으로 해당 형으로 변환을 이루어준다. 편리하지만 주의해야 할 점이 있다. 일반적으로는 개발자가 생성한 클래스 타입에 한하여 활용을 해야 한다. StringConvert,IntegerConverter 등을 수행시 모든 varchar,number 타입이 해당 컨버터를 사용하게 되므로 문제가 발생할 수 있다. ( 별도의 클래스 생성한 경우에 사용하는 것을 권장한다. )

profile
멋쟁이 토마토

0개의 댓글