1. 사전 준비
-프로젝트 구성
-build.gradle
dependencies{
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
implementation 'org.springframework.boot:spring-boot-starter-web'
compileOnly 'org.projectlombok:lombok'
runtimeOnly 'com.h2database:h2'
annotationProcessor 'org.projectlombok:lombok'
testImplementation 'org.springframework.boot:spring-boot-starter-test'
}
1. data.sql
을 통해 기초 데이터 생성
call next value for hibernate_sequence;
→ insert를 하는 경우 id를 자동 생성하는데 그것이 충돌나지 않기 위하여 id값을 증가
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (1, 'martin', 'martin@fastcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (2, 'dennis', 'dennis@fastcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (3, 'sophia', 'sophia@slowcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (4, 'james', 'james@slowcampus.com', now(), now());
call next value for hibernate_sequence;
insert into user (`id`, `name`, `email`, `created_at`, `updated_at`) values (5, 'marti
n', 'martin@another.com', now(), now());
2. application.yml
설정
spring.h2.console.enabled: true
h2 console을 사용하는지 여부 설정
spring.jpa.defer-datasource-initialization: true
data.sql을 시스템이 올라온 후 사용할지 여부 설정
spring.jpa.show-sql: true
jpa 쿼리를 볼 것인지 여부 설정
spring.jpa.properties.hibernate.format_sql: true
jpa 쿼리를 정렬된 상태로 볼 수 있는 설정
logging.level.org.hibernate.type: trace
파라미터 값이 어떻게 매핑되는지 확인하는 설정
spring:
h2:
console:
enabled: true
jpa:
defer-datasource-initialization: true
show-sql: true
properties:
hibernate:
format_sql: true
logging:
level:
org.hibernate.type: trace
3. domain >
User.java
작성
@NoArgsConstructor
@AllArgsConstructor
@RequiredArgsConstructor
@Data
@Builder
@Entity
public class User {
@Id
@GeneratedValue
private Long id;
@NonNull
private String name;
@NonNull
private String email;
private LocalDateTime createdAt;
private LocalDateTime updatedAt;
}
4. repository >
UserRepository.java
작성
@Repository
public interface UserRepository extends JpaRepository<User, Long>{
}
2. 테스트 코드 작성 및 실행 결과
→ crud()
메소드에서 학습용 코드를 넣어서 결과를 확인
@SpringBootTest //스프링 컨텍스트를 사용하겠다.
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
void crud(){ //create, read, update, delete
}
}
[ Select 다중 쿼리 ]
→ 공통: users.stream().forEach(System.out::println);
이용하여 결과 출력
- List<T> findAllById(Iterable<ID> ids);
List<User> users = userRepository.findAllById(Lists.newArrayList(1L, 3L, 5L));
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_
where
user0_.id in (
? , ? , ?
)
- List<T> findAll(Sort sort);
List<User> users = userRepository.findAll(Sort.by(Sort.Direction.DESC, "name"));
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_
order by
user0_.name desc
[ Select 단일 쿼리 ]
- T getOne(ID id);
→ *Lazy(지연된, 로드된 후 실행)
한 조회방법으로 테스트 코드에 @Transactional
필요하다.
@Test
@Transactional
void crud(){
User user = userRepository.getOne(1L); //getOne Entity에 대해서 lazy한 로딩
System.out.println(user);
}
Hibernate:
select
user0_.id as id1_0_0_,
user0_.created_at as created_2_0_0_,
user0_.email as email3_0_0_,
user0_.name as name4_0_0_,
user0_.updated_at as updated_5_0_0_
from
user user0_
where
user0_.id=?
- Optional<T> findById(ID id);
→ 가장 일반적으로 사용하는 방식, Optional로 Entity를 감쌓다.
→ 쿼리는 getOne와 동일하지만, Lazy의 차이가 있음. @Transactional 필수적이지 않음
User user = userRepository.findById(1L).orElse(null);
Hibernate:
select
user0_.id as id1_0_0_,
user0_.created_at as created_2_0_0_,
user0_.email as email3_0_0_,
user0_.name as name4_0_0_,
user0_.updated_at as updated_5_0_0_
from
user user0_
where
user0_.id=?
- long count();
long count = userRepository.count();
Hibernate:
select
count(*) as col_0_0_
from
user user0_
- boolean existsById(ID id);
boolean exists = userRepository.existsById(1L);
Hibernate:
select
count(*) as col_0_0_
from
user user0_
where
user0_.id=?
[ Paging 쿼리 ]
- Page<T> findAll(Pageable pageable);
Page<User> users = userRepository.findAll(PageRequest.of(0, 3)); //0페이지, 3개씩
System.out.println("page : " + users); //객체
System.out.println("totalElements : " + users.getTotalElements()); //총 레코드 수
System.out.println("totalPages : " + users.getTotalPages()); //총 페이지 수
System.out.println("numberOfElements : " + users.getNumberOfElements()); //현재 페이지의 레코드 수 (zero-base index 0에서부터 시작)
System.out.println("sort : " + users.getSort()); //소트 방식
System.out.println("size : " + users.getSize()); //페이징 나누는 수
users.getContent().forEach(System.out::println);
<쿼리>
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_ limit ?
Hibernate:
select
count(user0_.id) as col_0_0_
from
user user0_
<결과>
page : Page 1 of 2 containing com.example.bookmanager.domain.User instances
totalElements : 5
totalPages : 2
numberOfElements : 3
sort : UNSORTED
size : 3
User(id=1, name=martin, email=martin@fastcampus.com, createdAt=2021-07-20T21:58:38.005887, updatedAt=2021-07-20T21:58:38.005887)
User(id=2, name=dennis, email=dennis@fastcampus.com, createdAt=2021-07-20T21:58:38.016890, updatedAt=2021-07-20T21:58:38.016890)
User(id=3, name=sophia, email=sophia@slowcampus.com, createdAt=2021-07-20T21:58:38.017889, updatedAt=2021-07-20T21:58:38.017889)
[ Insert 쿼리 ]
- <S extends T> S save(S entity);
userRepository.save(new User("Kim", "kim@naver.com"));
Hibernate:
call next value for hibernate_sequence
Hibernate:
insert
into
user
(created_at, email, name, updated_at, id)
values
(?, ?, ?, ?, ?)
- <S extends T> S saveAndFlush(S entity);
→ flush: 쿼리 변화x 디비 반영시점을 조정, 동작확인 어렵다.
userRepository.saveAndFlush(new User("Kim", "kim@naver.com"));
Hibernate:
call next value for hibernate_sequence
Hibernate:
insert
into
user
(created_at, email, name, updated_at, id)
values
(?, ?, ?, ?, ?)
[ Delete 쿼리 ]
- void delete(T entity);
→ 해당 데이터가 있는지 조회 후 삭제
userRepository.delete(userRepository.findById(1L).orElseThrow(RuntimeException::new));
Hibernate:
select
user0_.id as id1_0_0_,
user0_.created_at as created_2_0_0_,
user0_.email as email3_0_0_,
user0_.name as name4_0_0_,
user0_.updated_at as updated_5_0_0_
from
user user0_
where
user0_.id=?
Hibernate:
delete
from
user
where
id=?
- void deleteById(ID id);
userRepository.deleteById(1L);
Hibernate:
select
user0_.id as id1_0_0_,
user0_.created_at as created_2_0_0_,
user0_.email as email3_0_0_,
user0_.name as name4_0_0_,
user0_.updated_at as updated_5_0_0_
from
user user0_
where
user0_.id=?
Hibernate:
delete
from
user
where
id=?
- void deleteAll();
→ 데이터를 조회 후 한건 한건씩 삭제
userRepository.deleteAll();
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_
Hibernate:
delete
from
user
where
id=?
Hibernate:
delete
from
user
where
id=?
...
- void deleteAll(Iterable<? extends T> entities);
userRepository.deleteAll(userRepository.findAllById(Lists.newArrayList(1L, 3L)));
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_
where
user0_.id in (
? , ?
)
Hibernate:
delete
from
user
where
id=?
Hibernate:
delete
from
user
where
id=?
- void deleteAllInBatch();
→ 조회하지 않고 바로 삭제
userRepository.deleteAllInBatch();
Hibernate:
delete
from
user
- void deleteAllInBatch(Iterable<T> entities);
userRepository.deleteAllInBatch(userRepository.findAllById(Lists.newArrayList(1L, 3L)));
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_
where
user0_.id in (
? , ?
)
Hibernate:
delete
from
user
where
id=?
or id=?
[ update 쿼리 ]
- <S extends T> S save(S entity);
→ insert문과 동일한 save()
를 사용 id값이 있는 entity인 경우 update를 한다.
userRepository.save(new User("david", "david@gmail.com")); //insert
User user = userRepository.findById(1L).orElseThrow(RuntimeException::new); //select
user.setEmail("martin-update@gmail.com");
userRepository.save(user); //update
//SimpleJpaRepository.java save 구현 부분
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
[ Example ] - 잘 사용하진 않음
- <S extends T> List<S> findAll(Example<S> example);
→ withIgnorePaths("name")
name의 설정은 무시하겠다.
→ withMatcher("email", endsWith())
email 값으로 끝나는 조건 ( like email '%fastcampus.com' )
→ withMatcher("email", startsWith())
email 값으로 시작하는 조건 ( like email 'fastcampus.com%' )
→ withMatcher("email", contains())
email 값을 모두 포함하는 조건
( like email '%fastcampus.com%' )
ExampleMatcher matcher = ExampleMatcher.matching()
.withIgnorePaths("name")
.withMatcher("email", endsWith());
Example<User> example = Example.of(new User("ma", "fastcampus.com"), matcher);
userRepository.findAll(example).forEach(System.out::println);
Hibernate:
select
user0_.id as id1_0_,
user0_.created_at as created_2_0_,
user0_.email as email3_0_,
user0_.name as name4_0_,
user0_.updated_at as updated_5_0_
from
user user0_
where
user0_.email like ? escape ?
2021-07-20 22:27:26.326 TRACE 9200 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [1] as [VARCHAR] - [%fastcampus.com]
2021-07-20 22:27:26.326 TRACE 9200 --- [ Test worker] o.h.type.descriptor.sql.BasicBinder : binding parameter [2] as [CHAR] - [\]
Example<User> example = Example.of(new User("ma", "fastcampus.com"));
userRepository.findAll(example).forEach(System.out::println);
User user = new User();
user.setEmail("slow");
ExampleMatcher matcher = ExampleMatcher.matching().withMatcher("email", contains());
Example<User> example = Example.of(user, matcher);
'백엔드 > JPA' 카테고리의 다른 글
[ JPA ] 5-2. Entity Relations ( 1:1 @OneToOne ) (0) | 2021.07.25 |
---|---|
[ JPA ] 5-1. Entity Relations (ERD, 데이터베이스 기준 연관 관계) (0) | 2021.07.25 |
[ JPA ] 4. Entity Listener (1) | 2021.07.24 |
[ JPA ] 3. Entity 기본속성 (0) | 2021.07.22 |
[ JPA ] 2. Query Method 정의 및 실습 (0) | 2021.07.21 |