본문 바로가기
  • GDG on campus Ewha Tech Blog
3-2기 스터디/Spring 입문

[3주차] 스프링 DB 접근 기술

by 사과당근 2022. 5. 4.

섹션 6 : 스프링 DB 접근 기술

데이터베이스에 데이터를 저장하고 관리해보자

H2 데이터베이스 설치

개발이나 테스트 용도로 용량도 가볍고 편리한 DB이다. 교육용으로 많이 쓰인다.

h2.sh 파일을 실행하고 창이 뜰 때 localhost로 접속하면 웹 화면이 뜬다.

해당 화면을 통해 데이터베이스를 연결할 수 있다.

SQL문을 사용해 테이블 관리를 할 수 있다.

순수 JDBC

20년 전에 사용하던... 

기존에 메모리에 저장하던 방식을 없애고, JDBC 버전의 멤버 리포지토리를 이용하게 된 것이다.

개방-폐쇄 원칙(OCP, Open-Closed Principle)이라고 한다.

확장에는 열려있고 수정에는 닫혀있다는 뜻이다.

스프링의 DI (Dependencies Injection)을 사용하면 기존 코드를 전혀 손대지 않고, 설정만으로 구현 클래스를 변경할 수 있다.

서버를 껐다 켜도 데이터가 남아있다.

스프링 통합 테스트

순수 자바 코드로만 테스트할 수 없다.

그래서 테스트를 스프링과 엮어서 해보자.

실제 DB에 넣는 과정이다.

테스트는 반복해야하므로 테스트한 데이터를 지워줘야한다.

@Transactional

트랜젝션이라는 개념이 있어서 오토 커밋을 안시키고

테스트 시작 전에 트랜잭션을 시작하고, 테스트 완료 후에 항상 롤백한다.

db에 저장이 안된다.

@SpringBootTest

@Transactional

package hello.hellospring.service;
import hello.hellospring.domain.Member;
import hello.hellospring.repository.MemberRepository;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {
 @Autowired MemberService memberService;
 @Autowired MemberRepository memberRepository;
 @Test
 public void 회원가입() throws Exception {
 //Given
 Member member = new Member();
 member.setName("hello");
 //When
 Long saveId = memberService.join(member);
 //Then
 Member findMember = memberRepository.findById(saveId).get();
 assertEquals(member.getName(), findMember.getName());
 }
 @Test
 public void 중복_회원_예외() throws Exception {
 //Given
 Member member1 = new Member();
 member1.setName("spring");
 Member member2 = new Member();
 member2.setName("spring");
 //When
 memberService.join(member1);
 IllegalStateException e = assertThrows(IllegalStateException.class,
 () -> memberService.join(member2));//예외가 발생해야 한다.
 assertThat(e.getMessage()).isEqualTo("이미 존재하는 회원입니다.");
 }
}

스프링 JdbcTemplate

스프링 JdbcTemplate 라이브러리는 JDBC API에서 반복적인 코드를 제거해준다.

하지만 SQL은 직접 작성해야 한다

실무에서 많이 쓴다.

  • 생성자가 하나면 @Autowire 삭제해도 된다.

JdbcTemplate.query 를 이용하여 쿼리문을 날릴 수도 있다. 단 두줄로!

JPA에서는 이 쿼리조차 없앨 수 있다.

JPA

JPA를 사용하면 객체를 SQL 쿼리없이 바로 데이터베이스에 저장할 수 있다. 개발 생산성 up

JPA를 사용하면, SQL과 데이터 중심의 설계에서 객체 중심의 설계로 패러다임을 전환을 할 수 있다.

implementation 'org.springframework.boot:spring-boot-starter-data-jpa'

위는 JPA와 JDBC를 모두 포함하고 있는 라이브러리이다.

JPA는 객체와 ORM (객체와 Relational DB 의 테이블을 매핑) 기술을 사용한 것이다.

 

JPA 회원 리포지토리 (중요)

package hello.hellospring.repository;
import hello.hellospring.domain.Member;
import javax.persistence.EntityManager;
import java.util.List;
import java.util.Optional;

public class JpaMemberRepository implements MemberRepository {
	 private final EntityManager em;
	 public JpaMemberRepository(EntityManager em) {
		 this.em = em;
 }

 public Member save(Member member) {
	 em.persist(member);
	 return member;
 }

 public Optional<Member> findById(Long id) {
	 Member member = em.find(Member.class, id);
	 return Optional.ofNullable(member); 
 }

 public List<Member> findAll() {
	 return em.createQuery("select m from Member m", Member.class)
		 .getResultList();
 }

 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();
 }
}

select m from Member m 은 객체를 대상으로 쿼리를 날리게 되는 것이다.

id name 찾지않아도 알아서 매핑된다.

스프링 데이터 JPA

스프링 데이터 JPA는 JPA를 편리하게 사용하도록 도와주는 기술이다.

RDBMS를 사용한다면 스프링 데이터 JPA는 이젠 필수가 되었다..

스프링 데이터 JPA를 사용하면, 리포지토리에 구현 클래스 없이 인터페이스 만으로 개발을 가능하다.

댓글