TECH/웹개발

JDBC 노가다 탈출! Apache QueryRunner 완벽 가이드

런코리치 2026. 3. 14. 22:53

QueryRunner: JDBC의 복잡함을 덜어주는 효율적인 유틸리티

안녕하세요! 오늘은 자바 데이터베이스 프로그래밍을 할 때 JDBC(Java Database Connectivity)의 번거로운 반복 작업을 획기적으로 줄여주는 Apache Commons DBUtils 라이브러리의 핵심 클래스, QueryRunner에 대해 상세히 알아보겠습니다. 많은 방법들이 있겠지만 이번엔 QueryRunner를 활용하여 작업하는 방법을 볼 것입니다.


1. QueryRunner란 무엇인가?

QueryRunner는 이름 그대로 SQL 쿼리 실행을 도와주는 실행기입니다. 순수 JDBC를 사용할 때 발생하는 Connection 생성, PreparedStatement 설정, ResultSet 처리, 그리고 마지막 close() 호출까지 이어지는 이른바 '상용구 코드(Boilerplate Code)'를 대신 처리해 줍니다.

주요 특징:

  • 리소스 관리 자동화: Statement와 ResultSet의 관리를 내부적으로 처리하여 리소스 누수를 방지합니다.
  • 간결함: 수십 줄의 JDBC 코드를 단 몇 줄로 줄여줍니다.
  • Bean 매핑: 쿼리 결과를 자바 객체(POJO)로 즉시 변환해 주는 Handler 기능을 제공합니다.

2. 핵심 메서드 분석

QueryRunner는 크게 세 가지 형태의 작업을 수행합니다.

① update(): 데이터 변경

INSERT, UPDATE, DELETE 쿼리를 실행할 때 사용합니다.

  • 반환값: 영향받은 행(row)의 개수 (int)
  • 사용 예: queryRunner.update(conn, sql, params...);

② query(): 데이터 조회

SELECT 쿼리를 실행할 때 사용하며, 결과를 어떻게 받을지 결정하는 ResultSetHandler가 반드시 필요합니다.

  • 반환값: Handler가 정의한 타입 (객체, 리스트, Map 등)
  • 사용 예: queryRunner.query(conn, sql, handler, params...);

③ batch(): 일괄 처리

동일한 SQL을 여러 번 실행해야 할 때(Bulk Insert 등) 성능 최적화를 위해 사용합니다.


3. ResultSetHandler: 결과 처리의 핵심

QueryRunner의 진가는 다양한 Handler 제공에 있습니다. 쿼리 결과를 어떤 형태로 받을지 선택만 하면 됩니다.

Handler 클래스 설명
BeanHandler 단일 행을 특정 자바 객체(Bean)로 변환
BeanListHandler 여러 행을 자바 객체 리스트(List<Bean>)로 변환
MapHandler 첫 번째 행을 Map<String, Object> 형태로 변환
ScalarHandler COUNT(*)나 MAX() 같은 단일 컬럼 값을 반환
ArrayListHandler 각 행을 Object[] 배열로 변환하여 리스트로 반환

4. 실제 사용 예시 (코드 가이드)

프로젝트에 commons-dbutils 의존성을 추가한 후, 다음과 같이 코드를 작성할 수 있습니다.

[SELECT 예시: 리스트 조회]

Java
 
QueryRunner run = new QueryRunner();
String sql = "SELECT * FROM users WHERE status = ?";

// BeanListHandler를 사용하여 User 객체 리스트로 바로 받기
List<User> userList = run.query(conn, sql, new BeanListHandler<>(User.class), "ACTIVE");

[INSERT 예시]

Java
 
String insertSql = "INSERT INTO users (name, email) VALUES (?, ?)";
int rows = run.update(conn, insertSql, "홍길동", "hong@example.com");

5. 주의사항 및 Tip

  1. Connection 관리: QueryRunner는 DataSource를 인자로 받아 생성할 수도 있고, 메서드 호출 시마다 Connection을 직접 넘길 수도 있습니다. 트랜잭션 관리가 필요하다면 동일한 Connection을 메서드 파라미터로 전달하는 방식을 권장합니다.
  2. 가독성 vs 제어권: MyBatis나 JPA 같은 무거운 프레임워크를 쓰기에는 프로젝트 규모가 작거나, SQL의 세밀한 제어가 필요할 때 QueryRunner는 최고의 선택지가 됩니다.
  3. DB 컬럼명과 필드명: BeanHandler 계열을 사용할 때는 DB의 컬럼명(snake_case)과 자바 객체의 필드명(camelCase)이 일치하거나 적절히 매핑되도록 확인해야 합니다.

 

QueryRunner는 "최소한의 코드로 최대한의 JDBC 효율"을 내고자 할 때 가장 빛나는 도구입니다. 복잡한 설정 없이 라이브러리 추가만으로 즉시 생산성을 높일 수 있다는 점이 가장 큰 매력입니다.

작성하신 코드에서 반복되는 try-catch-finally와 ResultSet 노다가에 지쳤다면, 지금 바로 도입해 보시는 건 어떨까요?

다음엔 일하거나 공부하며 궁금한 점이나 알아야 할 것에 대해 작성하도록 할 예정입니다. 감사합니다.