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, ์์ผ๋ฉด falseboolean 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์ ๋ํ์ฌ

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์ ์ฒ๋ฆฌํด์ค๋ค๊ณ ํ๋ ์ฐจ์ฐจ ๊ฐ๋ ์ ์์๊ฐ์.