[Spring] JDBCTemplate 정리

Zoe·2022년 1월 27일
0

Spring

목록 보기
7/9
post-thumbnail

JDBCTemplate 정리


✅ JDBCTemplate의 위치와 역할

  • JDBCTemplate : GoF 디자인 패턴 중 템플릿 메소드 패턴이 적용된 클래스

  • 템플릿 메소드 패턴: 복잡하고 반복되는 알고리즘을 캡슐화하여 재사용하는 패턴

  • JDBC처럼 코딩 순서가 정형화된 기술에서 유용하게 사용할 수 있음

  • 반복되는 DB 연동 로직JdbcTemplate 클래스의 템플릿 메소드가 제공하고, 개발자는 달라지는 SQL 구문과 설정값만 신경 쓰면 됨

  • JDBCTemplate : JDBC의 반복적인 코드를 제거하기 위해 제공하는 클래스

  • DAO 클래스에서는 JDBCTemplate 클래스가 제공하는 템플릿 메소드를 호출하여 DB 연동을 간단하게 처리함

  • JDBCTemplate 클래스는 내부적으로 JDBC API를 이용하여 실제 DB 연동 작업을 처리함

  • 개발자는 JDBCTemplate 클래스가 어떻게 JDBC API를 이용하는지는 신경 쓸 필요가 없음

public class PieceDao() {
    public Connection connection() {
        Connection connection = null;
        String server = "localhost:13306";
        String database = "db_name";
        String option = "?useSSL=false&serverTimezone=UTC&useUnicode=true&characterEncoding=utf8";
        String userName = "root";
        String password = "root";

        try {
            Class.forName("com.mysql.cj.jdbc.Driver");
        } catch (ClassNotFoundException e) {
            System.err.println(" !! JDBC Driver load 오류: " + e.getMessage());
            e.printStackTrace();
        }

        try {
            connection = DriverManager
                .getConnection("jdbc:mysql://" + server + "/" + database + option, userName,
                               password);
        } catch (SQLException e) {
            System.err.println("연결 오류:" + e.getMessage());
            e.printStackTrace();
        }

        return connection;
    }

    public void closeConnection(Connection connection) {
        try {
            if (connection != null) {
                connection.close();
            }
        } catch (SQLException e) {
            System.err.println("con 오류:" + e.getMessage());
        }
    }

    protected void disconnect(PreparedStatement preparedStatement, ResultSet resultSet) throws SQLException {
        if (!Objects.isNull(preparedStatement)) {
            preparedStatement.close();
        }
        if (!Objects.isNull(resultSet)) {
            resultSet.close();
        }
    }

    public void addPieces(final int boardId, final Map<Position, Piece> pieces) throws SQLException {
        Connection connection = connection();
        PreparedStatement preparedStatement = null;
        connection.setAutoCommit(false);
        try {
            for (Piece piece : pieces.values()) {
                if (Objects.isNull(piece)) {
                    continue;
                }
                String query = "INSERT INTO piece(board_id, piece_position, piece_symbol) VALUES (?, ?, ?)";
                preparedStatement = connection.prepareStatement(query);
                addPieceDataInit(boardId, preparedStatement, piece);
                preparedStatement.executeUpdate();
                preparedStatement.close();
            }
        } finally {
            disconnect(preparedStatement, null);
            closeConnection(connection);
        }
    }

    private void addPieceDataInit(final int boardId, final PreparedStatement preparedStatement,
        final Piece piece) throws SQLException {
        preparedStatement.setInt(1, boardId);
        preparedStatement.setString(2, piece.position().changedPositionToString());
        preparedStatement.setString(3, piece.symbol());
    }
}
  • 이 코드는 체스게임에서 말들의 정보를 저장하기 위한 코드

  • JDBC로 작성하면 위와 같이 길어지는 부분

  • 이러한 코드를 JdbcTemplate으로 바꾸면 아래와 같아짐

@Repository
public class PieceDao {
    private final JdbcTemplate jdbcTemplate;

    public PieceDao(final JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public void addPieces(long boardId, Map<Position, Piece> pieces) {
        String sql = "INSERT INTO piece(board_id, piece_position, piece_symbol) VALUES (?, ?, ?)";
        List<Position> positions = new ArrayList<>(pieces.keySet());
        jdbcTemplate.batchUpdate(sql, new BatchPreparedStatementSetter() {
            @Override
            public void setValues(PreparedStatement preparedStatement, int i) throws SQLException {
                Piece piece = pieces.get(positions.get(i));
                preparedStatement.setInt(1, boardId);
                preparedStatement.setString(2, piece.position().changedPositionToString());
                preparedStatement.setString(3, piece.symbol());
            }

            @Override
            public int getBatchSize() {
                return pieces.size();
            }
        });
    }
}
  • 속도를 위한 BatchUpdate를 적용. 불필요한 처리작업이 사라져 코드가 간결
  • Connection으로 연결하기
  • 쿼리를 작성 후 PreparedStatement로 실행하기
  • resultSet을 이용하여 결과 처리하기
  • Connection 닫아주기
  • 위의 과정들을 알아서 해줌
profile
iOS 개발자😺

0개의 댓글