ORM: Object-Relational Mapping이란?
JPA: Java Persistence API란?
Hibernate란??
사실상 표준
이다.영속성 컨텍스트란? 엔티티(Entity)를 저장하고 관리하는 저장소의 개념
코드로 공부하기
//application.properties
spring.h2.console.enabled=true
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.url=jdbc:h2:./myselectdb;AUTO_SERVER=TRUE
spring.datasource.username=sa
spring.datasource.password=
spring.jpa.properties.hibernate.format_sql=true
spring.jpa.hibernate.ddl-auto=update
spring.jpa.generate-ddl=true
logging.level.org.hibernate.SQL=debug
logging.level.org.hibernate.type.descriptor.sql=trace
JPA 영속성 컨텍스트 1차 캐시 이해
Users beforeSavedUser = new Users("user1", "정국", "불족발");
// 회원 "user1" 객체를 영속화
Users savedUser = userRepository.save(beforeSavedUser);
// beforeSavedUser: 영속화되기 전 상태의 자바 일반객체
// savedUser:영속성 컨텍스트 1차 캐시에 저장된 객체
assert(beforeSavedUser != savedUser); // 같은 객체일 경우 에러가 발생한다. assert는 괄호 안의 내용이 참이어야함을 강력히 주장하는 메서드
Entity 조회 시
1차 캐시에 조회하는 Id가 존재하는
경우: 1차 캐시에 저장되어있는 entity(객체)를 가져온다.
실제로 디버깅하며 테스트 해봐도 insert 이후 조회 시 select문이 실행이 안되는 것을 알 수 있음.
1차 캐시에 조회하는 Id가 없는
경우: select 쿼리문을 실행하여 DB에서 해당 객체를 가져온다.
1차 캐시 사용의 장점
1차 캐시
를 사용해 DB row 1개 당 객체 1개가 사용되는 것을 보장 (객체 동일성 보장)Entity 삭제 시
캐시 뿐만 아니라 DB에 저장된 객체도 삭제한다.
Entity 업데이트 실패 (Setter)
public Users updateUserFail() {
// 회원 "user1" 객체 추가
Users user = new Users("user1", "뷔", "콜라");
// 회원 "user1" 객체를 영속화
Users savedUser = userRepository.save(user);
// 회원의 nickname 변경
savedUser.setNickname("얼굴천재");
// 회원의 favoriteFood 변경
savedUser.setFavoriteFood("버거킹");
// 회원 "user1" 을 조회
Users foundUser = userRepository.findById("user1").orElse(null);
// 중요!) foundUser 는 DB 값이 아닌 1차 캐시에서 가져오는 값
assert(foundUser == savedUser);
assert(foundUser.getUsername().equals(savedUser.getUsername()));
assert(foundUser.getNickname().equals(savedUser.getNickname()));
assert(foundUser.getFavoriteFood().equals(savedUser.getFavoriteFood()));
return foundUser;
}
@Transactional
public Users updateUser2() {
// 테스트 회원 "user1" 생성
// 회원 "user1" 객체 추가
Users user = new Users("user1", "진", "꽃등심");
// 회원 "user1" 객체를 영속화
Users savedUser = userRepository.save(user);
// 회원의 nickname 변경
savedUser.setNickname("월드와이드핸섬 진");
// 회원의 favoriteFood 변경
savedUser.setFavoriteFood("까르보나라");
return savedUser;
}
DB에도 연관관계(association)을 설정하듯, JPA에도 연관관계를 설정할 수 있다.
JPA 의 경우는 Enitity 클래스의 필드 위에 연관관계 어노테이션 (@) 을 설정해 주는 것만으로 연관관계가 형성된다.
일대다(@OneToMany) / 다대일(ManyToOne) / 일대일(OneToOne) / 다대다(ManyToMany)
@Enitity
public class Order {
@OneToMany
private List<Food> foods;
@OneToOne
private Coupon coupon;
}
@Entity
public class Owner {
@ManyToOne
Restaurant restaurant;
}
@Entity
public class User {
@ManyToMany
List<Restaurant> likeRestaurants;
}
// 1. 상품 생성
Product product = new Product(...);
productRepository.save(product);
// 2. 상품 전체 조회
List<Product> products = productRepository.findAll();
// 3. 상품 전체 개수 조회
long count = productRepository.count();
// 4. 상품 삭제
productRepository.delete(product);
@Transactional
@Override
public <S extends T> S save(S entity) {
Assert.notNull(entity, "Entity must not be null.");
if (entityInformation.isNew(entity)) {
em.persist(entity); // entityManager(영속성 컨텍스트 매니저)
return entity;
} else {
return em.merge(entity);
}
}
QueryMethod
라고 한다.public interface ProductRepository extends JpaRepository<Product, Long> {
// (1) 회원 ID 로 등록된 상품들 조회
List<Product> findAllByUserId(Long userId);
// (2) 상품명이 title 인 관심상품 1개 조회
Product findByTitle(String title);
// (3) 상품명에 word 가 포함된 모든 상품들 조회
List<Product> findAllByTitleContaining(String word);
// (4) 최저가가 fromPrice ~ toPrice 인 모든 상품들을 조회
List<Product> findAllByLpriceBetween(int fromPrice, int toPrice);
}