JDBC 흐름 정리

2024. 3. 8. 01:18Backend 취업준비/Spring

 

JDBC( JAVA DataBase Connectivity )

 

  • JDBC(Java Database Connectivity)는 자바 프로그래밍 언어를 사용해 데이터베이스에 접근할 수 있도록 하는 자바 API
  • 이를 통해서 우리는 데이터베이스에 접속하고, SQL을 실행하고, 이를 통해 데이터를 가져오거나 삭제하는 등 데이터를 다룰 수 있게 된다.

 

JDBC 등장배경

 

  • JDBC가 등장하게 된 이유 => 데이터베이스 접근의 표준화를 위해서
  • 데이터베이스에는 Oracle Database, MySQL, PostgreSQL 와 같이 여러 종류의 데이터베이스가 있다
  • 각각 데이터베이스마다 SQL를 전달하거나 결과를 응답받는 방법들이 다 다르고 데이터베이스의 종류는 수십 개가 존재
  • JDBC가 존재하기 전에는 이런 데이터베이스마다 존재하는 고유한 API를 직접 사용했었다.
  • 이에 따라 개발자는 기존의 데이터베이스를 다른 데이터베이스로 교체해야 하는 경우에는 데이터베이스에 맞게 기존의 코드를 모두 수정해야 했으며 심지어 각각의 데이터베이스를 사용하는 방법도 새로 학습해야 했다.
  • JDBC의 표준 인터페이스 덕분에 개발자는 데이터베이스를 쉽게 변경할 수 있게 되었고 변경에 유연하게 대처할 수 있게 되었다.
  • 어떤 데이터베이스를 사용하더라도 일관된 코드로 작성할 수 있다

 

JDBC를 알아야 하는 이유

 

  • JDBC는 JDK 1.1 버전에 출시된 매우 오래된 기술이며 사용하는 방법도 많이 복잡 =>  데이터베이스 접근을 더 편리하게 하고 개발 생산성을 높이기 위한 기술인 SQL Mapper와 ORM(Object-Relational Mapping)을 주로 사용
  • 응?? 그렇다면 JDBC를 굳이 알아야 하나? 라는 의문점이 들 수도 있다.
  • 사실 SQL Mapper나 ORM은 JDBC를 기반으로 동작한다. 이들의 기술은 JDBC의 기능과 개념을 내부적으로 활용하여 데이터베이스와의 상호작용을 처리
  • 따라서 JDBC를 이해하면 SQL Mapper나 ORM이 어떻게 동작하는지 더 잘 이해할 수 있는 베이스가 되며 또한 문제가 발생했을 때 근본적인 문제를 해결할 수 있다.

 

JDBC 동작 흐름

  • JDBC API를 사용하기 위해서는 JDBC 드라이버를 먼저 로딩한 후 데이터베이스와 연결해야 한다.
  • JDBC 드라이버는 JDBC 인터페이스를 구현한 구현체라고 생각할 수 있으며 특정 데이터베이스 벤더(Oracle, MySQL, PostgreSQL 등)에 대한 연결과 데이터베이스에 대한 작업을 가능하게 해준다. (JDBC 드라이버의 구현체를 이용해서 특정 벤더의 데이터베이스에 접근할 수 있음)
  • JDBC가 제공하는 DriverManager가 드라이버들을 관리하고 Connection을 획득하는 기능을 제공한다. 이 획득한 Connection을 통해서 데이터베이스에 SQL을 실행하고 결과를 응답받을 수 있다.

  1. DriverManager를 통해 Connection 획득
  2. Connection을 통해 Statement 생성
  3. 질의 수행 및 Statement를 통해 ResultSet 생성
  4. ResultSet을 통해 데이터 획득
  5. 리소스 정리
  • DriverManager를 사용하기 전에 Class.forName("com.mysql.jdbc.Driver"); 을 통해 해당 드라이버를 불러와야 하는데 JDBC 4.0 버전 이후부터는 JDBC 드라이버 자동 로딩이 도입되어 생략이 가능하다.
implementation group: 'mysql', name: 'mysql-connector-java', version: '8.0.33'
package org.example;

import java.sql.*;

public class PlainJdbcExample {
    static final String DB_URL = "jdbc:mysql://localhost:11802/test";
    static final String USER = "root";
    static final String PASS = "root";
    static final String QUERY = "SELECT * FROM student";

    public static void main(String[] args) {
        // Open & get a connection
        try (Connection conn = DriverManager.getConnection(DB_URL, USER, PASS);
             Statement stmt = conn.createStatement();
             ResultSet rs = stmt.executeQuery(QUERY);) {
            // Extract data from result set after execute query
            while (rs.next()) {
                // Retrieve by column name
                System.out.print("ID: " + rs.getInt("id"));
                System.out.print(", name: " + rs.getString("name"));
                System.out.print(", Age: " + rs.getInt("age"));
                System.out.println(", desc: " + rs.getString("desc"));
            }
        } catch (SQLException e) {
            System.out.println(e.getErrorCode());
            System.out.println(e.getMessage());
            e.printStackTrace();
        } finally {
            // 5. 리소스 정리
            try {
                if (resultSet != null) {
                    resultSet.close();
                }
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }
    }
}

 

Connection conn = DriverManager.getConnection(DB_URL,USER,PASS);
Statement stmt = conn.createStatement();
  • 위 코드조각은 쿼리문을 날리고 싶을때 마다 매번 새로운 Connection을 생성하는 꼴이다 => HikariCP로 해결
  • 또한 출력을 할 때 데이터 타입을 전부 알고 일일이 맞춰 줘야 한다 => SQLMapper로 해결
  • 매번 커넥션을 생성하기 위해서는 네트워크와 연결하고 서버의 자원을 사용해야 한다.
  • SQL을 실행할 때마다 커넥션을 획득해야 하므로 연결하는 데에 추가적인 시간이 걸리며 매번 리소스를 사용하게 된다.
  • 그래서 이러한 문제점을 해결하기 위해 커넥션 풀(Connection Pool)을 사용하게 된다.

 

 

커넥션 풀과 DataSource

  • 데이터베이스와의 연결이 필요할 때마다 매번 새로운 커넥션을 생성하는 대신 미리 생성된 커넥션을 커넥션풀에 보관하고 필요할 때마다 커넥션을 꺼내서 사용
  • 커넥션 풀을 통해 커넥션을 사용하고 나면 커넥션을 종료하지 않고 커넥션 풀에 반납
  • 이와 같은 방법으로 커넥션을 재사용하게 되면 리소스를 효율적으로 활용할 수 있으며 성능을 높일 수 있다.

 

  • 이처럼 커넥션을 획득할 때 DriverManager를 통해서 커넥션을 획득하거나 커넥션풀을 통해서 커넥션을 획득하는 등 여러 방법이 존재한다.
  • 그래서 DataSource 인터페이스를 통해서 커넥션을 획득하는 방법을 추상화한다.
  • 어떤 방식으로 커넥션을 획득하는지 상관없이 DataSource 인터페이스를 통해 일관된 방식으로 데이터베이스와 통신할 수 있는 것이다.
  • 또한 인터페이스를 구현한 구현체를 쉽게 교체할 수 있어 애플리케이션의 유연성을 높일 수 있다.
  • 스프링과 스프링 부트에서는 DataSource 인터페이스를 구현한 여러 구현체를 제공한다
  • 대표적으로 JDBC DriverManager 기반으로 한 DriverManagerDataSource와 HikariCP 커넥션 풀을 기반으로 한 HikariDataSource가 있다.
  • 커넥션풀을 사용해서 커넥션을 획득하고 싶은 경우 DataSource의 구현체 DriverManagerDataSource를 HikariDataSource로 바꾸어 끼기만 하면 된다 이로써 커넥션을 획득할 때 리소스를 효율적으로 활용할 수 있고 빠른 속도로 커넥션을 획득할 수 있다.

 

결론적으로 위의 설정을 HikariCP를사용한 yml파일로 만들 수 있다

spring:
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    type: com.zaxxer.hikari.HikariDataSource
    url: jdbc:mysql://localhost:11802/test
    username: root
    password: root
    //밑은 히카리 옵션들
    minimum-idle: 1
    maximum-pool-size: 5
    pool-name: SampleConnectionPool
    connectionTimeout: 10000
    validationTimeout: 5000
    idleTimeout: 600000
    minimumIdle: 3
    maximumPoolSize: 10

HikariCP 옵션을 사용하여 커넥션 풀 설정을 할 수 있다

 

SQL Mapper

 

Spring JDBC

  • Spring JDBC는 JDBC(Java Database Connectivity) 기반으로 데이터베이스와의 상호작용을 지원하는 스프링 프레임워크의 모듈 중 하나
  • Spring JDBC는 데이터베이스 연결, 쿼리 실행, 결과 처리 등의 기능을 단순화하고 추상화합니다. 이를 통해 개발자가 보다 간편하게 JDBC를 사용
  • Spring JDBC는 JdbcTemplate이라는 중요한 클래스를 제공. JdbcTemplate은 JDBC 작업을 수행하는데 사용되며, 예외 처리, 트랜잭션 관리, SQL 쿼리 실행 등의 기능을 제공

Jdbc Template 사용

https://velog.io/@nimoh/Spring-JdbcTemplate%EC%9D%98-%EA%B8%B0%EB%B3%B8

 

[Spring] JdbcTemplate의 기본

Spring에서 SQL을 사용할 때 JdbcTemplate는 간단하면서 좋은 선택지이다. JdbcTemplate은 트랜잭션 관리 및 리소스 관리등을 자동으로 해주는 등 매우 편리하게 JDBC를 사용할 수 있게 도와준다.JdbcTemplate

velog.io

 

 

MYBatis

 

Mybatis는 기존 JDBC의 문제점을 Spring JDBC와 약간 다르게 해석했다. Java 코드에서 SQL을 쓰는 것 자체를 분리하는 것을 목표로 잡았다. Query를 Java에서 XML로 이동하는 것이다.

  • 복잡한 JDBC 코드 X
  • ResultSet과 같이 결과값을 매핑하는 객체 X
  • 간단한 설정
  • 관심사 분리

 

  • SQL statements를 xml에 따로 지정하고 쿼리를 메소드와 매핑시킴으로써 Java 코드와 SQL 구문들을 완전히 분리한다.
  • DAO는 interface로 Spring JDBC보다 훨씬 간결해진다
  • 그럼에도 SQL을 직접 작성함에 따라 동반되는 문제점은 피할 수 없다 (논리적으로 DB에 종속)
    • 테이블 마다 비슷한 CRUD SQL 작업이 일어나는데 DAO개발이 반복되게 된다
    • 테이블 필드가 변경될 시 이와 관련된 DAO의 SQL문, 객체의 필드 등을 수정해야 한다

MyBatis 동작 원리

  1. 설정 로딩
    1. 애플리케이션 시작 시, MyBatis 설정 파일을 읽고 설정 정보를 기반으로 SqlSessionFactory를 생성. 이 과정에서 SqlSessionFactoryBuilder가 사용 된다.
  2. 세션 생성
    1. 애플리케이션에서 DB 작업을 수행해야 할 때, SqlSessionFactory를 사용하여 SqlSession 객체를 생성.
    2. SqlSession은 JDBC의 Connection 객체와 유사한 역할을 한다.
  3. 매퍼 호출
    1. 생성된 SqlSession 객체를 이용하여 매퍼 인터페이스를 호출.
    2. 매퍼 인터페이스는 SQL 쿼리에 대응하는 메서드를 가지고 있다. 이때, SqlSession에는 매퍼 정보가 내장되어 있어 해당 매퍼 인터페이스를 어떤 SQL에 매핑해야 하는지 알 수 있다.
  4. SQL 실행
    1. 매퍼가 SqlSession을 호출하여 SQL을 실행. SqlSession은 SQL과 매핑된 매퍼를 참조하여 쿼리를 실행하고, 그 결과를 반환

MyBatis사용

https://lotuus.tistory.com/75

MyBatis 강력한 기능 ⇒ 동적 쿼리

  • MyBatis에서 동적 SQL 생성 기능은 SQL 쿼리의 일부가 실행될지 여부를 조건에 따라 동적으로 결정할 수 있는 기능을 의미
  • 이는 주로 조건에 따라 WHERE 절이나 SET 절 등을 포함하거나 제외하는 등의 작업을 할 때 유용
  • 예를 들어, 사용자가 입력한 검색 조건에 따라 WHERE 절을 동적으로 조립하거나, 사용자가 업데이트할 컬럼을 선택했을 때 SET 절을 동적으로 생성.
  • <if>, <choose>, <when>, <otherwise> 등의 태그를 사용하여 조건부로 SQL을 생성할 수 있습니다. 또한, <trim>, <where>, <set> 등의 태그를 사용하여 조건에 따라 필요한 SQL 부분을 포함하거나 제외할 수도 있다
<select id="getUserList" parameterType="map" resultType="User">
  SELECT * FROM users
  <where>
    <if test="username != null">
      AND username = #{username}
    </if>
    <if test="email != null">
      AND email = #{email}
    </if>
  </where>
</select>

MyBatis 동적 쿼리 사용법

https://mybatis.org/mybatis-3/ko/dynamic-sql.html

 

ORM

 

패러다임의 불일치

  • 객체 지향적으로 설계한 프로그램 (추상화, 상속, 다형성) <=> 관계형 DB 테이블 (데이터 중심)
  • 프로그램을 바탕으로 테이블을 만들거나, 테이블에 저장한 데이터를 다시 객체화 하는 것이 어려움
  • 각각 지향하는 목적이 다르므로 객체 구조를 테이블 구조에 저장하는 데에는 한계가 있다
  1. 추상화 수준의 차이: 객체지향 프로그래밍은 추상화, 상속, 다형성 등의 개념에 의존하여 프로그램을 설계하는 반면, 관계형 데이터베이스는 테이블과 데이터 중심으로 설계
  2. 데이터 모델의 차이: 객체는 행동과 상태를 가지고 있지만, 관계형 데이터베이스는 데이터의 상태만을 저장
  3. 데이터 관계의 표현 방식: 객체 간의 관계는 객체 참조로 표현되지만, 관계형 데이터베이스에서는 외래 키 등의 제약 조건으로 표현

이러한 이유들로 작성해야할 sql 문이 복잡해 지는데, 적절한 메서드들을 사용하면 JPA가 이러한 작업들을 대신 해준다

어떤식으로 처리해 주는지 예시

https://www.elancer.co.kr/blog/view?seq=231 11분 55초부터 보시길

 

ORM

  • 객체와 관계형 데이터 베이스를 맵핑
  • 객체 간의 관계를 바탕으로 SQL문을 자동으로 생성하고 직관적인 메서드로 데이터를 조작

 

JPA

JPA, Hibernate, Spring Data JPA, QueryDSL

아래 링크 강의 꼭 보기 추천..

https://www.youtube.com/playlist?list=PL9mhQYIlKEhfpMVndI23RwWTL9-VL-B7U

 

 

 

출처

https://tecoble.techcourse.co.kr/post/2023-06-28-JDBC-DataSource/

 

JDBC와 DataSource 이해하기

JDBC란? JDBC(Java Database Connectivity)는 자바 프로그래밍 언어를 사용해 데이터베이스에 접근할 수 있도록 하는 자바 API이다. 이를 통해서 우리는 데이터베이스에 접속하고, SQL…

tecoble.techcourse.co.kr

https://sdesigner.tistory.com/101

'Backend 취업준비 > Spring' 카테고리의 다른 글

스프링 Data Jpa로 API 만들기  (0) 2024.03.16
HTTP응답을 처리하는 방식 (@Controller, @RestController)  (0) 2024.03.09
스프링 빈  (0) 2024.03.03
빌드 도구 Gradle  (0) 2024.03.02
스프링과 스프링 부트  (0) 2024.02.29