JDBC

이준영·2022년 9월 30일
0

스프링-입문

목록 보기
11/15
post-thumbnail

순수 JDBC

Java와 DB가 붙으려면 JDBC 드라이버가 꼭 필요하다
크게 해야되는게

  • 라이브러리 추가
  • 연결 설정 추가(경로설정)
  • 리포지토리 구현
  • 스프링 설정 변경(인터페이스 수정)

가 있는데 먼저 환경 설정을 보자면

1. jdbc, h2db 관련 라이브러리 추가 : build.gradle

라이브러리를 추가하면 우측 상단에 있는 코끼리를 눌러서 import 해줘야 한다.

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

2. 스프링부트 데이터베이스 연결 설정 추가 : resource/application.properties

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

위의 두가지만 하면 환경 설정(라이브러리 추가, 연결설정 추가) 끝!!


3. JDBC 회원 리포지토리 작성

사실 이 코드를 지금 이해하기엔 무리가...

package hello.hellospring.repository;
    import hello.hellospring.domain.Member;
    import org.springframework.jdbc.datasource.DataSourceUtils;
    import javax.sql.DataSource;
    import java.sql.*;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.Optional;
    public class JdbcMemberRepository implements MemberRepository {
        private final DataSource dataSource;
        public JdbcMemberRepository(DataSource dataSource) {
            this.dataSource = dataSource;
      
 }
    @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);
        }
}
    @Override
    public Optional<Member> findById(Long id) {
        String sql = "select * from member where id = ?";
        Connection conn = null;
        PreparedStatement pstmt = null;

 ResultSet rs = null;
    try {
        conn = getConnection();
        pstmt = conn.prepareStatement(sql);
        pstmt.setLong(1, id);
        rs = pstmt.executeQuery();
        if(rs.next()) {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return Optional.of(member);
        } else {
            return Optional.empty();
}
    } catch (Exception e) {
        throw new IllegalStateException(e);
    } finally {
        close(conn, pstmt, rs);
} }
@Override
public List<Member> findAll() {
    String sql = "select * from member";
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        conn = getConnection();
        pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();

         List<Member> members = new ArrayList<>();
        while(rs.next()) {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            members.add(member);
}
        return members;
    } catch (Exception e) {
        throw new IllegalStateException(e);
    } finally {
        close(conn, pstmt, rs);
    }
}
@Override
public Optional<Member> findByName(String name) {
    String sql = "select * from member where name = ?";
    Connection conn = null;
    PreparedStatement pstmt = null;
    ResultSet rs = null;
    try {
        conn = getConnection();
        pstmt = conn.prepareStatement(sql);
        pstmt.setString(1, name);
        rs = pstmt.executeQuery();
        if(rs.next()) {
            Member member = new Member();
            member.setId(rs.getLong("id"));
            member.setName(rs.getString("name"));
            return Optional.of(member);
}

             return Optional.empty();
        } catch (Exception e) {
            throw new IllegalStateException(e);
        } finally {
            close(conn, pstmt, rs);
        }
}
    private Connection getConnection() {
        return DataSourceUtils.getConnection(dataSource);
}
    private void close(Connection conn, PreparedStatement pstmt, ResultSet rs)
{
        try {
            if (rs != null) {
                rs.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
} try {
            if (pstmt != null) {
                pstmt.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        try {
            if (conn != null) {
                close(conn);
            }
        } catch (SQLException e) {
            e.printStackTrace();
	} 
}
    private void close(Connection conn) throws SQLException {
        DataSourceUtils.releaseConnection(conn, dataSource);

4. 대망의 스프링 설정 변경

Spring.Config에서

@Configuration
  public class SpringConfig {
  
      private final DataSource dataSource;
      
      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);
      }

이렇게 Datasource를 주고 MemperRepository의 return값만 수정하면 위에서 생성한 jdbc 리포지토리를 사용할 수 있다!!!

스프링을 왜 쓸까?

많은 장점이 있겠지만 바로 이런 거.
서버 메모리 쓰다가 DB로 갈아탔는데 몇가지 설정 변경해주고 Config파일 밖에 수정 안했다.
이런걸 보고 다형성을 활용한다고 한다.
자바는 객체지향적 설계가 좋다고 하는데 이게 왜 좋은거냐면 이런 다형성이 편리하게 되도록 스프링 컨테이너가 지원해주기 때문이고 DI개념이 핵심적인 역할을 한다.

  • 개방/폐쇄 원칙 : 확장에는 열려있고, 수정에는 닫혀있다.

  • DI를 이용하면 기존 코드를 손대지 않고 설정만으로 구현 클래스를 변경할 수 있다.


JDBC Template

설정은 순수 JDBC와 같다.

3. 스프링 Jdbc Template 회원 리포지토리

이 코드 역시 이해하기에는 아직 무리가 있는데 순수 jdbc 리포지토리 코드와 비교해보면 확실이 반복이 줄어들고 간결해진 것을 볼 수 있다.


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

그럼 여기서도

4. 대망의 Jdbc Template 스프링 설정 변경

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

끝..??

끝..!!

profile
화이팅!

0개의 댓글