스프링 DB접근 1편 - JDBC,Connection Pool, DataSource

이성준·2022년 9월 26일
0

JDBC

애플리케이션 서버와 db를 연결할 수 있는 방법, 쿼리를 전달하는 방법, 결과를 응답받는 방법이 db마다 각각 다르다 그래서 자바에서는 표준 인터페이스를 만들었고, 이게 바로 JDBC고 이 JDBC를 각각의 벤더들이 구현해서 라이브러리로 제공하는데, 이걸 JDBC 드라이버라고 한다.
드라이버 매니저에 모든 드라이버들이 들어온다 url를 본다음에 자기가 처리할 수 있는지 확인한다. 그리고 커넥션을 획득 한 다음 이 커넥션을 클라이언트에 반환한다.

데이터베이스 연결

DriverManager 커넥션 요청 흐름


DB에 연결할려면 JDBC 인터페이스 중에서 Connection부분을 구현해야한다, JDBC가 제공하는 DriverManager는 라이브러리에 등록된 DB 드라이버들을 관리하고, 커넥션을 획득한다.
1. 애플리케이션 로직에서 커넥션이 필요하면 DriverManager.getConnection()을 호출하고,
2. DriverManger는 라이브러리에 등록된 드라이버 목록을 자동으로 인식한다음, URL, NAME, PASSWORD들을 넘겨서 처리할 수 있는지 확인 후 처리할 수 있는지 확인되면 진행하고 아니면 다음 순서로 넘어간다
3.이렇게 찾은 커넥션 구현체가 클라이언트에 반환된다.

조회 예시

public Member save(Member member) throws SQLException {
	// 데이터베이스에 전달할 SQL을 정의한다.
	String sql = "insert into member(member_id, money) values(?, ?)";
	Connection con = null;
	PreparedStatement pstmt = null;
 	try {
 		con = getConnection();
        // 데이터베이스에 전달할 SQL과 파라미터로 전달할 데이터들을 준비한다.
 		pstmt = con.prepareStatement(sql);
        // SQL의 첫번째 ? 에 값을 지정한다. 
        //statement는 그냥 넣는거고 preparestatement는 바인딩하고 넣는거
 		pstmt.setString(1, member.getMemberId());
 		pstmt.setInt(2, member.getMoney());
        // 준비된 SQL을 커넥션을 통해 실제 데이터베이스에 전달한다.
        // 영향받은 DB row 수를 반환한다.
		pstmt.executeUpdate();
    	return member;
 	} catch (SQLException e) {
 		log.error("db error", e);
 		throw e;
 	} finally {
 		close(con, pstmt, null);
 	}
 }
 
 private void close(Connection con, Statement stmt, ResultSet rs) {
	if (rs != null) {
 		try {
 			rs.close();
 		} catch (SQLException e) {
 		log.info("error", e);
		}
	}
	if (stmt != null) {
 		try {
 			stmt.close();
 		} catch (SQLException e) {
 			log.info("error", e);
 		}
 	}
 	if (con != null) {
 		try {
 			con.close();
 		} catch (SQLException e) {
 			log.info("error", e);
 		}
 	}
}
 
private Connection getConnection() {
 	return DBConnectionUtil.getConnection();
}

이것은 JDBC로 하는 조회 예인데
주의사항은

    1. 커넥션 요청 2. 커넥션 생성 3. 커넥션 반환
      커넥션을 꼭 닫아야 된다 리소스를 쓰고 있기 때문에 안닫으면 커넥션 풀에 계속 떠다닌다.
  • 리소스를 반환할때는 역순으로 해준다.

  • SQL Injection 공격을 예방하려면 파라미터 바인딩 방식을 사용하자.

  • result set에서 커서를 호출하면서 다음 데이터를 조회할 수 있다.

커넥션 풀

커넥션을 획득 할때는 커넥션 조회과정, 커넥션을 연결하기위한 네트워크 동작, 내부 인증, 세션 생성, 비용이 많이 든다
그래서 개발자들은 커넥션을 어플리케이션 생성 시점에 필요한 만큼 만들어놓고 필요할때마다 쓰고 반납하는 커넥션 풀이라는 개념을 만들어 낸다.

어플리케이션이 실행될때 커넥션이 초기화되는 과정


어플리케이션 서버 시작과 함께 커넥션풀에서 쓸 커넥션을 만드는데 이때 커넥션은 별도의 스레드에서 만든다.
생성된 커넥션을 객체 참조로 그냥 가져다 쓰면 되고, 커넥션 풀에 커넥션을 요청하면 커넥션 풀은 커넥션을 하나 반환한다.
그리고 이걸 쓴 후, 그냥 커넥션풀에 다시 반납하면 된다.

만약 커넥션이 없으면 1개를 얻을때까지 기다렸다가 획득한다. 그리고 풀이 확보될때까지 대기상태로 진입한다.

DataSource

DataSource는 왜 등장했나

커넥션을 획득 하는 방법은 JDBC DriverManager를 이용하거나, 커넥션 풀을 사용하는 방법을 이용한다.
하지만 DriverManager를 이용하다가 커넥션 풀을 사용하기 위해 변경할려면 어플리케이션 코드 변경이 필요하기때문에, 개발자들은 커넥션 획득 방법을 추상화해서 전략적으로 사용할 수 있게 바꿨다. 그래서 애플리케이션 로직은 DataSource 에만 의존하면 된다.

DataSorce는 커넥션을 획득하는 방법을 추상화한 인터페이스

설정과 사용의 분리

//	1번
   		@Test
        void driverManager() throws SQLException {
            Connection con1 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            Connection con2 = DriverManager.getConnection(URL, USERNAME, PASSWORD);
            log.info("connection={}, class={}", con1, con1.getClass());
            log.info("connection={}, class={}", con2, con2.getClass());
        }
//  2번        
        @Test
        void dataSourceDriverManager () throws SQLException {
            //DriverManagerDataSource - 항상 새로운 커넥션 획득
        DriverManagerDataSource dataSource = new DriverManagerDataSource(URL,
                    USERNAME, PASSWORD);
        }
        useDataSource(dataSource);
    }

    private void useDataSource(DataSource dataSource) throws SQLException {
        Connection con1 = dataSource.getConnection();
        Connection con2 = dataSource.getConnection();
        log.info("connection={}, class={}", con1, con1.getClass());
        log.info("connection={}, class={}", con2, con2.getClass());
    }

1번은 driverManager로 커넥션을 하는 코드고 2번은 dataSource를 통해서 커넥션을 하는 코드다 1번은 커넥션을 할때마다 파라미터로 URL, USERNAME, PASSWORD를 넘기고 있지만, 2번은 처음 설정할때만 파라미터를 넘겨주고있다.

설정과 사용의 분리
필요한 데이터를 datasource가 만들어지는 시점에 다 넣어두게 되면, getconnection만 호출하면 되니까, url, username,password같은 속성들의 의존안해도 된다.
설정을 바꿀려면 한곳에서만 바꿔야 단일 책임 원칙이다.

0개의 댓글