코드네임 JY

[스프링 입문] JDBC & JDBC Template 본문

백엔드 공부

[스프링 입문] JDBC & JDBC Template

영재임재영 2022. 12. 14. 15:49

미리보기

✅ JDBC란 무엇인가!

✅ JDBC Template에 대해 알아보자!

✅ 의존성 주입(DI)을 이용하여 저장소를 변경해보자!


🌽 JDBC (Java Database Connectivity)

자바에서 DBMS(Database Management System)에 접근할 수 있게 해주는 API

 

쉽게 말해서, 자바에서 DB를 사용할 수 있게 해주는 API 라고 이해하면 된다!

JBCD API는 자바로 작성되어있는 인터페이스 및 클래스들로 구성되어 있고,

개발자는 직접 쿼리를 보내고 동작을 수행하고, 이를 통해 결과 값을 받을 수 있다.

 

그러면 JDBC를 사용하기 위해서 어떤 설정을 해야하는가? 기존 파일 설정에 아래 코드를 추가해주면 된다.

일단 이번 공부에서는 로컬 DB로 H2 Database(Java SQL Database)를 사용할 것이다.

 

build.gradle 파일 내 설정
application.properties 파일 내 설정

아직은 스프링 입문 단계라서.. 지금부터 다루는 방식들의 코드들의 문법은 적지 않고, 간단히 짚고만 넘어갈 예정이다.

일단 JDBC를 사용하는 전체적인 과정 중에서 꼭 필요한 객체가 하나 있는데, 바로 'Datasource' 라는 객체이다.

private final DataSource dataSource;

public JdbcMemberRepository(DataSource dataSource) {
    this.dataSource = dataSource;
}

JDBC는 데이터베이스 커넥션을 획득할 때 사용되는 객체이며, 커넥션에 대한 정보를 담고 있다.

스프링은 DataSource 객체를 생성하여 스프링 빈에 등록해두고, 이 정보를 주입받아서 JDBC를 사용할 수 있게 되는 것이다.

@Override
public Optional<Member> findById(Long id) {  // JDBC 방식
    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);
    }
}

위 코드는 ID를 통해서 사용자를 찾는 코드(findById)인데 간단히만 보면.. (한줄한줄 이해하기에는 너무 방대하다 ㅠㅠ)

 

전체적인 과정은 Connection → Statement → Result 순으로 진행되는데,

말 그대로 Connection 부분에서는 DB와의 연동이 시작되고, Statement 부분에서는 SQL 쿼리 문을 담을 수 있다.

그리고 Result 부분에서 쿼리를 통해 수행한 결과 값을 받아서 이를 사용자에게 보여줄 수 있는 것이다.

마지막에는 메모리의 낭비를 막기 위해 이들의 할당을 해제해주어야한다. 전체적으로는 이렇다.. 너무 복잡하다..

 

단점이라면, 코드가 엄청 길고, 전체적인 과정에서 사용되는 객체들을 모든 메소드에 작성해야할 만큼 코드의 중복이 심하다.

따라서 이런 코드의 중복을 줄이기 위해 나온 것이 바로 'JDBC Template' 이라는 것이다.

🥕 JDBC Template

기존 JDBC 코드에 중복을 줄여줄 수 있다. 하지만 SQL 문은 직접 작성해야한다.

private final JdbcTemplate jdbcTemplate;

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

JDBC Template 방식에서는 JdbcTemplate 객체를 선언해주어야하고,

이 또한 스프링으로부터 DataSource를 주입받아 사용해야한다!

@Override
public Optional<Member> findById(Long id) {  // JDBC Template 방식
    List<Member> result = jdbcTemplate.query("select * from member where id = ?", memberRowMapper(), id);
    return result.stream().findAny();
}

위에서 설명한 JDBC 방식과 비교해보면.. 엄청나게 코드를 줄였다!

전체적인 과정을 설명하자면, 작성된 쿼리를 통해 나온 결과를 RowMapper라는 함수를 통해 값을 매핑하여 반환한 것이다.

(참고 : 여기서 RowMapper 함수는 id, name을 하나의 쌍으로 묶어서 매핑해주는 역할을 했다)

🎀 환승 연애 리포지토리!

우리는 스프링에서 Container, Service, Repository 간의 관계를 '의존성 주입(DI)' 을 통해 구현할 수 있었다.

 

현재 공부하는 스프링 강의에서는 인터페이스를 만들어서 DB 방식에 따라 Repository를 만들어 구현하였다.

그동안 사용했던 Repository는 메모리를 통해서 DB 기능을 구현했는데, 이제는 JDBC로 Repository를 만들었으니 환승하고 싶다!

 

위와 같이 구현하려면! 우리가 자바 코드로 직접 등록한 방식을 사용하면 아주 간단하게 Repository를 환승할 수 있다!

@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);  // 여기로 환승할께 ㅎㅎ..
      }
}

그렇다! MemoryMemberRepository(메모리로 구현한 리포지토리)를 JdbcMemberRepository로 바꿔주면 된다!

하지만 이는 JDBC를 사용한 것이기 때문에, DB 커넥션에 대한 정보를 담고있는 DataSource 객체를 인자로 담아주어야 한다!

따라서 의존성 주입 방식을 사용하면, 기존 코드를 하나도 손대지 않고 설정 코드만 수정해서 구현 클래스를 변경할 수 있다!

Comments