JPA Methods

ORM은 java 객체와 DB record와의 연동을 해주는 것이므로, 최종 동작은 SQL 쿼리가 실행된다.

JpaRepository의 메서드를 통해 실행되는 실제 쿼리들을 살펴볼 수 있다.

  • show-sql : 메서드를 통해 실행되는 쿼리를 log로 찍을 수 있음
  • properties:hibernate:format_sql : 보기 좋게 정렬
1
2
3
4
5
6
7
spring:
jpa:
defer-datasource-initialization: true
show-sql: true
properties:
hibernate:
format_sql: true

Method

getOne(), getById(), FindById()

getOne()

  • Entity에 대해서 Lazy Loading을 하여, Spring Data JPA 2.5 버전 이전에만 사용되었다.
  • 일반적으로 객체를 getOne()으로 불러와 저장, 출력 등을 실행할 때 session이 만료되기 때문에 @Transactional 어노테이션과 함께 사용하여야한다.

더 이상 사용되지 않는 getOne() 메서드를 getById() 메서드가 대체합니다.
참조값을 return해주기 때문에, query를 통해 구현되던 기존의 getById() 메서드로 대체합니다.
이로 인해 transaction 외부에서 LazyLoadingException이 발생할 수 있는데, 이를 방지하기 위해 getById()메서드를 getXyzId() 메서드로 변경해야한다.
Xyz에는 아무 문자열이나 들어갈 수 있다.
출처 : Spring Data JPA docs

1
2
3
4
5
6
7
@Deprecated
@Override
public T getOne(ID id) {

Assert.notNull(id, ID_MUST_NOT_BE_NULL);
return em.getReference(getDomainClass(), id);
}

위와 같이 EntityManager em이 reference만 가지고있고, 실제 값을 구하는 시점에 세션을 통해 값을 가져와야한다.

getById()

  • JPA 2.5 버전 이상에서 getOne()과 같이 사용하면 됩니다.
  • 구현 코드 또한 같다.

findById()

  • Opional entity를 리턴해주며, Eager Loading 방식이다.
  • Optional 객체로 wrapping되어 있기 때문에 별도의 처리가 필요하다.
  • 아래와 같이 해당 객체가 없으면 null을 리턴하도록 처리하였다.
1
2
3
User user = userRepository.findById(1L).orElse(null);

System.out.println(user);
1
return Optional.ofNullable(type == null ? em.find(domainType, id, hints) : em.find(domainType, id, type, hints));

Entity Manger에서 바로 find()메서드를 통해 가져온다.

Sort()

sort.by를 사용하면 ORDER BY 쿼리가 실행된다.

1
2
3
List<User> users = userRepository.findAll(Sort.by(Sort.Direction.DESC, "name"));

users.forEach(System.out::println);

findAllById()

findAllById, findById를 사용하면 WHERE 쿼리를 사용한다.

1
2
3
List<Long> ids = new ArrayList<Long>;
ids.add(1L);
/* ... */

Main 폴더에서 사용할 때는 위와 같이 ArrayList를 생성해서 값을 넣어주어야한다.

하지만 Test 코드에서는 assrtj의 클래스를 사용하여 아래와 같이 사용할 수 있다.

1
2
List<User> users = userRepository.findAllById(Lists.newArrayList(1L, 3L, 5L));
users.forEach(System.out::println);

saveAll()

saveAll()을 실행하면 각 객체에 대해 INSERT 쿼리를 객체 수만큼 실행한다.

1
2
3
4
User user1 = new User("inwoo", "inwoo@gmail.com");
User user2 = new User("eddy", "eddy@gmail.com");

userRepository.saveAll(Lists.newArrayList(user1, user2));

flush(), saveAndFlush()

flush()를 실행하여 DB에 반영하는 시점을 제어할 수 있다.

saveAndFlush()는 저장 후 바로 DB에 반영을 시켜주는 메서드이다.

1
2
3
4
5
userRepostiory.save(new User("inwoo", "inwoo@gmail.com"));

userRepository.flush();

userRepository.saveAndFlush();

count()

count는 이름 그대로 Repository의 데이터가 개수를 리턴해준다.
리턴 타입은 long이다.

1
long count = userRepository.count();

existsById()

Id 값을 parameter로 넣어 해당 id에 해당하는 데이터가 있는지 boolean 타입으로 리턴한다.

1
boolean exists = userRepository.existsById(1L);

delete()

해당 데이터를 찾아서 parameter로 입력하면 data를 WHERE 쿼리를 통해 삭제한다.

1
userRepository.delete(userRepository.findById(1L).orElseThrow(RuntimeException::new));

etc. (Page, QBE)

Page

Page는 데이터를 literally page 형태로 감싸준다.

아래 코드는 repo에 있는 모든 데이터를 Pagerequest를 통해 1페이지의 데이터를 가져오고, 1페이지당 size 3으로 나누어 생성한다.

1
Page<User> users = userRepository.findAll(PageRequest.of(1,3));

위 코드의 users 페이지의 getter()를 통해 다양한 데이터를 호출할 수 있다.

1
2
3
4
5
6
System.out.println("page 정보 : " + users);
System.out.println("전체 데이터 개수 : " + users.getTotalElements());
System.out.println("데이터 리스트를 size로 나누었을 때 나온 전체 페이지" + users.getTotalPages());
System.out.println("PageRequest에 요청했던 페이지에 있는 데이터 개수 (zero-bases)" + users.getNumberOfElements());
System.out.println("Sort로 설정한 값" + users.getSort());
System.out.println("PageRequest에 요청했던 페이지 1개당 size" + users.getSize());

QBE (Query By Example)

QBE는 단어그대로 ExampleMatcher를 생성하여, 해당된 데이터를 찾아내는 방식이다.

1
2
3
4
5
6
7
ExampleMatcher matcher = ExampleMatcher.matching() // matching 선언
.withIgenorePaths("name") // matching에서 제외할 column 설정
.withMatcher("email", endsWith()); // email column에서 설정한 단어로 끝나는 데이터가 있으면 match

Example<User> example = Example.of(new User("Any name does'nt care", "gmail.com"), matcher);

userRepository.findAll(example).forEach(System.out::println);

위 코드를 보면 먼저 ExampleMatcher를 생성하고, Example의 타입을 알맞은 Data 타입으로 설정해준다.

내부에서 임시적으로 객체를 생성하여, 이 객체와 matching되는 데이터를 matcher를 통해 찾는다.

Author

Inwoo Jeong

Posted on

2021-11-03

Updated on

2021-11-03

Licensed under

You need to set install_url to use ShareThis. Please set it in _config.yml.

댓글