반응형
Notice
Recent Posts
Recent Comments
Link
«   2024/05   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
05-19 00:03
관리 메뉴

ImJay

[Java Spring] 1-19. 순수 JDBC 본문

Java Spring/스프링 입문

[Java Spring] 1-19. 순수 JDBC

ImJay 2023. 1. 30. 13:07
반응형

[Java Spring] 1-19. 순수 JDBC


1. 이제 어플리케이션과 DB를 연동해서 어플리케이션에서 SQL 문을 작성하여 DB에 데이터를 저장해보는 작업을 수행해보자.

 

2. 주의! 이렇게 JDBC API로 직접 코딩하는 것은 15년 전의 이야기이다. 따라서 고대 개발자들이 이렇게 고생하고 살았구나 생각하고, 참고만 하며 넘어가자.

 

3. bundle.gradle dependencies 에 아래 코드를 추가하자.

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

 

4. src > resources > application.properties 에 해당 코드를 작성한다.

spring.datasoruce.url=jdbc:h2:~/test
spring.datasource.driver-class-name=org.h2.Driver

- url 은 H2 콘솔의 JDBC URL 이다.

 

5. 그리고 코끼리 버튼을 클릭한다.

 

6. 빌드가 정상적으로 되는지 확인한다.

 

7. 빌드에 성공했다면 연동에 성공한 것이다. 이제 어플리케이션을 통해 작업을 수행해보자.

src > main > java > repository > 새로 만들기 > java 클래스

 

8. JdbcMemberRepository 클래스 생성

 

9. 코드 작성

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

- 데이터를 가져오려면 sql.DataSource 라이브러리가 필요하다.

 

10. SpringConfig 수정

package hello.hellospring;

import hello.hellospring.domain.Member;
import hello.hellospring.repository.JdbcMemberRepository;
import hello.hellospring.repository.MemberRepository;
import hello.hellospring.repository.MemoryMemberRepository;
import hello.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);
    }
}

 

11. 빌드 후 회원 목록 확인

- 정상적으로 DB가 연동된 것을 확인할 수 있다.

 

12. H2 콘솔로 새로운 데이터를 추가해보자.

 

13. 다시 한번 회원목록을 확인해보자.

- 정상적으로 추가되었음을 확인할 수 있다.

 

14. 작동 원리

14-1. 현재 우리가 구성한 클래스는 다음과 같다.

14-2. 스프링 컨테이너에서는 우리가 반환해준 객체를 토대로 스프링에서 빈 등록을 교체했다.

- 스프링의 장점이 다른 걸 건들 필요 없이 간단하게 레포지토리만 변경하면 된다는 점이다.

 

15. 우리가 지금 사용한 객체지향 원리는 5원칙(SOLID) 중 OCP(개방 폐쇄 원칙 : 확장에는 열려있고, 변경에는 닫혀있다.)이다.

 

16. 스프링의 DI (Dependencies Injection)을 사용하면 기존 코드를 전혀 손대지 않고, 설정만으로 구현 클래스를 변경할 수 있다.

 

반응형
Comments