(▲ https://hackmd.io/@ddubson/rkn-sR4wU)
JDBC
-
Java Database Connectivity(JDBC)는 DBMS에 접근하기 위한 Java의 표준 API 스펙
-
JDBC 드라이버 로딩, DBMS 연결, SQL 전송 및 결과 반환 등의 처리
fun main() {
val driver = "com.mysql.cj.jdbc.Driver"
val url = "jdbc:mytsql://localhost:3306/test"
Class.forName(driver).newInstance()
val con: Connection = DriverManager.getConnection(url, "root", "root")
val st: Statement = con.createStatement()
val sql = "SELECT * FROM member"
val rs: ResultSet = st.executeQuery(sql)
while(rs.next()) {
const name = rs.getString(1)
const date = rs.getString(2)
println("$name - $date")
}
rs.close()
st.close()
con.close()
}
구성요소

Driver
import java.sql.Driver
-
Driver인터페이스를 구현하여 DB와 연결할 JDBC Driver를 만들 수 있음 -
com.mysql:mysql-connector-j와 같은 라이브러리가 해당 DBMS에 맞는 드라이버를 구현함
Connection
import java.sql.Driver
import java.sql.Connection
val con: Connection = if (usingDriverManager) {
// 방법 1 - DriverManager
val driver = "com.mysql.cj.jdbc.Driver"
Class.forName(driver).getDeclaredConstructor().newInstance()
DriverManager.getConnection(url, user, password)
} else {
// 방법 2 - MysqlDataSource
MysqlDataSource().apply {
setUrl(url)
setUser(user)
setPassword(password)
}.connection
}
-
특정 DB와의 연결정보를 가지는 인터페이스
-
DriverManager.getConnection()를 통해 JDBC 연결 생성 -
특정 database와 jdbc driver에 의존함
-
연결이 되면
Stagement를 통해 쿼리는 실행할 수 있음
Statement
import java.sql.Statement
val st: Statement = con.createStatement()
PreparedStatement
import java.sql.PreparedStatement
-
Statement의 하위 인터페이스 -
SQL을 미리 컴파일하여 실행 속도를 높힘
ResultSet
import java.sql.ResultSet
statement.executeQuery().let { rs: ResultSet ->
Entity(
id = resultSet.getLong(1),
name = resultSet.getString(2),
)
}
-
Statement를 통한 쿼리 실행 결과에 사용되는 인터페이스
동작 분석
어떻게 데이터를 ResultSet 에 가져오는가?
-
mysql testcontainer 사용한 test case에서 디버깅해봤을 때
-
ResultSet의 구현체는com.mysql.cj.jdbc.result.ResultSetImpl사용함 -
쿼리 실행시
rowData: ResultsetRows(실제 인스턴스는ResultsetRowsStatic)필드의rows에Row인스턴가 저장되어 있음Row인스턴스는ByteArrayRow이고,internalRowData가 byte-array를 가지고 있음
-
DB와 무언가를 통한 통신을 통해 데이터를 byte array로 가져와서 저장하는 것으로 보임.
-
TODO: cursor는 그럼 어떻게 동작할까?
// MySQL에서 이 설정이 있다면 스트리밍 방식으로 읽는 듯 // https://dev.mysql.com/doc/connector-j/8.0/en/connector-j-reference-implementation-notes.html val stmt = con.createStatement( java.sql.ResultSet.TYPE_FORWARD_ONLY, java.sql.ResultSet.CONCUR_READ_ONLY, ).apply { fetchSize = Integer.MIN_VALUE }
-
-
ConnectionPool
-
일정량의 Connection 인스턴스를 미리 만들어서 pool에 저장해두고 사용하기 위함
-
HikariCP
-
DBCP(Database Connection Pool) 라이브러리
val config = HikariConfig().apply { jdbcUrl = url username = user this.password = password } val ds = HikariDataSource(config) val con: Connection = ds.connection
-
spring-jdbc
org.springframework.boot:spring-jdbc:5.2.9.RELEASE > org.springframework:spring-beans:5.2.9.RELEASE > org.springframework:spring-core:5.2.9.RELEASE > org.springframework:spring-tx:5.2.9.RELEASE
-
JDBC에서 처리하는 데이터베이스 관련 작업들을 스프링 프레임워크로 위임하고, 별도 API를 통해 데이터베이스 연결 및 쿼리 실행을 함.
구성요소
@startuml
hide empty field
hide empty method
interface JdbcOperations {
query(psc, rowMapper): List<T>
}
class JdbcTemplate
interface NamedParameterJdbcOperations
class NamedParameterJdbcTemplate {
-classicJdbcTemplate: JdbcOperations
}
abstract class JdbcAccessor {
-dataSource: DataSource
}
JdbcOperations <|-- JdbcTemplate
JdbcAccessor <|-- JdbcTemplate
NamedParameterJdbcOperations <|-- NamedParameterJdbcTemplate
NamedParameterJdbcTemplate --> JdbcOperations
@enduml
JdbcTemplate
-
DataSource를 생성하고JdbcTemplate에 주입하여 사용. -
JdbcTemplate를 통해 JDBC를 편리하게 사용할 수 있음. -
JdbcTemplate: 가장 저수준에서 동작하며, Spring 내부적으로JdbcTemplate을 사용함-
thread-safe 하므로, DAO등에서 맴버 변수로 저장.
DataSource만 외부에서 유입받아 초기화해둘 수 있음.
-
NamedParameterJdbcTemplate
-
NamedParameterJdbcTemplate:JdbcTemplate을 래핑해서?가 아닌 이름이 붙은 파라미터 사용할 수 있게함.
RowMapper
-
RowMapper:ResultSet(쿼리 결과)에서 원하는 객체로 타입을 변환하는 역할 -
BeanPropertyRowMapper
-
DataClassRowMapper
-
spring-boot-starter-jdbc
org.springframework.boot:spring-boot-starter-jdbc:2.3.4.RELEASE > com.zaxxer:HikariCP:3.4.5 > org.springframework.boot:spring-boot-starter:2.3.4.RELEASE > org.springframework:spring-jdbc:5.2.9.RELEASE
-
spring-jdbc에 대하여 스프링부트 의존성 관리를 한번에 하고자 wrapping된 모듈.
ORM
-
ORMObject Relational Mapping
-
TODO
spring-data-jdbc
org.springframwork.data:spring-data-jdbc:2.0.4.RELEASE > org.slf4j-api:1.7.30 > org.springframework.data:spring-data-commons:2.3.4.RELEASE > org.springframework.data:spring-data-relational:2.0.4.RELEASE > org.springframework:spring-beans:5.2.9.RELEASE > org.springframework:spring-context:5.2.9.RELEASE > org.springframework:spring-core:5.2.9.RELEASE > org.springframework:spring-jdbc:5.2.9.RELEASE > org.springframework:spring-tx:5.2.9.RELEASE
-
Spring Data의 미션은 데이터 액세스를 위해 친숙하고 일관된 Spring 기반의 프로그래밍 모델을 제공하는 동시에 기본 데이터 저장소의 특수한 특성을 유지하는 것.
-
spring data repository 추상화의 목표는 데이터 액세스 레이어를 구현하는 데 필요한 상용구 코드의 양을 줄이는 것
-
Spring Data JDBC는 Spring Data의 여러 모듈중 하나로, 말 그대로 JDBC를 지원하는 모듈.
-
뭔가 문서가 JPA인것 같은데…? 엔티티매니저 가지고 더티체킹하는게 큰 차이?
-
-
CrudRepository를 활용하여 기본적인 CRUD 구현을 쉽게 함. -
중신에
Repository인터페이스가 있고,CrudRepository,ListCurdRepository인터페이스와 같이 엔티티 클래스에 대한 정교한 CURD기능을 제공-
CurdRepository인터페이스는Iterable반환 -
ListCurdRepository인터페이스는List반환
-
구성요소
@startuml
hide empty field
hide empty method
interface Repository
interface CurdRepository {
save(eneity: S)
saveAll(entities: Iterable<S>)
findById(id: ID)
existsById(id: ID)
findAll()
findAllById(ids: Iterable<ID>)
count()
deleteById(id: ID)
delete(entity: T)
deleteAllById(ids: Iterable<? extends ID>)
deletaAll(entities: Iterable<? extends T>)
deleteAll()
}
interface PagingAndSortingRepository {
findAll(sort: Sort): Iterable<T>
findAll(pageable: Pageable): Page<T>
}
class SimpleJdbcRepository
interface JdbcAggregateOperations
class JdbcAggregateTemplate
Repository <|-- CurdRepository
CurdRepository <|-- SimpleJdbcRepository
PagingAndSortingRepository <|-- SimpleJdbcRepository
SimpleJdbcRepository ..> JdbcAggregateOperations
interface DataAccessStrategy
interface JdbcConverter
JdbcAggregateOperations <|-- JdbcAggregateTemplate
JdbcAggregateTemplate ..> DataAccessStrategy
JdbcAggregateTemplate ..> JdbcConverter
@enduml
Repository
CurdRepository
EntityRowMapper
-
spring-jdbc의 RowMapper의 구현체
JdbcConverter
JdbcValue
spring-boot-starter-data-jdbc
org.springframework.boot:spring-boot-starter-data-jdbc:2.3.4.RELEASE > org.springframework.boot:spring-boot-starter-jdbc:2.3.4.RELEASE > org.springframework.data:spring-data-jdbc:2.0.4.RELEASE
spring-jdbc-plus
-
네이버에서 제공하는 Spring Data JDBC 확장 라이브러리.
References
-
JdbcTemplate:
-
JdbcOperation: 구현체
-
NamedParameterJdbcTemplate
-
TransactionManager
-
TransactionTemplate
-
DataAccessStrategy
findById
-
CrudRepository구현체인SimpleJdbcRepository-
JdbcAggregateOperations필드의findById메서드 실행됨 -
JdbcAggregateOperations구현체인JdbcAggregateTemplate-
DataAccessStrategy필드의findById메서드 호출-
DataAccessStrategy구현체인DefaultDataAccessStrategy -
SqlGeneratorSource필드의getSqlGenerator메서드 통해서 쿼리 생성 -
SqlParamgersFactory필드의forQueryById메서드 통해서 쿼리 파라미터 생성 -
getEntityRowMapper메서드 통해RowMapper생성 -
operations: NamedParameterJdbcOperations필드의queryForObject메서드 통해서 쿼리 실행 (w/ rowMapper)-
converter: JdbcConverter필드의query메서드 호출 -
execute메서드 호출 -
DateSourceUtils.getConnection(DataSource)메서드 통해서Connection생성 -
doInPreparedStatement실행-
PreparedStatement#executeQuery메서드 통해서ResultSet생성-
update -
AbstractQueryProtocol#executeQuery -
ComQuery.sendSubCmd
-
-
-
쿼리 결과인
result생성
-
-
-
triggerAfterConvert메서드 실행
-
-
-
실제 DB로부터 어떻게 값이 오는지?
-
reading converter가 동작할 수 있는지?
-
spring batch에서 cursor는 어떻게?

