2024. 3. 8. 01:18ㆍBackend 취업준비/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을 실행하고 결과를 응답받을 수 있다.
- DriverManager를 통해 Connection 획득
- Connection을 통해 Statement 생성
- 질의 수행 및 Statement를 통해 ResultSet 생성
- ResultSet을 통해 데이터 획득
- 리소스 정리
- 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 동작 원리
- 설정 로딩
- 애플리케이션 시작 시, MyBatis 설정 파일을 읽고 설정 정보를 기반으로 SqlSessionFactory를 생성. 이 과정에서 SqlSessionFactoryBuilder가 사용 된다.
- 세션 생성
- 애플리케이션에서 DB 작업을 수행해야 할 때, SqlSessionFactory를 사용하여 SqlSession 객체를 생성.
- SqlSession은 JDBC의 Connection 객체와 유사한 역할을 한다.
- 매퍼 호출
- 생성된 SqlSession 객체를 이용하여 매퍼 인터페이스를 호출.
- 매퍼 인터페이스는 SQL 쿼리에 대응하는 메서드를 가지고 있다. 이때, SqlSession에는 매퍼 정보가 내장되어 있어 해당 매퍼 인터페이스를 어떤 SQL에 매핑해야 하는지 알 수 있다.
- SQL 실행
- 매퍼가 SqlSession을 호출하여 SQL을 실행. SqlSession은 SQL과 매핑된 매퍼를 참조하여 쿼리를 실행하고, 그 결과를 반환
MyBatis사용
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 테이블 (데이터 중심)
- 프로그램을 바탕으로 테이블을 만들거나, 테이블에 저장한 데이터를 다시 객체화 하는 것이 어려움
- 각각 지향하는 목적이 다르므로 객체 구조를 테이블 구조에 저장하는 데에는 한계가 있다
- 추상화 수준의 차이: 객체지향 프로그래밍은 추상화, 상속, 다형성 등의 개념에 의존하여 프로그램을 설계하는 반면, 관계형 데이터베이스는 테이블과 데이터 중심으로 설계
- 데이터 모델의 차이: 객체는 행동과 상태를 가지고 있지만, 관계형 데이터베이스는 데이터의 상태만을 저장
- 데이터 관계의 표현 방식: 객체 간의 관계는 객체 참조로 표현되지만, 관계형 데이터베이스에서는 외래 키 등의 제약 조건으로 표현
이러한 이유들로 작성해야할 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
'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 |