JPA는 기존 반복 코드는 물론이고, 기본적 SQL도 JPQ가 직접 만들어서 실행
JPA를 사요하면 SQL과 데이터 중심의 설계에서 객체 중심의 설계로 가능
build.gradle 설정
dependencies {
implementation 'org.springframework.boot:spring-boot-starter-thymeleaf'
implementation 'org.springframework.boot:spring-boot-starter-web'
//implementation 'org.springframework.boot:spring-boot-starter-jdbc'
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
runtimeOnly 'com.h2database:h2'
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
}
스프링 부트에 JPA 설정 추가
spring.datasource.url=jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.jpa.show-sql=true
spring.jpa.hibernate.ddl-auto=none
JPA 엔티티 매핑
package hello.hellospring.domain;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
@Entity
public class Member {
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String password;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
public class JpaMemberRepository implements MemberRepository {
private final EntityManager em; //JPA 구동 원리
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
@Override
public Member save(Member member) {
em.persist(member);
return member; //JPA가 자동으로 쿼리 짠다.
}
@Override
public Optional<Member> findById(Long id) {
Member member = em.find(Member.class, id); //select문
return Optional.ofNullable(member);
}
@Override
public Optional<Member> findByName(String name) {
List<Member> rst = em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name).getResultList();
return rst.stream().findAny(); //findByName으로 하나만 찾아온다
}
@Override
public List<Member> findALl() {
return em.createQuery("select m from Member", Member.class) //이미 Mapping 되어 있다.
.getResultList();
}
}
@Service
@Transactional //data를 저장 변경
public class MemberService {
//DI
@Autowired
private final MemberRepository memberRepository;
public MemberService(MemberRepository memberRepository) {
this.memberRepository = memberRepository;
}
public Long join(Member member){
validateDuplicateMember(member);
return member.getId();
}
private void validateDuplicateMember(Member member){
memberRepository.findByName(member.getName())
.ifPresent(m -> {
throw new IllegalStateException("이미 존재 하는 회원");
});
}
public List<Member> findMembers(){
return memberRepository.findALl();
}
public Optional<Member> findOne(Long id){
return memberRepository.findById(id);
}
}
JPA를 통한 모든 데이터 변경은 Transaction 안에서 실행
@Configuration
public class SpringConfig {
//spring Jpa가 interface에 대한 구현체를 찾도록 만든다0
private final MemberRepository memberRepository;
public SpringConfig(MemberRepository memberRepository) {
this.memberRepository = memberRepository; //jpa 구현체 만들어 놓은거 등록
}
@Bean
public MemberService memberService(){
return new MemberService(memberRepository); //memberService에 의존관계 setting
}
/*
interface를 보고 springBean 자동 등록
-> proxt라는 기술로 객체를 생성 -> springBean 생성 -> inject
*/
}
스프링 데이터 JPA
스프링 부트와 JPA만 사용해도 개발 생산성 증가, 개발 코드 감소
여기에 스프링 데이터 JPA 사용시, 리포지토리에 구현 클래스 X, 인터페이스만 갖고 개발 완료. CRUD 기능도 스프링 데이터 JPA가 모두 제공
package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import org.springframework.data.jpa.repository.JpaRepository;
import java.util.Optional;
//spring data Jpa가 spring Bean을 자동으로 등록
public interface SpringDataJapMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
@Override
Optional<Member> findByName(String name);
}

스프링 데이터 JPA 제공 기능
1. 인터페이스를 통한 기본적인 CRUD
2. 페이징 기능 자동 제공