๐Ÿ•น Level 1. ์ฒด์Šค ๋ฏธ์…˜ ์ •๋ฆฌ - JDBC


JDBC (Java DataBase Connectivity)

JDBC๋Š” DB์— ์ ‘๊ทผํ•  ์ˆ˜ ์žˆ๋„๋ก Java์—์„œ ์ œ๊ณตํ•˜๋Š” API๋กœ, ๋ชจ๋“  Java์˜ Data Access ๊ธฐ์ˆ ์˜ ๊ทผ๊ฐ„์ด๋‹ค.
๋ชจ๋“  Persistence Framework๋Š” ๋‚ด๋ถ€์ ์œผ๋กœ JDBC API๋ฅผ ์ด์šฉํ•œ๋‹ค.

JDBC๋ฅผ ํ†ตํ•œ DB ์—ฐ๊ฒฐ

1. ๋“œ๋ผ์ด๋ฒ„ ๋กœ๋“œ

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

์ œ๊ณต๋˜๋Š” ํด๋ž˜์Šค๋ฅผ ์ธ์Šคํ„ด์Šคํ™”ํ•ด์„œ ๋‚ด๋ถ€์ ์œผ๋กœ ์ €์žฅํ•ด ๋ฉ”๋ชจ๋ฆฌ์— ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๊ฒŒํ•œ๋‹ค.
์ด ๋ฉ”์†Œ๋“œ๋ฅผ ํ†ตํ•ด ๋“œ๋ผ์ด๋ฒ„๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ์ดˆ๊ธฐํ™” ํ•œ๋‹ค.
์ƒ์„ฑ์ž๋ฅผ ํ†ตํ•œ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ๊ณผ ๊ฐ™๋‹ค๊ณ  ๋ณผ ์ˆ˜ ์žˆ๋‹ค.

2. Connection ๊ฐ์ฒด ์ƒ์„ฑ

DriverManager ํด๋ž˜์Šค๋Š” ๋“œ๋ผ์ด๋ฒ„๋ฅผ ํ†ตํ•ด Conection ๊ฐ์ฒด๋ฅผ ๋งŒ๋“ ๋‹ค.
Connection์€ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ๊ฐ์ฒด๋กœ DB์™€ ์—ฐ๊ฒฐํ•˜๋Š” ํ†ต๋กœ์ด๋ฉฐ, ์ด๋ฅผ ํ†ตํ•ด ์ฟผ๋ฆฌ๋ฅผ ์ „๋‹ฌํ•˜๊ณ  ๊ฒฐ๊ณผ๊ฐ’์„ ๋ฐ˜ํ™˜๋ฐ›๋Š”๋‹ค.

try {
  con = DriverManager.getConnection("jdbc:mysql://" + server + "/" + database + option, userName, password);
  System.out.println("์ •์ƒ์ ์œผ๋กœ ์—ฐ๊ฒฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.");
} catch (SQLException e) {
  System.err.println("์—ฐ๊ฒฐ ์˜ค๋ฅ˜:" + e.getMessage());
  e.printStackTrace();
}

3. Statement / PreparedStatement ๊ฐ์ฒด ์ƒ์„ฑ

Statement ๊ฐ์ฒด๋ฅผ ํ†ตํ•ด insert ์ฟผ๋ฆฌ๋ฅผ ์ž‘์„ฑํ•˜๋ฉด ์•„๋ž˜์™€ ๊ฐ™์ด ๊ฐ๊ฐ์˜ ๊ฐ’์„ ์ฝค๋งˆ์™€ ๋”ฐ์˜ดํ‘œ๋กœ ๊ตฌ๋ณ„ํ•ด์•ผํ•˜๊ธฐ ๋•Œ๋ฌธ์—
๊ฐ€๋…์„ฑ๋„ ๋–จ์–ด์ง€๊ณ  ์ž˜๋ชป ์ž…๋ ฅํ•  ํ™•๋ฅ ๋„ ์ปค์ง„๋‹ค.

statement = connection.createStatement();
String query = "INSERT INTO piece(color, name, position, chessGameId) VALUE ('" + color + "','" + name +  "','" + position + "','" + chessGameId "')";
resultCount = statement.executeUpdate(insertQuery);

PreparedStatement ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์†์„ฑ ๊ฐ’์„ ?๋กœ ์„ค์ •ํ•˜๊ณ  set์„ ํ†ตํ•ด ์„ค์ •ํ•˜๋ฉด, ์ž๋™์œผ๋กœ ์ฟผ๋ฆฌ๋ฅผ ์™„์„ฑ์‹œ์ผœ์ค€๋‹ค.

String query = "INSERT INTO piece(color, name, position, chessGameId) VALUE (?, ?, ?, ?)";
try (Connection connection = dbManager.getConnection();
     PreparedStatement pstmt = connection.prepareStatement(query)) {
  for (Piece piece : pieces) {
    pstmt.setString(1, piece.color().name());
    pstmt.setString(2, piece.name());
    pstmt.setString(3, piece.position().key());
    pstmt.setInt(4, chessGameId);
    pstmt.executeUpdate();
  }
} catch (SQLException e) {
  e.printStackTrace();
}
  • executeQuery() : select๋ฅผ ํ†ตํ•œ ์ •๋ณด๋ฅผ ์กฐํšŒํ•˜๊ณ , ์ฟผ๋ฆฌ๋ฅผ ์ „์†ก ํ›„ ๊ฒฐ๊ณผ ๊ฐ์ฒด ๋ฐ˜ํ™˜ํ•œ๋‹ค.
  • executeUpdate(String query) : Insert, Update, Delete ์ฟผ๋ฆฌ๋ฅผ ์ „์†กํ•˜๊ณ  ๋ณ€๊ฒฝ๋œ ๋ ˆ์ฝ”๋“œ ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค.

4. ResultSet ๊ฐ์ฒด ๋ฐ˜ํ™˜

ResultSet ๊ฐ์ฒด๋Š” select ์ฟผ๋ฆฌ์˜ ๊ฒฐ๊ณผ๊ฐ’์„ ๋ชจ๋‘ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” ๊ฐ์ฒด์ด๋‹ค.

while (rs.next()) {
                Piece piece = PieceFactory.findByInfo(rs.getString("color"),
                        rs.getString("name"), rs.getString("position"));
                pieces.add(piece);
            }
  • boolean next() : ๊ฒฐ๊ณผ ๋ ˆ์ฝ”๋“œ๊ฐ€ ์กด์žฌํ•˜๋ฉด true, ์—†์œผ๋ฉด false
  • boolean previous() : ์ด์ „ ๋ ˆ์ฝ”๋“œ๋กœ ์ด๋™ (๊ฐ€์žฅ ์ฒซ ํ–‰์ด๋ฉด false)
  • boolean first() : ์ฒ˜์Œ ์œ„์น˜๋กœ ์ด๋™ (๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด false)
  • boolean last() : ๋งˆ์ง€๋ง‰ ์œ„์น˜๋กœ ์ด๋™ (๋ ˆ์ฝ”๋“œ๊ฐ€ ์—†์œผ๋ฉด false)
  • String getString(String colLabel) : ํ˜„์žฌ ์ปค์„œ ์œ„์น˜์˜ ์ปฌ๋Ÿผ๋ช…์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜
  • int getInt(String colLabel) : ํ˜„์žฌ ์ปค์„œ ์œ„์น˜์˜ ์ปฌ๋Ÿผ๋ช…์— ํ•ด๋‹นํ•˜๋Š” ์ •์ˆ˜๊ฐ’ ๋ฐ˜ํ™˜
  • String getString(int colIndex) : ์ปฌ๋Ÿผ ์ธ๋ฑ์Šค์— ํ•ด๋‹นํ•˜๋Š” ๋ฌธ์ž์—ด ๋ฐ˜ํ™˜ (1๋ถ€ํ„ฐ ์‹œ์ž‘)
  • int getInt(int colIndex) : ์ปฌ๋Ÿผ ์ธํ…์Šค์— ํ•ด๋‹นํ•˜๋Š” ์ •์ˆ˜๊ฐ’ ๋ฐ˜ํ™˜ (1๋ถ€ํ„ฐ ์‹œ์ž‘)

5. ์ž์› ํ•ด์ œ

DB ๊ด€๋ จ ์ž‘์—…์„ ํ•˜๋ฉด์„œ Connection, Statement / PreparedStatement, ResultSet ๊ฐ์ฒด๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.
DB ๊ด€๋ จ ์ฒ˜๋ฆฌ ์ž‘์—…์ด ์™„๋ฃŒ๋˜์—ˆ๋‹ค๋ฉด, ์‚ฌ์šฉํ–ˆ๋˜ ๊ฐ์ฒด๋“ค์„ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ํ•ด์ œํ•ด์ฃผ์–ด์•ผ ํ•œ๋‹ค.
๋งŒ์•ฝ ํ•ด๋‹น ์ž์›๋“ค์„ ํ•ด์ œํ•ด์ฃผ์ง€ ์•Š์œผ๋ฉด ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๋ฌธ์ œ์ ์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.

  • Connection pool์„ ์‚ฌ์šฉํ•˜์ง€ ์•Š์€ ์ƒํƒœ์—์„œ Connection์„ ๋‹ซ์ง€ ์•Š์œผ๋ฉด DBMS์— ์—ฐ๊ฒฐ๋œ ์ƒˆ๋กœ์šด Connection์„ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.
  • Statement / PreparedStatement๋ฅผ ํ•ด์ œํ•˜์ง€ ์•Š์œผ๋ฉด, ์ƒ์„ฑ๋œ ๊ฐฏ์ˆ˜๊ฐ€ ์ฆ๊ฐ€ํ•˜๋ฉด์„œ ๋” ์ด์ƒ ์ƒˆ๋กœ์šด Statement / PreparedStatement๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์—†๋‹ค.

์ด๋ฒˆ ๋ฏธ์…˜์—์„œ๋Š” try-with-resource๋ฅผ ํ†ตํ•ด ์ž์› close ์ฒ˜๋ฆฌ ๊ฐœ์„ ์„ ํ•˜์˜€๋‹ค. ์ด๋Š” try ๋ธ”๋ก์˜ ์†Œ๊ด„ํ˜ธ ์•ˆ์—์„œ ์ž์› ํ•ด์ œ๊ฐ€ ํ•„์š”ํ•œ ๊ฐ์ฒด๋ฅผ ํ• ๋‹นํ•˜๋ฉด try catch ์ ˆ์ด ์ข…๋ฃŒ๋˜๋ฉด์„œ
์ž์› ํ•ด์ œ๊ฐ€ ํ•„์š”ํ•œ connection๊ณผ preparedstatement๋ฅผ ์ž๋™์œผ๋กœ close๋˜๋Š” try-catch ๋ฌธ์ด๋‹ค.
preparedstatement๋ฅผ ํ•ด์ œํ•˜๋ฉด ํ˜„์žฌ(๊ฐ€์žฅ ์ตœ๊ทผ์— ์ƒ์„ฑํ•œ) ResultSet๋„ ์ž๋™์œผ๋กœ ํ•ด์ œ๋œ๋‹ค.

public List<Piece> findAllByChessGameId(int chessGameId) {
  List<Piece> pieces = new ArrayList<>();
  String query = "SELECT color, name, position FROM piece WHERE chessGameId = ?";
  try (Connection connection = dbManager.getConnection();
       PreparedStatement pstmt = connection.prepareStatement(query)) {
    pstmt.setInt(1, chessGameId);
    ResultSet rs = pstmt.executeQuery();

    while (rs.next()) {
      Piece piece = PieceFactory.findByInfo(rs.getString("color"),
                                            rs.getString("name"), rs.getString("position"));
      pieces.add(piece);
    }
  } catch (SQLException e) {
    e.printStackTrace();
  }
  return pieces;
}

SQL Exception์— ๋Œ€ํ•˜์—ฌ

image

checked exception์ธ SQLException์— ๋Œ€ํ•ด ์–ด๋–ป๊ฒŒ ์ฒ˜๋ฆฌ๋ฅผ ํ• ์ง€ ๊ณ ๋ฏผํ•˜๋‹ค๊ฐ€ ๊ฒฐ๊ตญ ์™ธ๋ถ€๋กœ ๋˜์ ธ์ฃผ๊ธฐ๋งŒ ํ–ˆ์—ˆ๋‹ค.
ํœด์˜ ํ”ผ๋“œ๋ฐฑ๋Œ€๋กœ ์ง€๊ธˆ์€ DAO์—์„œ stacktrace๋งŒ ์ถœ๋ ฅํ•˜๋„๋ก ๋ณ€๊ฒฝํ•˜์˜€๋‹ค.
์ถ”ํ›„์— ํœด๊ฐ€ SQLException์— ๋Œ€ํ•œ ์ฐธ๊ณ  ์ž๋ฃŒ๋ฅผ ๋ณด๋‚ด์ฃผ์…จ๋‹ค.

[Toby spring] ์‚ฌ๋ผ์ง„ SQLException์— ๋”ฐ๋ฅด๋ฉด DAO์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์˜ˆ์™ธ๋ฅผ ๊ณ„์†ํ•ด์„œ ์™ธ๋ถ€๋กœ ๋˜์ ธ์ฃผ๋Š” ๊ฒƒ๋„ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์ด์ง€๋งŒ,
์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์˜ˆ์™ธ๊ฐ€ ๋ฐœ์ƒํ•œ DAO๋ฅผ ์‚ฌ์šฉํ•œ Service์—์„œ ์™œ SQLException์ด ๋ฐœ์ƒํ–ˆ๋Š”์ง€ ์•Œ ์ˆ˜ ์—†๊ธฐ ๋•Œ๋ฌธ์—
์•„๋ž˜์™€ ๊ฐ™์ด SQLException์„ ํฌ์žฅํ•œ ์˜ˆ์™ธ์˜ ์˜๋ฏธ๋ฅผ ๋‹ด์€ ์ปค์Šคํ…€ ์˜ˆ์™ธ๋ฅผ ๋งŒ๋“ค์–ด ๋˜์ ธ์ฃผ๋Š” ๊ฒƒ๋„ ํ•˜๋‚˜์˜ ๋ฐฉ๋ฒ•์ด ๋  ์ˆ˜ ์žˆ๋‹ค.
์ด๋ ‡๊ฒŒ ๋˜๋ฉด ์˜๋ฏธ๊ฐ€ ๋ถ„๋ช…ํ•œ ์˜ˆ์™ธ๋กœ ์ „๋‹ฌํ•ด์„œ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๊ฒŒ ๋œ๋‹ค.

try {
  //...
} catch (SQLException e) {
  throw DuplicatePieceIdException(e);
}

try {
  //...
} catch (SQLException e) {
  throw DuplicatePieceIdException().initCause(e);
}

๋˜ ์ž๋ฃŒ์— ๋”ฐ๋ฅด๋ฉด JDBCTemplate์„ ์‚ฌ์šฉํ•˜๋ฉด ์ด ๋‚ด๋ถ€์—์„œ SQLException์„ ์ฒ˜๋ฆฌํ•ด์ค€๋‹ค๊ณ  ํ•˜๋‹ˆ ์ฐจ์ฐจ ๊ฐœ๋…์„ ์•Œ์•„๊ฐ€์ž.

์ฐธ๊ณ  ์ž๋ฃŒ