본문 바로가기
우아한테크코스 4기/레벨1

[Java] JDBC API Statement vs PreparedStatement

by 나는후니 2022. 3. 29.

오늘 제이슨의 수업에서 mysql을 docker container에 올려 실행하는 방법과 간단한 jdbc api 사용법, sql 문법에 대해 배웠습니다. 수업 진행 중 제이슨이 "Statement 와 PreparedStatement가 있는데 차이는 누가 블로그에 올리겠죠." 라고 했고 저는 이 블로그 각을 놓칠 수 없었습니다.

 

옛날에 JDBC를 공부하던 때의 기억을 되살려 한 번 Statement vs PreparedStatement를 비교하여 포스팅을 해보고자 합니다.

원문은 baeldung 에서 확인할 수 있고 이 포스팅은 원문을 조금 이해하기 쉽게 설명하고자 합니다..

Statement vs PreparedStatement

JDBC API에는 두가지 인터페이스가 존재합니다. (인터페이스의 구현체는 아마도 각 rdbms 벤더사 class에 있을 가능성이 높아요 .. 아닐지도 ㅋ)

  1. Statement
  2. PreparedStatement

위 두 인터페이스는 SQL query를 실행하는 데 사용하지만 전혀 다른 기능을 갖고 있습니다.
차이점은 doc에 나와있는 설명에서부터 확인할 수 있는데요. 두 Interface를 생성하는 Connection docs 로 이동해봅시다.

위 두 사진의 내용을 간단히 해석해보면 SQL query를 db에 보내기 위한 객체를 생성한다고 말하지만 PreparedStatement는 조금 다릅니다."매개변수가 있는" 이라는 단어가 존재하죠.

 

그렇다면 사용법에서 어떤 차이를 보이는지 살펴보면서 장단점을 알아보겠습니다..

Statement

public class MemberDao {

    public void insert(final Member member) {
        Connection connection = JdbcTemplate.getConnection();
        String sql = "insert into member (id,name) values (\'" + member.getId() + "\', \'" + member.getName() + "\');";
        try {
            Statement statement = connection.createStatement();
            statement.executeUpdate(sql);
            connection.commit();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
}

위 코드에서 볼 수 있듯, String 문자열에 직접 원하는 데이터를 넣어야 합니다.
이는 코드의 가독성 을 떨어트림과 동시에 유지보수, 코드 작성에도 치명적인 단점을 보입니다.

이런 Statement의 쿼리 생성 방법으로 인해 SQLInjection에도 취약하다고 하는데요.

 

만약 코드를 실행하는 시점에 아래와 같은 argument가 입력됐다고 가정하겠습니다.

memberDao.insert(new Member("1", "jaehun' --"));

statement 객체는 sql query를 생성할 때 ' 를 탈출하지 못하고 게다가 --로 인해 이후 모든 sql 명령어가 주석으로 처리됩니다.

하지만 CREATE, ALTER 등 DDL을 사용할 때는 Statement 인터페이스를 사용하는 것도 효과적이라고 합니다.

PreparedStatement

public class MemberDao {

    public void insert(final Member member) {
        Connection connection = JdbcTemplate.getConnection();
        String sql = "insert into member (id,name) values (?, ?);";
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            preparedStatement.setString(1, member.getId());
            preparedStatement.setString(2, member.getName());
            preparedStatement.executeUpdate();
            connection.commit();
        } catch (SQLException e) {
            System.out.println(e);
        }
    }
}

Statement를 상속받은 PreparedStatement는 벌써부터 보기 편합니다.
가독성이 좋고 당연히 유지보수 및 이해에도 좋습니다.

게다가 Statement에서 발생한 SQL Injection 문제에도 안전합니다.
PreparedStatement는 쿼리를 생성할 때 setString 하는 시점에 엥간한 기호는 escape해준다고 보면 됩니다.

그래서 무엇을 쓸꼬?

상황에 따라 다릅니다. DDL 문법은 간단하게 Statement 인터페이스를 쓸 수 있습니다.
하지만 일반적인 DML 쿼리를 작성할 때는 PreparedStatement 인터페이스의 사용을 추천합니다.
게다가 PreparedStatement 인터페이스는 바이너리 프로토콜을 이용하여 패킷의 데이터를 줄임으로써 JVM과 db간의 통신 속도를 개선해줍니다.

마무리

더 많은 차이점이 있지만 요정도만 알아도 충분히 둘을 사용하는 상황을 구분하여 쓸 수 있을 것 같습니다.
즐거운 JDBC 사용을 해보아요~!