Enum은 열거형이라는 뜻을 가지고 있다 Enum이라는 타입을 사용할 시 Enum에서 설정한 데이터만 사용할 수 있다 예를 들면 '요일' "월, 화, 수, 목, 금, 토, 일"이 있다 해당 요일 외에 데이터는 받지 않기 때문에 컴파일 에러로 사전에 버그를 잡아낼 수 있다
@Transactional
@Rollback(value = false)
class MemberRepositoryTest {
...
}
@Transactional에서 장애 발생시 롤백 시키는 걸 할지 말지에 대한 것이다. 일반적으로 사용하지 않으며 테스트 코드 작성해서 디비 데이터 값을 확인해야한다면 사용한다 (테스트 코드 작동한 후 종료된 뒤에 바로 롤백 시켜서 디비에서 확인하기가 어려움)
📝@PostConstruct
// 초기 데이터 INSERT
@PostConstruct
public void insertData() throws Exception {
IntStream.range(0, 100).forEach((i) -> {
Member member = new Member("username" + i);
memberRepository.save(member);
});
}
종속성 주입이 완료된 후 실행되어야 하는 메서드에 사용한다 여기에서는 정상으로 스프링부트가 기동 된다면 해당 메소드가 동작해 초기 데이터를 INSERT하는 작업이다.
@Entity
@NamedQuery(
name="Member.findByUsername", // Key
query="select m from Member m where m.username = :username" // Value
)
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
}
public interface MemberRepository extends JpaRepository<Member, Long> {
/** ----- 방법1 (@Query) ----- **/
@Query(name ="Member.findByUsername")
List<Member> findByUsername(@Param("username") String username);
/** ----- 기본 예제 ----- **/
@Query("select m from Member m where m.username = :username and m.age = :age")
List<Member> findUser(@Param("username") String username, @Param("age") int age);
}
조건절 조회하는 임의의 쿼리가 필요할 때 Entity에 @NamedQuery를 이용해 JpaRepository에서 {키:값} 형태로 찾아 사용이 가능하다
이 방법보단 JpaRepository에서 바로 @Query를 이용해 바로 작성하는 걸 더 많이 사용한다
📝@Modifying
public interface MemberRepository extends JpaRepository<Member, Long> {
@Modifying(clearAutomatically = true)
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
}
Update한 후에 Update 항목을 조회하는 경우가 있을 때영속성 컨텍스트 캐시를 날리고 데이터 조회하기 때문에 디비에서 조회하게 되고 데이터의 정합성을 맞춘다
📝@EntityGraph
public interface MemberRepository extends JpaRepository<Member, Long> {
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
// 위에 코드는 EntityGraph + Query로 아래와 같은 코드이다. (team Fetch Join)
// @Query("select m from Member m left join fetch m.team")
List<Member> findMemberEntityGraph();
}
패치조인을 더 쉽게할 수 있도록 스프링 데이터 JPA에서 제공해준다.
📝엔터티 라이프 사이클 컨트롤 어노테이션
@PrePersist : 새로운 엔티티에 대해 persist가 호출되기 전
@PreUpdate : 엔티티 업데이트 작업 전
@PreRemove : 엔티티가 제거되기 전
@PostPersist : 새로운 엔티티에 대해 persist가 호출된 후
@PostUpdate : 엔티티가 업데이트된 후
@PostRemove : 엔티티가 삭제된 후
@PostLoad : Select조회가 일어난 직후에 실행
@Inheritance(strategy = InheritanceType.JOINED) // 조인 전략
@DiscriminatorColumn
@Entity
public class Item {
@Id
@GeneratedValue
private long id;
private String name;
private int price;
}
@Entity
// @DiscriminatorValue("this is movie")
public class Movie extends Item{
private String director;
private String actor;
}
public class Main {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try{
Movie movie = new Movie();
movie.setName("바람과 함께 사라지다");
movie.setPrice(10000);
movie.setActor("이민호");
movie.setDirector("봉준호");
em.persist(movie);
tx.commit();
}catch (Exception e){
e.printStackTrace();
}finally{
emf.close();
em.close();
}
}
}
@Inheritance
관계형 데이터베이스에 상속관계라는 걸 JPA에서 표현했다
@DiscriminatorColumn
해당 어노테이션을 사용 안 하면 DTYPE이 따로 안 보이는데 이걸 명시적으로 표현해주는 어노테이션 어느 자식이 UPSERT 되어서 그런지 잘 모르니 해당 어노테이션을 사용하는게 좋다
@DiscriminatorValue
해당 어노테이션을 사용하면 DTYPE에 들어갈 걸 명시적으로 지정할 수 있다.
📝@MappedSuperclass
@MappedSuperclass
public abstract class BaseEntity {
@Column(name = "create_date") // 부모 클래스에서 컨트롤 가능
private LocalDateTime localDateTime;
private LocalDateTime modi_date;
}
@Entity
public class Book extends BaseEntity{
@Id
@GeneratedValue
private long id;
private String name;
private String author;
private String ISBN;
}
Inheritance와 차이가 있는 점은 Inheritance은 부모 자식 테이블 따로따로 들어가게 되는데 MappedSuperclass의 경우 필드만 공유하고 하나의 테이블로 만들어진다.
📝@NamedQuery, @Query
@Entity
@NamedQuery(
name="Member.findByUsername", // Key
query="select m from Member m where m.username = :username" // Value
)
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String username;
private int age;
}
public interface MemberRepository extends JpaRepository<Member, Long> {
/** ----- 방법1 (@Query) ----- **/
@Query(name ="Member.findByUsername")
List<Member> findByUsername(@Param("username") String username);
/** ----- 기본 예제 ----- **/
@Query("select m from Member m where m.username = :username and m.age = :age")
List<Member> findUser(@Param("username") String username, @Param("age") int age);
}
조건절 조회하는 임의의 쿼리가 필요할 때 Entity에 @NamedQuery를 이용해 JpaRepository에서 {키:값} 형태로 찾아 사용이 가능하다
이 방법보단 JpaRepository에서 바로 @Query를 이용해 바로 작성하는 걸 더 많이 사용한다
📝@Modifying
public interface MemberRepository extends JpaRepository<Member, Long> {
@Modifying(clearAutomatically = true)
@Query("update Member m set m.age = m.age + 1 where m.age >= :age")
int bulkAgePlus(@Param("age") int age);
}
Update한 후에 Update 항목을 조회하는 경우가 있을 때 영속성 컨텍스트 캐시를 날리고 데이터 조회하기 때문에 디비에서 조회하게 되고 데이터의 정합성을 맞춘다
📝@EntityGraph
public interface MemberRepository extends JpaRepository<Member, Long> {
@EntityGraph(attributePaths = {"team"})
@Query("select m from Member m")
// 위에 코드는 EntityGraph + Query로 아래와 같은 코드이다. (team Fetch Join)
// @Query("select m from Member m left join fetch m.team")
List<Member> findMemberEntityGraph();
}
@PrePersist : 새로운 엔티티에 대해 persist가 호출되기 전
@PreUpdate : 엔티티 업데이트 작업 전
@PreRemove : 엔티티가 제거되기 전
@PostPersist : 새로운 엔티티에 대해 persist가 호출된 후
@PostUpdate : 엔티티가 업데이트된 후
@PostRemove : 엔티티가 삭제된 후
@PostLoad : Select조회가 일어난 직후에 실행