1. JDBC 정의
- JDBC 또는 Java Database Connectivity는 데이터베이스와 쿼리를 연결하고 실행하기 위한 Java API
- JDBC 의 클래스와 인터페이스를 사용하면, 유저가 작성한 요청(쿼리문)을 지정된 데이타베이스에 송신할 수 있다.
- Java 데이터베이스 연결 표준을 갖춘 언어를 제공한다.
- Java는 표준 인터페이스인 JDBC API를 제공한다. (즉, 어떤 DBMS를 사용하더라도 똑같은 방식으로 다룰 수 있음 =(데이터 베이스 종류에 상관없다.)
- 자바를 이용한 DB 접속과 SQL 문장 실행, 실행 결과로 얻어진 데이터의 핸들링을 제공하는 방법과 절차에 관한 규약을 정의한다.
- 데이터베이스에 액세스하는 데 필요한 프로그램을 작성하는 데 사용된다.
1. JDBC 컴포넌트
JDBC에는 일반적으로 데이터베이스와 상호 작용할 수 있는4개의 주요 컴포넌트가 있다.
- JDBC API : 데이터베이스와 쉽게 통신할 수 있는 다양한 방법 및 인터페이스를 제공한다. (Java SE 및 Java EE 플랫폼에서 java.sql.* 를 제공한다) 데이터베이스를 클라이언트 응용 프로그램에 연결하기 위한 표준을 제공함.
- JDBC 드라이버 매니저: 데이터베이스와의 연결을 만들고, 데이타베이스 고유의 드라이버를 애플리케이션에 로드한다. 사용자 요청을 처리하기 위해 데이터베이스에 대한 데이터베이스 고유 호출에 사용한다.
- JDBC Test suite : JDBC 드라이버에 의해 수행되는 작업(삽입, 삭제, 업데이트 등)을 테스트하기 위해 사용된다.
- JDBC-ODBC Bridge Drivers : 데이터베이스 드라이버를 데이터베이스에 연결
2. JDBC 아키텍쳐
- Application :데이터 소스와 통신하는 Java applet 또는 서블릿이다.
- JDBC API: JDBC API를 사용하면 Java 프로그램이 SQL 문을 실행하고 결과를 가져올 수 있다. (JDBC API에 정의되어 있는 중요한 클래스 및 인터페이스는 다음 챕터에 설명)
- JDBC Driver Manager: JDBC 아키텍처에서 중요한 역할을 한다.일부 데이터베이스 고유 드라이버를 사용하여 엔터프라이즈 애플리케이션을 데이터베이스에 효과적으로 연결한다.
- JDBC Driver: JDBC를 통해 데이터 소스와 통신하려면 각 데이터 소스와 유연하게 통신하는 JDBC 드라이버가 필요하다.
3. JDBC API
JDBC API는 다음 인터페이스와 클래스로 구성된다.
Driver Manager
데이터베이스 드라이버 목록을 관리하는 클래스다.이 클래스는 데이터베이스에 따라 다를 수 있다.
Java 응용 프로그램의 연결 요청을 통신 하위 프로토콜을 사용하여 적절한 데이터베이스 드라이버와 일치시킨다.
Driver
JDBC 드라이버는 Java 응용 프로그램이 데이터베이스와 상호 작용할 수 있도록 하는 인터페이스이다.
다른 데이터베이스에 접속하려면 데이터베이스별로 JDBC 드라이버가 필요하다.
JDBC 드라이버는 데이터베이스에 접속하여 클라이언트와 데이터베이스 간에 쿼리 및 결과를 전송하기 위한 프로토콜을 구현한다.
Connection
Connection Interface는 데이터베이스에 접속하기 위한 다양한 방법으로 구성된다.
Statement
statement는 파싱되거나, 컴파일 또는 계획되거나(planned), 실행할 SQL 문을(데이터베이스로 전달될 SQL문) 캡슐화합니다.
Result Set
Result Set은 statement 개체를 사용하여 SQL(Structured Query Language) 쿼리를 실행할 때 데이터베이스에서 검색된 데이터를 유지한다. Result Set를 사용하여 데이터를 반복할 수 있다.
4. JDBC API - 인터페이스
JDBC인터페이스의 목록은 다음과 같다.
- Driver interface
- Connection interface
- Statement interface
- PreparedStatement interface
- CallableStatement interface
- ResultSet interface
- ResultSetMetaData interface
- DatabaseMetaData interface
- RowSet interface
5. JDBC API - 클래스
JDBC클래스의 목록은 다음과 같다.
- DriverManager class
- Blob class
- Clob class
- Types class
2. JDBC 사용 절차
JDBC 사용하는 절차를 요약하면 다음과 같다.
- import java.sql.*
- JDBC Driver Loading - Class.forName()
- DBMS Connection - Connection conn = DriverManager.getConnection()
- (Prepared)Statement - PreparedStatement pstmt = conn.prepareStatement();
- Execute the query - EX. pstmt.executeUpdate();
- Close all Object (Release Resource)
2-1. import java.sql.*
Connection, Result의 인터페이스를 사용하기 위해 import 해 주어야 한다.
위의 JDBC API 인터페이스, 클래스에 목록을 확인해보자.
JDBCtest.java
import java.sql.*;
2-2. Driver 로드
JDBC 프로그램을 위해 가장 먼저 해야할 것은 데이터베이스 작업을 위해 준비된 JDBC 드라이버 파일을 사용할 수 있도록 메모리에 로딩해야 한다.
본 포스팅에서 MySQL을 사용하여 자바와 연결할 것이다.
https://mvnrepository.com/artifact/mysql/mysql-connector-java
다음 링크에서 자바 드라이버를 다운 받아서 다음 문장을 사용하여 로드한다.
JDBCtest.java
try {
// 2. Driver Load
Class.forName("패키지경로.Driver");
System.out.println("Driver load success!");
} catch (ClassNotFoundException | SQLException e) {
...
}
/* 결과
Driver load success!
*/
JDBC 드라이버를 메모리에 동적으로 로딩하기 위해서는 Class.forName( )을 이용한다.
forName( ) 메소드의 인자값으로는 JDBC 드라이버 파일 안에서 드라이버 인터페이스를 상속하고 있는 클래스이름을 패키지 이름과 함께 정확하게 명시해주어야 한다.
Class.forName( )에 의해 JDBC 드라이버 파일의 드라이버 인터페이스를 상속한 클래스가 동적으로 로딩될 때 자동으로 JDBC 드라이버 인스턴스가 생성되어 준비가 완료된다.
그리고 DB에 테이블을 생성하자
testdb.sql
create database testdb;
use testdb;
create table employee(
emp_id int auto_increment,
emp_name varchar(40),
emp_address varchar(400),
primary key (emp_id)
);
select * from employee;
2-3. DBMS Connection객체 생성 (DBMS 서버 접속)
DB서버와의 연결작업을 해야한다. Connection객체를 얻어낼 때 DriverManager객체를 사용한다.
DriverManager 클래스의 getConnection( ) 메소드 실제 자바 프로그램과 데이터베이스를 네트워크상에서 연결한다.
인자 값은 다음과 같다.
- String url : 접속할 서버의 URL, 프로토콜, 서버주소,서버포트, DB이름으로 구성됨.
- String user : DB서버에 로그인할 계정
- String password : DB서버에 로그인할 비밀번호
연결에 성공하면 DB와 연결된 상태를 Connection 객체로 표현하여 반환한다.
JDBCtest.java
// 3. connection DBMS
String url = "jdbc:mysql://localhost:포트번호/데이터베이스이름?serverTimezone=UTC";
String id = "root";
String pw = "root";
Connection conn = DriverManager.getConnection(url, id, pw);
System.out.println("DBMS connection success!");
System.out.println("conn: "+ conn);
/* 결과
DBMS connection success!
conn: 패키지경로.ConnectionImpl@13a5fe33
*/
2-4. (Prepared) Statement
2-3 과정에서 DB사이에 연결이 완료되었으면 statement는 DB로 SQL문을 전송하고, DB의 처리된 결과를 전달받는 역할을 한다.
PreparedStatement는 다음과 같이 생성한다. (동적으로 값을 입력하지 않을 때)
JDBCtest.java
String sql = "insert into employee values (1, 'kim', 'seoul')";
PreparedStatement pstmt = conn.prepareStatement(sql);
동적으로 값을 입력하려면 다음과 같이 하면 된다.
JDBCtest.java
String sql = "insert into employee values (?, ?, ?)";
PreparedStatement pstmt = conn.prepareStatement(sql);
pstmt.setString(1, "2");
pstmt.setString(2, "park");
pstmt.setString(3, "jeju");
2-5. Execute the query (쿼리문 실행)
Statement 객체를 이용해 DB서버로 SQL문을 전송하고 처리 결과를 받아올 수 있다.
SQL문을 실행하기 위해 Statement 객체에서 제공되는 메서드는 다음과 같다.
- ResultSet executeQuery(String sql)
: executeQuery( ) 메소드가 반환하는 ResultSet은 select한 결과값을 가지고 있다. (select결과가 여러개일 수 있음) - int executeUpate(String sql)
executeUpdate( ) 메소드가 반환하는 숫자값은 SQL문이 실행된(update,delete,insert) 후 영향을 받은 레코드의 개수
앞에서 작성한 쿼리문으로 값을 동적으로 입력해보자.
JDBCtest.java
// 5. Execute the query
int count = pstmt.executeUpdate();
System.out.println("number of rows affected by this query= " + count);
/* 결과
number of rows affected by this query= 1
*/
이 상태에서 select문을 이용해 테이블의 내용을 출력하고자 한다.
ResultSet을 이용하여 결과를 출력해보자.
JDBCtest.java
String sql = "select * from employee";
PreparedStatement pstmt = conn.prepareStatement(sql);
ResultSet rs = pstmt.executeQuery(sql);
// 맨 마지막까지 반복하여 출력
while(rs.next()) {
System.out.println(rs.getInt("emp_id")+":"+rs.getString("emp_name")+":"+rs.getString("emp_address"));
}
ResulSet은 executeQuery( ) 메소드에서 실행된 select 문의 결과값을 가지고 있는 객체이다.
ResultSet 객체의 특징은 내부적으로 위치를 나타내는 커서(Cursor)라는 개념이 있다.
ResultSet 객체의 메소드들은 이 커서의 위치를 이동시킨다.
- void afterLast( ) : 커서를 끝 빈 행으로 위치시키는 메소드
- void beforeFirst( ) : 커서를 시작 빈행으로 위치시키는 메소드
- boolean next( ) :커서 다음에 레코드가 있는지 판단하여 없으면 false, 있으면 true를 반환하 다음에 커서를 다음 레코드로 이동
ResultSet 객체는 현재 이동한 커서의 컬럼의 값을 데이터 타입에 따라 추출하는 getter 메소드를 가지고 있다.
getter 메소드의 인자값으로 칼럼의 이름을 지정할 수 있고, 컬럼의 인덱스 값을 지정할 수도 있다.
컬럼의 인덱스는 ResultSet 결과값으로 나타난 컬럼의 순서이다.
2-6. 자원 해제
앞에서 DB관련 작업을 하면서 다음 객체들을 사용하였다. Connection, PreparedStatement, ResultSet 객체
사용했던 객체들을 메모리에서 해제해 주어야 한다. 해제하는 순서는 최근에 사용한 객체부터 해제한다.
- rs.close( )
- stme.close( ) 또는 pstmt.close( )
- conn.close( )
JDBCtest.java
// 6. release resources
rs.close();
pstmt.close();
conn.close();
전체 코드 첨부 - JDBCtest.java
package test;
// 1. import java,sql.*;
import java.sql.*;
public class JDBCtest {
public static void main(String[] args) {
try {
// 2. Driver Load
Class.forName("packagePath.Driver");
System.out.println("Driver load success!");
// 3. connection DBMS
String url = "jdbc:mysql://localhost:PORT/DB_NAME?serverTimezone=UTC";
String id = "root";
String pw = "root";
Connection conn = DriverManager.getConnection(url, id, pw);
System.out.println("DBMS connection success!");
System.out.println("conn: "+ conn);
// 4. Statement
// String sql = "insert into employee values (1, 'kim', 'seoul')";
// String sql = "insert into employee values (?, ?, ?)";
String sql = "select * from employee";
PreparedStatement pstmt = conn.prepareStatement(sql);
// pstmt.setString(1, "2");
// pstmt.setString(2, "park");
// pstmt.setString(3, "jeju");
// 5. Execute the query
// int count = pstmt.executeUpdate();
// System.out.println("number of rows affected by this query= " + count);
ResultSet rs = pstmt.executeQuery(sql);
while(rs.next()) {
System.out.println(rs.getInt("emp_id")+":"+
rs.getString("emp_name")+":"+
rs.getString("emp_address"));
}
// 6. release resources
rs.close();
pstmt.close();
conn.close();
} catch (ClassNotFoundException | SQLException e) {
e.printStackTrace();
}
}
}
출처 및 인용 (참고)