본문 바로가기

컴퓨터/Spring Boot

[TIL] Spring Boot(intellij) - [DB-2] DB 연결과 JDBC

* 인프런 김영한 강사님의 스프링 입문 강의 정리

데이터 베이스를 설치했으므로 이제 스프링과 연결한다.

순수 jdbc와 jdbcTemplate을 사용하는 방법을 학습하였는데

jdbcTemplate을 중심으로 정리하려고 한다.

 

 

2. build.gradle에 라이브러리 추가

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

 

3. application.properties에 라이브러리 추가

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

 

build.gradle과 application.properties에 DB와 JDBC 사용을 위한 환경설정을 해주고 나면 

스프링과 DB연결이 된다.

이제 할 일은 JDBC 리포지토리를 구현하는 것이다.

처음 DB가 연결되지 않았을 때에는 memoryMemberRepository를 생성하여 메모리 저장소에 데이터를 저장하였다.

이제 DB가 연결되었으니 JDBC Repository를 사용하고 스프링 빈 설정을 변경해주어야 한다.

 

 

4. JDBC Repostory 생성

JdbcMemberRepository는 순수 JDBCJdbcTemplateMemberRepositoryJdbcTemplate을 이용한 구현체이다.

JdbcTemplate은 JDBC 코어 패키지의 중앙 클래스로 순수 JDBC보다 훨씬 간편하게 코드를 작성할 수 있도록 도와준다.

여기서는 JdbcTemplate을 사용한 코드를 기록하였다.

 

 

[JdbcTemplateMemberRepository]

package myStudyspring.myStudyspring.repository;

import myStudyspring.myStudyspring.domain.member;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.namedparam.MapSqlParameterSource;
import org.springframework.jdbc.core.simple.SimpleJdbcInsert;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;

public class JdbcTemplateMemberRepository implements memberRepository{

    private final JdbcTemplate jdbcTemplate;

    @Autowired  // 생략 가능
    public JdbcTemplateMemberRepository(DataSource dataSource) {
        this.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 Optional<member> findByName(String name) {
        List<member> result=  jdbcTemplate.query("select * from member where name=?", memberRowMapper(), name);
        return result.stream().findAny();
    }

    @Override
    public List<member> findAll() {
        return jdbcTemplate.query("select * from member", memberRowMapper());
    }

    //여기서  개체 생성 후 넘어감.
    private RowMapper<member> memberRowMapper(){
        return (rs, rowNum) -> {
            member member = new member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return member;
        };
    }
}

sql문은 jdbcTemplate.query()안에 직접 작성하고 

결과는 RowMapper로 받는다.

변수가 필요한 경우 바인딩해준다.

 

RowMapper?
- 원하는 형태의 결과값을 반환할 수 있다.
- jdbc에서 ResultSet 결과를 직접 꺼내 객체에 저장하던 방식을 자동화해준다.

 

 

Jdbc Repository를 생성한 후 SpringConfig에서 스프링 빈으로 등록해야 하는데

JdbcTemplates은 DataSource를 필요로 한다.

 

Datasource데이터베이스 커넥션을 획득할 때 사용하는 객체이며, 스프링 부트는 데이터베이스 커넥션 정보를 바탕으로 DataSource를 생성하고 스프링 빈으로 만들어준다.

 

따라서 다음과 같이 DataSource를 주입받는다.

 

[SpringConfig]

package myStudyspring.myStudyspring;

//import myStudyspring.myStudyspring.repository.JdbcMemberRepository;
import myStudyspring.myStudyspring.repository.JdbcTemplateMemberRepository;
import myStudyspring.myStudyspring.repository.memberRepository;
//import myStudyspring.myStudyspring.repository.memoryMemberRepository;
import myStudyspring.myStudyspring.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);  //순수 jdbc Repository

        return new JdbcTemplateMemberRepository(dataSource);	//jdbctemplate Repository
    }
}

 

위의 코드를 보면 스프링의 장점을 알 수 있다.

 

메모리 저장소 구현체(memoryMemberRepository),

jdbc 구현체(JdbcMemberRepository),

jdbcTemplates 구현체(JdbcTemplateMemberRepository)

 

이렇게 3개의 구현체들이 생성되어 있는데 스프링의 DI를 사용하면 기존의 코드를 전혀 손대지 않고

SpringConfig의 설정만으로 구현 클래스를 어떤 것으로 할 것인지 변경할 수 있다.

객체 지향 개발의 원칙 중 하나인 OCP의 원리를 확인할 수 있다.

* OCP(Open-Closed Principle) 개방-폐쇄 원칙 : 확장에는 열려있고 수정, 변경에는 닫혀있다.

 

 

정리해보면

데이터 베이스 설치 -> build.gradle과 application.properties 환경설정 -> jdbc Repository 생성

-> SpringConfig에서 스프링 빈으로 등록하기 위한 설정 변경

의 과정을 통해 스프링과 데이터베이스를 연동하였다.

 

이제 메모리 저장소가 아닌 데이터베이스를 연결하였기 때문에

서버를 종료하였다 다시 시작해도 데이터가 그대로 남아있다.

 

화면의 회원 리스트
db의 회원 리스트

 

728x90