IT·테크/개발

Java JDBC — 드라이버 로드부터 Statement·PreparedStatement·ResultSet까지

레루루 2026. 7. 28. 21:42
반응형

이 글은 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

둘 중 하나만 쓸 수 있는 것은 아닙니다

StatementPreparedStatement는 서로의 영역을 침범할 수 있습니다. 다만 침범할 때마다 대가가 있습니다.

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 호출을 위한 객체입니다.

반응형