본문 바로가기
Back-End/Spring

6.스프링 DB접근기술

by 두두리안 2020. 12. 29.
728x90

6.스프링DB접근기술

목차

  • 2.스프링 통합테스트
  • 3.스프링 JdbcTemplate
  • 4.JPA
  • 5.스프링 데이터 JPA

2.스프링 통합테스트

MemberServiceIntegrationTest 테스트추가!

@SpringBootTest
@Transactional
class MemberServiceIntegrationTest {

    @Autowired MemberService memberService;
    @Autowired MemberRepository memberRepository;

    //...
}
  • 기존 MembeerServiceTest 에서 @SpringBootTest @Transactional를 추가한다
  • @Transactional을 추가하면 트랜잭션 롤백을한다
  • DB트랜잭션 롤백을 하면 앞에 실행된 것을 전부다 취소한다

MemberServiceTest

class MemberServiceTest {

    MemberService memberService;
    MemoryMemberRepository memoryMemberRepository;

    @BeforeEach
    public void beforeEach(){
        //같은 MemoryMemberRepository 를 사용한다 이럴경우 같은 DB를 공유한다
        memoryMemberRepository = new MemoryMemberRepository();
        memberService=new MemberService(memoryMemberRepository);
    }

    @AfterEach
    public void afterEach(){
        memoryMemberRepository.clearStore();  // DB값 초기화

    }

        //...
}
  • @Transactional 을 이용해서 @BeforeEach @AfterEach 을 안사용해도 된다
  • 테스트를 반복해서 사용할수 있다

정리

  • @SpringBootTest을 사용하면 스프링 컨테이너와 테스트를 함께 실행한다.
  • @Transactional 테스트 케이스에 이 에노테이션이 있으면 테스트 시작전에 트랜잭션을 시작하고 테스트 완료후에 항상 롤백한다
    • DB에 데이터가 남아있지 않아서 다음테스트에 영향을 안준다

3.스프링 JdbcTemplate

JdbcTemplateMemberRepository

public class JdbcTemplateMemberRepository implements MemberRepository {

    private final JdbcTemplate jdbcTemplate;
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    @Override
    public Member save(Member member) {
        SimpleJdbcInsert jdbcInsert = new SimpleJdbcInsert(jdbcTemplate);
        jdbcInsert.withTableName("member").usingGeneratedKeyColumns("id");

        Map<String, Object> parameters = new HashMap<>();
        parameters.put("name", member.getName());

        Number key = jdbcInsert.executeAndReturnKey(new MapSqlParameterSource(parameters));
        member.setId(key.longValue());
        return member;
    }
    @Override
    public Optional<Member> findById(Long id) {
        List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
        return result.stream().findAny();
    }
    @Override
    public List<Member> findAll() {
        return jdbcTemplate.query("select * from member", memberRowMapper());
    }
    @Override
    public Optional<Member> findByName(String name) {
        List<Member> result = jdbcTemplate.query("select * from member where name = ?", memberRowMapper(), name);
        return result.stream().findAny();
    }
    private RowMapper<Member> memberRowMapper() {
        return (rs, rowNum) -> {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return member;
        };
    }
}

SpringConfig

@Configuration
public class SpringConfig {

    ...

    @Bean
    public MemberRepository memberRepository(){
        //return new MemoryMemberRepository();
        //return new JdbcMemberRepository(dataSource);
        return new JdbcTemplateMemberRepository(dataSource);
    }

}
  • new JdbcTemplateMemberRepository(dataSource) 바꾸어준다음 테스트 실행해본다!
  • 테스트의 장점 직접스프링빈등록의 장점

4.JPA

  • JPA는 기본 반복코드는 물론이고, 기본적인 SQL도 JPA가 직접 만들어서 실행해준다
  • SQL과 데이터 중심의 설계에서 객체중심의 설계로 패러다임을 전환
  • 개발의 생산성을 높인다

Member

@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;
    }
}
  • @Entity 이클래스를 테이블과 매핑한다
  • @Id 기본키설정
  • @GeneratedValue(strategy = GenerationType.IDENTITY) DB가 알아서 생성
  • @Column(name = "username") 컬러명을 username으로 바꾸어준다

JpaMemberRepository

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); //DB를 생성하고 저장한다
        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) {
        List<Member> result = em.createQuery("select m from Member m where m.name = :name", Member.class)
                .setParameter("name", name)
                .getResultList();
        return result.stream().findAny();
    }

    @Override
    public List<Member> findAll() {
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }
}
  • 생성 persist
  • 조회 find
  • 단건조회 em.createQuery("select m from Member m where m.name = :name", Member.class)
  • 모두조회 em.createQuery("select m from Member m", Member.class)

SpringConfig

@Configuration
public class SpringConfig {

    EntityManager em;

    @Autowired
    public SpringConfig(EntityManager em) {
        this.em = em;
    }


    @Bean
    public MemberRepository memberRepository(){
        //return new MemoryMemberRepository();
        //return new JdbcMemberRepository(dataSource);
        //return new JdbcTemplateMemberRepository(dataSource);
        return new JpaMemberRepository(em);
    }

}
  • JpaMemberRepository 바꾸어주고 테스트 실행!

5.스프링데이터JPA

  • 개발생산성증가
  • 리포지토리에 구현클래스 없이 인터페이스만으로 개발

SpringDataJpaMemberRepository 인터페이스

public interface SpringDataJpaMemberRepository extends JpaRepository<Member,Long> ,MemberRepository{

    @Override
    Optional<Member> findByName(String name);
}
  • JpaRepository<클래스,ID타입>

SpringConfig

@Configuration
public class SpringConfig {

    private final MemberRepository memberRepository;

    @Autowired
    public SpringConfig(MemberRepository memberRepository) {
        this.memberRepository = memberRepository;
    }

    @Bean
    public MemberService memberService(){
        return new MemberService(memberRepository);
    }

}

image

  • 인터페이스가 기본적인 CRUD를 제공한다
  • 페이징 기능제공
  • findByName() , findByEmail() 처럼 메서드 이름 만으로 조회 기능 제공
  • findByName -> select m from Member m where m.name =?
  • 복잡한 동적쿼리는 Querydsl 라이브러리 사용
  • 이조합으로 해결하기 어려운 쿼리는 JdbcTemplate,네이티브쿼리 사용

참고자료

https://www.inflearn.com/course/%EC%8A%A4%ED%94%84%EB%A7%81-%EC%9E%85%EB%AC%B8-%EC%8A%A4%ED%94%84%EB%A7%81%EB%B6%80%ED%8A%B8/dashboard

728x90

'Back-End > Spring' 카테고리의 다른 글

1.객체지향설계와 스프링  (0) 2020.12.30
7.AOP  (0) 2020.12.29
5.순수 JDBC 접근기술  (0) 2020.12.28
4.회원 관리 예제 - 웹 MVC개발  (0) 2020.12.28
3.스프링빈과 의존관계  (0) 2020.12.28