[Spring] 스프링 DB 접근 기술

    1. H2 데이터베이스

     

    0) 실행

    //h2 폴더로 이동
    $cd Desktop
    $cd study
    $cd h2
    $cd bin
    
    //모든 파일, 폴더를 시간 역순으로 출력
    $ls -arlth
    
    //Mac OS의 경우 권한을 부여
    $chmod 755 h2.sh
    
    //실행
    $./h2.sh

     

    결과 )

     

     

    1) 데이터 파일을 만들어주기

     

    • jdbc:h2:~/test (최초 한번)
    • ~/test.mv.db 파일 생성 확인
    • jdbc:h2:tcp://localhost/~/test 이렇게 접속 

     

    2) MEMBER 테이블 생성

     

     

    3) SELECT * FROM MEMBER;

     

     

    4) insert into member name values('spring');

     

     

     

    2. 순수 JDBC

     

    1) build.gradle 파일에 jdbc, h2 데이터베이스 관련 라이브러리 추가

    implementation 'org.springframework.boot:spring-boot-starter-jdbc'
    runtimeOnly 'com.h2database:h2'

     

    2) 스프링 부트 데이터베이스 연결 설정 추가

    spring.datasource.url=jdbc:h2:tcp://localhost/~/test
    spring.datasource.dirver-class-name=org.h2.Driver

     

    3) 코드

     

    코드가 매~우 길기 때문에 내가 중요하다 생각한 것만 올릴 것임!

    //DB를 연동해서 멤버 저장
    public class JdbcMemberRepository implements MemberRepository {
    
        // DB에 붙으려면 데이터 소스가 필요
        private final DataSource dataSource;
    
        // 스프링부트가 데이터 소스를 만듦 -> 주입 받음
        public JdbcMemberRepository(DataSource dataSource) {
            this.dataSource = dataSource;
        }
    
        @Override
        public Member save(Member member) {
            /* ... */
        }
    
        @Override
        public Optional<Member> findById(Long id) {
            /* ... */
        }
    
        @Override
        public List<Member> findAll() {
            /* ... */
        }
    
        private Connection getConnection() {
            return DataSourceUtils.getConnection(dataSource); 
            //DataSourceUtils를 통해서 커넥션을 획득하자!
        }
    
        private void close(Connection conn, PreparedStatement pstmt, ResultSet rs)
        {
            /* ... */
        }
    
        private void close(Connection conn) throws SQLException {
            DataSourceUtils.releaseConnection(conn, dataSource); //닫을 때도 DataSource를 통해서 릴리즈 해주자!
        }
    }

     

     

    <정리>

     

    • MemberRepository를 상속받아서 JdbcMemberRepository 구현 (인터페이스 개념을 알고 있다면 쉬운 내용!)
    • 스프링의 DI (Dependencies Injection)을 사용하면 기존 코드를 전혀 손대지 않고, 설정만으로 구현 클래스를 변경할 수 있음
    • DataSource는 데이터베이스 커넥션을 획득할 때 사용하는 객체
    • 스프링 부트는 데이터베이스 커넥션 정보를 바탕으로 DataSource를 생성하고 스프링 빈으로 만들어둠 -> 그래서 DI를 받을 수 있음

     

     

    3. 스프링 통합 테스트 

     

    → DB까지도 테스트 해보자! (통합 테스트도 필요하긴 하나, 진짜 좋은 테스트는 단위 테스트를 만드는 것이다! )

     

    @SpringBootTest

     

    : 스프링 컨테이너와 테스트를 함께 실행

     

    @Transactional 

     

    : 테스트 케이스에 이 애노테이션이 있으면, 테스트 시작 전에 트랜잭션을 시작하고, 테스트 완료 후에 항상 롤백한다. 이렇게 하면 DB에 데이터가 남지 않으므로 다음 테스트에 영향을 주지 않는다.

     

     

    4. 스프링 JdbcTemplate

     

     

     

     

    5. JPA

     

    JPA가 SQL 쿼리를 자동으로 처리해주며, SQL과 데이터 중심의 설계에서 객체지향 중심 설계로 전환 가능

     

    public class JpaMemberRepository implements MemberRepository {
    
        private final EntityManager em; //JPA를 쓰려면 entitymanagerfmㄹ 주입 받아야 함
    
        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 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) //m(멤버 엔티티) 자체를 조회
                    .getResultList(); //객체를 대상으로 쿼리를 날리면 Sql로 번역됨
        }
    }

     

     

    6. 스프링 데이터 JPA

     

    public interface SpringDataJpaMemberRepository extends JpaRepository<Member, Long>, MemberRepository {
        @Override
        Optional<Member> findByName(String name);
    }

     

    댓글