JPA(Java Persistence API)는 객체와 관계형 데이터베이스를 매핑할 때 사용하는 ORM(Object-Relational Mapping)프레임워크이다.
JDBC는 자바에서 데이터베이스에 접근하기 위한 API로, 개발자가 SQL쿼리를 직접 작성하여 데이터베이스와 통신한다.
JDBC는 개발자가 SQL을 직접 작성하여 데이터베이스와 통신하기 때문에, 데이터베이스 연동 작업을 상세하게 제어할 수 있지만, JDBC를 사용하면 개발자가 매번 SQL을 작성해야 하며, 이로 인해 반복적인 작업이 많아지고 오류 발생 가능성이 높아지기도 한다.
반면, JPA는 엔티티 클래스를 사용하여 데이터베이스의 테이블과 객체간의 매핑을 자동으로 처리한다. 이를 통해 개발자는 객체 지향 프로그래밍 방식으로 데이터베이스와 통신할 수 있어 SQL을 직접 작성하지 않아도 된다. 이러한 이유로 개발 생산성이 향상되기도 한다. (하지만, JPA는 ORM 프레임워크이기 때문에 JDBC에 비해 성능이 떨어질 수 있고 복잡한 데이터베이스 연동 작업을 처리하는 경우에는 JDBC가 적합할 수 있다.)
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
build.gradle파일에 JPA 관련 라이브러리를 추가한다.
(spring-boot-starter-data-jpa 내부에는 jdbc관련 라이브러리가 포함되어있다)
spring.datasource.username=sa
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
properties 파일에 위와같은 설정을 추가해준다.
show-sql은 JPA가 생성하는 sql을 출력하도록 하는것.
(ddl-auto는 JPA가 테이블을 자동으로 생성하는 기능인데, 이미 있어서 만들지 않아도 돼서 none으로 함..)
package hello.hellospring.domain;
import jakarta.persistence.*;
@Entity //jpa가 관리하는 엔티티가 됨
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
public Long getId() {
return id;
}
public String getName() {
return name;
}
public void setId(Long id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
Member클래스를 jpa가 관리하는 엔티티로 등록하기 위해
@Entity 어노테이션을 부착,
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import jakarta.persistence.EntityManager;
import jakarta.persistence.TypedQuery;
import java.util.List;
import java.util.Optional;
public class JpaMemberRepository implements MemberRepository{
private final EntityManager em;
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
@Override
public Member save(Member member) {
em.persist(member);//저장
return member;
}
@Override
public Optional<Member> findById(Long id) {
Member member = em.find(Member.class,id);//조회할 타입과 식별자
return Optional.ofNullable(member);
}
@Override
public Optional<Member> findByName(String name) {
return em.createQuery("select m from Member m where m.name=:name",Member.class)
.setParameter("name",name).getResultList().stream().findAny();
}
@Override
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class).getResultList();
}
}
그릐고 JpaRepository를 만든다.
이 리파지토리는 EntitiyManager가 필요하다. 생성자 DI를 사용.
DB에 저장,조회등은 entityManager을 이용하면 된다.
각각의 메소드들은 위 코드를 참고..
(추가: JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야 하기 때문에, MemberService에 @Transactional 어노테이션을 추가)
EntityManager em;
@Autowired
SpringConfig(EntityManager em){
this.em=em;
}
@Bean
public MemberRepository memberRepository(){
return new JpaMemberRepository(em);
}
그리고 JpaMemberRepository를 빈에 등록해 사용하면 된다..
(em을 주입해야하니 em도 만들어주자.)
이런 JPA를 더 편리하게 사용하기 위한 기술로
Spring Data JPA가 있다.
public interface SpringDataJpaMemberRepository extends JpaRepository<Member,Long>,MemberRepository {
//findBy*** ==> select m from Member m where m.name=?
//메소드 이름만으로 기능 제공. findBy***And*** 등도 있음.
@Override
Optional<Member> findByName(String name);
}
JPA리파지토리 대신에 위와같이 SpringDataJpa리파지토리를 만들어 사용하면 된다.
(JpaRepository를 상속받고 MemberRepo도 상속받는다)
그런데, CRUD기능을 override 하는 코드들도 없는데 이게 맞나 싶다.
=> 스프링데이터 JPA가 JpaRespository 인터페이스를 제공한다.
이 인터페이스를 상속받는 인터페이스를 만들면 별도의 코드 작성 없이 데이터베이스의 CRUD 작업을 처리할 수 있다.
기본적인 CRUD 기능을 제공한다.
이외, 통용되지 않는 메소드들은 작성해주어야 한다.
findByName(Name)과 같이 메소드명을 규칙에 맞게 작성하면 된다..
private final MemberRepository memberRepository;
public SpringConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository; //Spring Framework가 구현체를 만들어 등록해줌
}
스프링 설정을 위와 같이 해주면...된다.
근데, SpringDataRepository 구현체가 없는데 어떻게 동작되었을까?..
JpaRepository를 상속받는 인터페이스를 만들어놓으면
Spring Framework에서 자동으로 구현체를 생성해 스프링 빈에 등록 해준다고 한다.
'웹개발 > SpringBoot' 카테고리의 다른 글
@RequestBody를 적어야 됐던 일 (1) | 2023.05.18 |
---|---|
[JPA] 엔티티 수정시 Dirty checking(변경 감지), Merge(병합) (0) | 2023.05.07 |
의존성 주입(DI), 스프링 빈과 의존관계 (0) | 2023.03.19 |
빌드하고 실행하기 (0) | 2023.03.18 |
ObjectMapper (0) | 2023.03.14 |
댓글