이 글은 2022년 5월 기준 기록입니다.
DBMS는 제품마다 다릅니다. 그런데 자바 코드는 어느 DB에 붙든 비슷하게 생겼습니다. 그 사이를 메우는 것이 JDBC입니다.
JDBC는 DBMS마다 다른 것을 하나의 인터페이스로 가립니다
JDBC는 자바에서 다양한 DBMS와 연결하기 위한 인터페이스를 제공합니다. 실제 연결을 수행하는 구현체는 자바가 만들지 않습니다. 각 DBMS 개발 업체에서 해당 인터페이스에 대한 구현체로 드라이버를 제공합니다.

응용 프로그램은 JDBC 인터페이스만 바라보고, 그 뒤에서 오라클 드라이버·MySQL 드라이버·MSSQL 드라이버가 각자의 데이터베이스로 연결을 이어 줍니다. 붙일 DB가 바뀌어도 응용 프로그램이 상대하는 면은 그대로라는 뜻입니다.
접속 정보는 코드가 아니라 properties 파일에 둡니다
드라이버 클래스를 로드하고 Connection 객체를 얻는 과정은 다음과 같습니다.
public static Connection getConnection() {
// conn 객체가 참조하는 값이 없으면 생성
if (conn == null) {
try {
// DB 접속 정보(DRIVER, URL, USER, PASSWORD)가 담긴 properties 파일 사용
Properties prop = new Properties();
File file = new File("src/prop/mysql.properties");
// properties 파일 내용 가져오기
prop.load(new FileReader(file));
String driver = prop.getProperty("driver");
String url = prop.getProperty("url");
String user = prop.getProperty("user");
String password = prop.getProperty("password");
// 클래스 로드(하지 않아도 자동으로 하지만, 하는 것을 권장)
Class.forName(driver);
// 드라이버 매니저로 Connection 객체 생성
conn = DriverManager.getConnection(url, user, password);
} catch (Exception e) {
e.printStackTrace();
}
}
return conn;
}
접속 정보 네 가지는 별도의 properties 파일에 둡니다.
driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://DB서버아이피:포트/DB이름
user=계정명
password=비밀번호
Class.forName(driver)로 드라이버 클래스를 로드하는 부분은 하지 않아도 자동으로 처리되지만, 명시적으로 하는 것을 권장합니다. 그다음 DriverManager.getConnection(url, user, password)가 실제 Connection 객체를 만들어 냅니다.
드라이버 이름을 적을 때 주의할 점이 있습니다. com.mysql.jdbc.Driver는 구버전 연결을 위한 드라이버로 Deprecated 되었습니다. com.mysql.cj.jdbc.Driver 사용이 권장됩니다.
정적 쿼리는 Statement로 보냅니다
연결을 얻었으면 쿼리를 실행할 차례입니다. Statement 객체는 정적인 쿼리에 사용합니다.
Statement createStatement() throws SQLException
Statement가 제공하는 메소드는 세 가지입니다.
| 메소드 | 반환 유형 | 설명 |
|---|---|---|
executeQuery(String sql) |
ResultSet |
SELECT 문을 실행할 때 사용합니다(ResultSet 객체 반환). |
executeUpdate(String sql) |
int |
삽입, 수정, 삭제와 관련된 SQL 문 실행에 사용합니다. |
close() |
void |
Statement 객체를 반환할 때 사용합니다. |
읽기는 executeQuery, 쓰기는 executeUpdate로 나뉘고 반환 타입도 다릅니다.
동적 쿼리는 PreparedStatement로 자리를 비워 둡니다
PreparedStatement 객체는 동적인 쿼리에 사용합니다. 방식이 다릅니다. 변할 수 있는 값에 ?로 쿼리를 작성하여 Prepared로 실행 계획을 작성한 후 대기시킵니다.
PreparedStatement prepareStatement(String sql) throws SQLException
이후 setXxx() 메소드를 사용해 ?의 빈 값에 변경 값을 전달하고 execute- 메소드로 실행합니다. setXxx() 계열은 필드 유형에 따라 갈립니다.
| 메소드 | 반환 유형 | 설명 |
|---|---|---|
setString(int parameterIndex, String x) |
void |
필드 유형이 문자열인 경우 |
setInt(int parameterIndex, int x) |
void |
필드 유형이 정수형인 경우 |
setLong(int parameterIndex, long x) |
void |
필드 유형이 정수형인 경우 |
setDouble(int parameterIndex, double x) |
void |
필드 유형이 실수형인 경우 |
setFloat(int parameterIndex, float x) |
void |
필드 유형이 실수형인 경우 |
setObject(int parameterIndex, Object x) |
void |
필드 유형이 객체형인 경우 |
setDate(int parameterIndex, Date x) |
void |
필드 유형이 날짜형인 경우 |
setTimestamp(int parameterIndex, Timestamp x) |
void |
필드 유형이 시간형인 경우 |
실행 메소드의 구성은 Statement와 같습니다.
| 메소드 | 반환 유형 | 설명 |
|---|---|---|
executeQuery() |
ResultSet |
SELECT 문을 실행할 때 사용합니다(ResultSet 객체 반환). |
executeUpdate() |
int |
삽입, 수정, 삭제와 관련된 SQL 문 실행에 사용합니다. |
close() |
void |
객체를 반환할 때 사용합니다. |
차이는 인자에 있습니다. Statement는 실행할 때 SQL 문자열을 넘기고, PreparedStatement는 이미 SQL을 들고 있으므로 넘기지 않습니다.
// Statement 객체를 사용하는 경우
ResultSet executeQuery(String sql) throws SQLException
// PreparedStatement 객체를 사용하는 경우
ResultSet executeQuery() throws SQLException
둘 중 하나만 쓸 수 있는 것은 아닙니다
Statement와 PreparedStatement는 서로의 영역을 침범할 수 있습니다. 다만 침범할 때마다 대가가 있습니다.
Statement 객체로도 동적 쿼리를 사용할 수 있습니다. 그러나 Statement는 쿼리 자체를 작성해서 문자열로 전달한 후 실행시키는 방식이라, 동적 쿼리에 사용할 경우 SQL Injection 등 보안적인 위험성이 존재합니다.
반대로 PreparedStatement 객체로도 정적 쿼리를 사용할 수 있습니다. 다만 정적 쿼리를 사용할 때는 Statement가 성능상 이점이 있습니다.
정리하면 동적이면 PreparedStatement, 정적이면 Statement가 기본 선택이고, 그중에서도 보안 쪽 위험이 훨씬 무겁습니다.
ResultSet은 커서를 움직이며 결과를 훑습니다
ResultSet 객체는 SELECT 쿼리에 대한 결과 레코드들을 테이블 형태로 가진 객체입니다. 값을 꺼내려면 커서를 움직여 가며 행을 읽습니다.
| 메소드 | 반환 유형 | 설명 |
|---|---|---|
getXxx(int ColumnIndex) |
XXX |
설정한 ColumnIndex(필드 순번)의 필드 값을 설정한 XXX 형으로 가져옵니다. |
getXxx(String ColumnName) |
XXX |
설정한 ColumnName의 필드 값을 설정한 XXX 형으로 가져옵니다. |
absolute(int row) |
boolean |
설정한 row 행으로 커서를 이동합니다. |
beforeFirst() |
void |
첫 번째 행의 이전으로 커서를 이동합니다. |
afterLast() |
void |
마지막 행의 다음으로 커서를 이동합니다. |
first() |
void |
첫 번째 행으로 커서를 이동합니다. |
last() |
void |
마지막 행으로 커서를 이동합니다. |
next() |
boolean |
다음 행으로 커서를 이동합니다. |
previous() |
boolean |
현재 행의 이전 행으로 커서를 이동합니다. |
close() |
void |
ResultSet 객체를 반환할 때 사용합니다. |
next()가 boolean을 반환한다는 점이 반복 처리의 열쇠입니다. 더 읽을 행이 있는지를 이동과 동시에 알려 주므로 반복문 조건에 그대로 쓸 수 있습니다.
저장 프로시저는 CallableStatement로 호출합니다
마지막으로 CallableStatement가 있습니다. Stored Procedure 호출을 위한 객체입니다.
'IT·테크 > 개발' 카테고리의 다른 글
| Java 멀티 스레드 — Thread와 Runnable로 작업 만들고 synchronized로 지키기 (0) | 2026.07.28 |
|---|---|
| Java 입출력 — 바이트·문자 스트림과 보조 스트림으로 기능 얹기 (0) | 2026.07.28 |
| Java 컬렉션 프레임워크 — List·Set·Map의 갈래와 Comparable·Comparator (0) | 2026.07.28 |
| Java 예외 처리 — 일반 예외와 실행 예외를 가르는 기준 (0) | 2026.07.27 |
| Java Wrapper 클래스 — 기본 타입을 객체로 다루는 박싱과 언박싱 (0) | 2026.07.26 |