DB와 연동하기

강한친구·2022년 3월 29일
0

Spring 입문

목록 보기
9/10

H2 DB 만들고 table만드는건 별로 안어려우니 생략하겠다.

그럼 이제 이 만들어둔 db가 memoryMemberRepositroy를 대체해야한다.

그러기 위해서는 총 3가지 정도의 방법이 있다 .

Original JDBC

전통적인 JDBC를 이용해서 연결하는 방법이다.
작년에 이걸로 DB 수업 프로젝트를 한적이 있었는데 그 때는 스프링도 뭐도 쓸줄 아는게 없어서 그냥 이걸로 했던 기억이 있다.

@Override
    public Member save(Member member) {
        String sql = "insert into member(name) values(?)";
        Connection conn = null;
        PreparedStatement pstmt = null;
        ResultSet rs = null;
        try {
            conn = getConnection();
            pstmt = conn.prepareStatement(sql,
                    Statement.RETURN_GENERATED_KEYS);
            pstmt.setString(1, member.getName());
            pstmt.executeUpdate();
            rs = pstmt.getGeneratedKeys();
            if (rs.next()) {
                member.setId(rs.getLong(1));
            } else {
                throw new SQLException("id 조회 실패");
            }
            return member;
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
    }

이 방식의 가장 큰 문제는 일단 굉장히 불편하다는 점이다. 직접 conn으로 열고, pstmt로 sql 준비해서 보내고 이것저것 해야하는 불편함이 있다. 이거보다 더 편한 방법이 3개나 있으니깐 굳이 이걸 쓸 필요는 없지만, jdbc의 작동원리를 파악하기에는 좋은 방법이라 생각한다.

JDBC Template

위의 JDBC 방식을 최대한 간략화 시킨것이 JDBC Template이다. 기존의 rs, pstmt등을 전부 template화 하여 최소화 시킨것이다.

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

보이는것처럼 좀 간단해졌다.

적용

DI를 학습할 때 컨테이너에 빈을 올리는 방법이 두가지 있다고 했는데 변경될 사항이 있는 경우 Annotation이 아니라 Config로 직접 올려주는 방식이 있다는걸 학습했었다.

package com.example.hellospring;

import com.example.hellospring.repository.JdbcMemberRepository;
import com.example.hellospring.repository.JdbcTemplateMemberRepository;
import com.example.hellospring.repository.MemberRepository;
import com.example.hellospring.service.MemberService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.sql.DataSource;

@Configuration
public class SpringConfig {

    private DataSource dataSource;

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

이렇게 MemberRepository에서 return 부분이 우리가 연결하는 db였다. 처음에는 단순 Memory, 두번째부터는 JDBC 방식 그리고 마지막으로는 JDBC Template를 사용하였다.

JPA

Java Persistence API이다.
구체적인 설명은 나중에 따로 하겠다.

우선 JPA를 쓰려면 build.gradle에서 jpa를 implement해야한다.

환경설정

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'
	}
}

jdbc는 안쓴니깐 일단 지우도록 하겠다.
그리고 application.properties에 몇가지 사항을 추가해야한다.

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

show-sql은 sql문을 보여주는 명령어이다. 가려도 상관없지만 작동여부를 보기위해서 선택했다.

ddl-auto는 테이블을 자동생성하는 기능을 제공한다. 일단은 꺼두겠지만, create를 사용하면 생성할 수도 있다.

Entity mapping

package com.example.hellospring.repository;

import com.example.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;
    }

    @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 List<Member> findAll() {
        return em.createQuery("select m from Member m", Member.class)
                .getResultList();
    }
    @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();
    }
}

JpaMemberRepository를 통해 MemberRepository interface를 구현해준다.

새부적인 내용은 강의를 참고하자

컨테이너에 올리기

@Configuration
public class SpringConfig { private final DataSource dataSource;
 private final EntityManager em;
 public SpringConfig(DataSource dataSource, EntityManager em) {
 this.dataSource = dataSource;
 this.em = em;
 }
 @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);
 }
}

이렇게 작성이 끝났음면 컨테이너에 ㅇ올려줘야한다.
Entity Manager를 통해 작동하니깐 constructor를 통해 Entity Manager를 받고 이를 올려주면 된다.

JPA 심화

JPA는 스프링만큼이나 방대하지만, 최근 많은 회사들이 사용하는 기술이라고 한다. 나중에 따로 학습을 해야할 것 같다.

이 밖에도 JPA Data 라고 인터페이스만 가지고 구현할 수 있는 방식도 있다.

이는 나중에 학습할 때 정리하겠다.

0개의 댓글

관련 채용 정보