JDBC에서 JDBC Template 변경해보면 코드가 확 간결해졌지만,
SQL은 사용자가 작성해야한다.
라이브러리를 추가해보자.
build.gradle 파일에서
implementation 'org.springframework.boot:spring-boot-starter-jdbc'를 주석처리하고
implementation 'org.springframework.boot:spring-boot-starter-data-jpa'를 추가해준다. 내부에 jdbc 관련 라이브러리를 포함한다. 따라서 jdbc는 제거해도
된다.
resources/application.properties에도 설정을 추가해줘야 한다.
spring.jpa.show-sql=true 는 jpa가 날리는 sql 확인이 가능해진다.
spring.jpa.hibernate.ddl-auto=none jpa를 사용하면 객체를보고 테이블을 생성하는데 우리는 만들어진것을 확인할거기에 끄고 시작한다. none이 아닌 create로 하면 테이블도 자동생성된다.
spring.datasource.url = jdbc:h2:tcp://localhost/~/test
spring.datasource.driver-class-name=org.h2.Driver
spring.datasource.username=sa
spring.jap.show-sql=true
spring.jpa.hibernate.ddl-auto=none
JPA 엔티티 매핑을 해주자.
domain/member 클래스에서
@Entity라는 어노테이션을 붙여 JPA가 관리하는 엔티티로 만든다.
@Id를 통해 PK도 매핑해줘야 한다.
@GeneratedValue(strategy = GenerationType.IDENTITY) 코드를 통해 자동 증가 해주는 값임을 명시한다.
name도 만약 DB에 컬럼명이 username 이라면 아래 주석과 같은 코드로 매핑해준다.
package hello.hellospring.domain;
import javax.persistence.*;
@Entity
public class Member { // 비즈니스 도메인 객체, 데이터베이스에 저장하고 관리됨.
@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
//@Column(name = "username")
private String name;
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;
}
}
이제 JpaMemberRepository를 생성하고 아래와 같이 코드를 작성하자.
build.gradle에서 라이브러리를 받으면 스프링부트가 자동으로 엔티티메니저를 생성해준다. 만들어진것을 인젝션 받으면된다.
private final EntityManager em;
public JpaMemberRepository(EntityManager em) {
this.em = em;
}
save 구현
jpa가 insert 쿼리 만들어서 집어놓고 setId까지 다 해준다.
@Override
public Member save(Member member) {
em.persist(member);
return member;
}
findById 구현
조회할 타입과 식별자 넣어주면 select문 생성
@Override
public Optional<Member> findById(Long id) {
Member member = em.find(Member.class, id);
return Optional.ofNullable(member);
}
findAll 구현
엔티티를 대상으로 쿼리를 날림.
@Override
public List<Member> findAll() {
return em.createQuery("select m from Member m", Member.class)
.getResultList();
}
findByName 구현
@Override
public Optional<Member> findByName(String name) {
List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
.setParameter("name", name)
.getResultList();
return result.stream().findAny();
}
JPA를 사용할시 주의할 점은 항상 트랜잭션이 있어여한다.
따라서 MemberService에 @Transactional생성한다.
스프링은 해당 클래스의 메서드를 실행할 때 트랜잭션을 시작하고, 메서드가 정상 종료되면 트랜잭션을 커밋한다. 만약 런타임 예외가 발생하면 롤백한다.
JPA를 통한 모든 데이터 변경은 트랜잭션 안에서 실행해야한다.
@Transactional
public class MemberService { // 핵심 비즈니스 로직 구현 (비즈니스에 가까운 용어들을 사용하는것이 일반적 repository와 반대)
}
SpringConfig 파일 수정해준다.
JpaMemberRepository를 return 해준다.
엔티티매니저가 필요하다. 따라서 아래코드로 di 해준다.
package hello.hellospring;
import hello.hellospring.repository.*;
import hello.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.persistence.EntityManager;
import javax.sql.DataSource;
import javax.swing.text.html.parser.Entity;
@Configuration
public class SpringConfig {
private EntityManager em;
@Autowired
public SpringConfig(EntityManager em) {
this.em = em;
}
// @Autowired
// public SpringConfig(DataSource dataSource) {
// this.dataSource = dataSource;
// }
@Bean
public MemberService memberService() {
return new MemberService(memberRepository());
}
@Bean
public MemberRepository memberRepository() {
//return new MemoryMemberRepository();
//return new JdbcMemberRepository(dataSource);
//return new JdbcTemplateMemberRepository(dataSource);
return new JpaMemberRepository(em);
}
}
이제 통합테스트를 통해 돌려보면 성공하는것을 알 수 있다.
값이 제대로 들어가는지 확인하고싶다면, 회원가입 위에 @Commit 어노테이션을 붙여주면 DB에 값이 잘들어가는지 확인 가능하다.