티스토리 뷰
1. JDBC (Java Database Connectivity)
- Java에서 DB와 연결하여 SQL 쿼리를 실행하고 결과를 처리할 수 있도록 도와주는 API
- 구성 요소 :: (1) JDBC API / (2) JDBC Driver
1.1 JDBC API
:: Java 애플리케이션과 DB 간의 상호작용을 위한 인터페이스 집합을 제공하는 API
구성 요소 | 내용 |
1.Connection (접속) | - DB 연결 관리 - Connection 객체는 DB에 대한 세션을 의미, 쿼리실행, 트랜젝션 관리 등 처리 1) createStatement() :: 쿼리를 실행할 Statement 객체를 생성 2) prepareStatement(String sql) :: 매개변수를 사용하는 쿼리를 실행하는 객체를 생성 3) commit() :: 트랜잭션을 커밋 4) rollback() :: 트랜잭션을 롤백 |
2. Statement (쿼리) | - SQL 쿼리를 DB에 전달하는 객체 / 단순한 SQL 쿼리를 실행 가능 1) executeQuery(String sql) :: SELECT 쿼리 실행 후 결과를 반환 2) executeUpdate(String sql) :: 삽입 / 갱신 / 삭제 등의 쿼리 실행 후, 영향을 받은 행의 개수를 반환 3) execute(String sql) :: SELECT와 INSERT, UPDATE, DELETE 등 다양한 종류의 SQL을 실행 |
3. PreparedStatement | - Statement와 유사 + SQL 쿼리의 성능을 최적화하고 보안을 강화하는 역할 - 매개변수를 사용하여 SQL 쿼리 실행 가능 1) setString(int parameterIndex, String value) :: SQL 쿼리에서 파라미터를 설정 2) executeQuery() :: 매개변수가 포함된 SELECT 쿼리를 실행 |
4. ResultSet (결과) | - 쿼리 실행 후 반환된 데이터를 처리하는 객체 - 테이블 형태의 데이터를 메모리 내에서 순차적으로 처리 1) next() :: 다음 행으로 이동하여 결과를 처리 2) getString(String columnName) :: 컬럼 값을 가져옴 |
5. SQLException | - JDBC에서 발생하는 예외를 처리하는 클래스 |
1.2 JDBC Driver
:: Java 애플리케이션이 DB와 통신할 수 있도록 지원하는 구현체
:: DB와 연결하고 SQL 명령을 실행하는데 필요한 물리적 연결을 제공 / 브리지 역할
드라이버 유형설명장점단점
드라이버 유형 | 설명 |
1. JDBC-ODBC 브리지 드라이버 | :: JDBC와 ODBC(구조적 쿼리 언어 호출)를 결합하여, :: JDBC 애플리케이션이 ODBC DB를 사용할 수 있도록 지원. 장) 쉽게 구성할 수 있으며, 오래된 시스템과 호환됨. 단) 성능이 느리고, 플랫폼 의존적이며, ODBC 드라이버가 필요. |
2. 네이티브 API 드라이버 | ::JDBC 애플리케이션이 DB에 직접 연결할 수 있도록 네이티브 API를 사용 Ex) MySQL, PostgreSQL 장) 성능이 뛰어나며, DB마다 최적화된 드라이버 제공. 단) 각 DB에 대해 별도의 드라이버가 필요. |
3. 네트워크 프로토콜 드라이버 | :: JDBC 애플리케이션이 네트워크 프로토콜을 사용하여 DB 서버와 연결 Ex) Oracle Thin Driver 장) 클라이언트와 서버 간의 효율적인 네트워크 연결 제공. 단) 네트워크 지연 및 장애에 취약할 수 있음. |
4. 데이터베이스 독립 드라이버 | :: JDBC 애플리케이션과 DB 간의 연결을 위해 DB 독립적인 API를 사용 장) DB에 의존하지 않음. 대부분의 DB에서 사용 가능. 단) 설정이 복잡할 수 있으며, 성능은 다른 드라이버들에 비해 떨어질 수 있음. |
2. JDBC 연결 흐름
(1) DB 연결 - (2) DB 조작 / 쿼리 실행 - (3) 결과 처리 및 리소스 해제
2.1 DB 연결 - JDBC Driver
- Java에서의 DB 접속은 물리적 접속 or 논리적 접속 중 하나 선택
- 물리적 접속 :: 매 접속때마다, DB에 직접 붙는것으로 Create/Close 반복
- 논리적 접속 :: 매 접속때마다, DB에 접속되어있는 Connection Pool 중 하나를 사용 후 반환하여 재사용
종류 | 내용 |
1. DriverManager | :: 물리적인 연결을 만들고 파기하는 방식 :: DB 연결을 설정할 때마다 직접적으로 새로운 Connection 객체를 create / 쿼리 수행 후 Close :: 여러 개의 연결을 각각 별도로 관리 - 많은 사용자의 동시처리 문제 발생 |
2. DataSource | :: 논리적인 연결을 관리 / Connection을 생성하는 역할 :: DB 연결을 미리 풀에 저장 후, DB 연결마다 Connection Pool 내 Connection을 빌려주는 방식 :: 방식은 이미 생성된 연결을 재사용하기 때문에 성능적으로 더 효율적이고, 자원 낭비를 줄임 |
- 주의 :: DataSource 구현체에 따라 어떤건 자체 Connection Pool 을 갖고, 어떤건 갖고있지 않음 - Spring Boot 2+ 부터 DataSource 표준은 HikariCP(Connection Pool) |
|
- connection를 재사용하기 때문에 최대 커넥션의 수를 제한적으로 설정 가능 - Connection Pool 내 사용가능한 Connection이 없을 경우, 순서대로 대기 - 성능적인 부분을 고려할 때, 최대 커넥션 수는 WAS Thread 수 고려 => 사용되지 않 DB Connection 은 실질적으로 메모리 공간만 차지하게 되기 때문 |
1. DriverManager의 예시
// 1) 접속과 동시에 Connection 을 반환하는 코드
// 각 DBMS 업체마다 DriverManager 에 맞는 Driver 구현하여 제공 (MySQL, PostgresQL 등
Connection connection = DriverManager.getConnection(URL, USER, PASSWORD);
// JDBC API 는 3개로 구성되어있다 = Connection 접속 → Statement 쿼리 → ResultSet 결과
// 이 중 Connection 접속 시 DriverManager 사용하면 물리적 접속(Create-Close 반복)
Connection connection = DriverManager.getConnection(url, username, password); // 물리적 연결
Statement statement = connection.createStatement(); // 객체
ResultSet resultSet = statement.executeQuery("SELECT * FROM \"user\" WHERE id = " + userId); //결과
if (resultSet.next()) {
return new User(
resultSet.getInt("id"),
resultSet.getString("name"),
resultSet.getInt("age"),
resultSet.getString("job"),
resultSet.getString("specialty"),
resultSet.getDate("createdAt")
.toInstant()
.atZone(ZoneId.systemDefault())
.toLocalDateTime()
);
}
2. DataSource
// 0.1) DataSource 설정
// Spring Boot 2+ 부터 DataSource 표준은 HikariCP(Connection Pool)
HikariConfig config = new HikariConfig();
config.setJdbcUrl(URL);
config.setUsername(USER);
config.setPassword(PASSWORD);
config.setDriverClassName("com.mysql.cj.jdbc.Driver");
config.setMaximumPoolSize(20); // Connection Pool 최대 커넥션 수 설정
config.setMinimumIdle(10); // 사용을 위해 커넥션 풀에 유지해놓을 커넥션 수 (IDLE)
// 0.1) DataSource 생성
HikariDataSource hikariDataSource = new HikariDataSource(config);
// 1) 접속을 Connection Pool 에서 가져오는 코드
Connection connection = hikariDataSource.getConnection();
2.2 DB 조작 : JDBC APIs
:: JDBC는 DB 접속 / 쿼리 / 결과에 대한 명세(API)를 제공.
:: Spring 에서 학습했던 DAO의 개념에 매핑
2.2-1 DAO(Data Access Object) 패턴
:: DB와의 상호작용을 캡슐화하여 비즈니스 로직과 데이터베이스 구현을 분리하는 설계 패턴
:: DB에 대한 접근을 관리하는 객체인 DAO를 통해 모든 DB의 연산(CRUD) 처리
:: DAO는 JDBC를 사용하여 DB에 접근하고, 비즈니스 로직에 맞는 데이터를 반환 / 저장하는 역할
- JDBC API 는 3개로 구성되어있다 = Connection 접속 → Statement 쿼리 → ResultSet 결과
1. Connection 인터페이스
:: DB 연결 관리 객체 (앞선 JDBC Driver 통해 취득 - DriverManager / DataSource)
:: 트랜잭션 처리를 위해 Auto-Commit 기능을 제공(기본적으로 true로 설정, 각 SQL 쿼리 실행 후 자동 커밋)
Connection connection = DriverManager.getConnection(dbUrl, dbUser, dbPassword);
connection.setAutoCommit(false); // Auto-Commit 비활성화
// SQL 쿼리 실행 - Auto-Commit 비활성화일 때, 직접 설정 필요
connection.commit(); // 트랜잭션 커밋
connection.rollback(); // 트랜잭션 롤백
2. Statement 인터페이스
:: DB에 쿼리 전송 및 실행
인터페이스의 종류 | 내용 |
1. Statement: | - 기본적인 SQL 쿼리를 실행할 때 사용 - 쿼리문에 파라미터를 동적으로 삽입X - SQL 인젝션 등의 보안 위험 |
2. PreparedStatement: | - 파라미터 바인딩을 사용 / 파라미터가 쿼리의 일부분으로 자동 처리 - 작은 따옴표 및 기타 특수문자를 변환 (Java 이스케이핑) - string-concatenating 기법인 SQL 인젝션 방어에 유리 - SQL 구문에 대한 실행 계획을 캐싱하여, 동일한 구문이 반복될 때 더 빠르게 실행 |
3. CallableStatement: | - 주로 저장 프로시저를 호출할 때 사용 - 저장 프로시저 :: DB에 저장된 자주 사용하는 쿼리 / 로직의 코드 블록 |
예시
1. Statement
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM users WHERE name = '" + userName + "'");
2. PreparedStatement
// 문제 발생) name 변수에 “' OR 1=1 AND 'a'='a” 입력 시 모든 MEMBER 결과 조회
String name = “' OR 1=1 AND 'a'='a”;
String query = "SELECT * FROM MEMBER WHERE NAME = '" + name + "'";
// 해결)PreparedStatement를 사용하여, 내부적으로 이스케이핑 수행 후 값 주입
String prepareStatement = "SELECT * FROM MEMBER WHERE NAME = ?";
PreparedStatement preparedStatement = connection.prepareStatement(prepareStatement);
preparedStatement.setString(1, loginName);
3. CallableStatement
String sql = "{call getUserById(?)}";
CallableStatement stmt = connection.prepareCall(sql);
stmt.setInt(1, userId);
ResultSet rs = stmt.executeQuery();
3. ResultSet 인터페이스
:: 쿼리 실행 결과를 담고 있는 객체로, DB 쿼리의 결과 데이터를 행(row) 단위로 처리
ResultSet 주요 메서드 | 내용 |
next() | - 기본적으로 첫 번째 행 포인트 - 결과셋에서 다음 행으로 이동 |
getString() / getInt() / getDate() | - 결과 행의 특정 컬럼에 접근하여 데이터 read |
String sql = "SELECT id, name FROM users";
Statement stmt = connection.createStatement();
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
int id = rs.getInt("id");
String name = rs.getString("name");
System.out.println(id + ": " + name);
}
참조
ASAC 수업자료
'정리용 > DB' 카테고리의 다른 글
[DB 기초] 7. 트랜잭션 - 동기화와 추상화 (0) | 2025.03.24 |
---|---|
[DB 기초] 6-2. JDBC Template (0) | 2025.03.19 |
[DB 기초] 6. DB 설정 및 연결 (0) | 2025.03.19 |
[DB 기초] 5. 인덱스 (0) | 2025.03.18 |
[DB 기초] 3-1. DB 동시성 제어 기법(Pessimistic / Optimistic Lock) (0) | 2025.03.11 |
- Total
- Today
- Yesterday
- useReducer
- acac
- asac7
- useContext
- useRef
- asac#asac7기
- asac7#asac
- git
- memo
- Nginx
- ASAC
- useMemo
- useState
- useLayoutEffect
- react
- acas#acas7기
- ssh
- asac7기
- useEffect
- useCallback
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |