#19 JDBC
by JiwonDev# JDBC? (Java Database Connectivity)
Java ์ฝ๋์์ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ์ ๊ณตํด์ฃผ๋ API. ์ฐธ๊ณ ๋ก JDBC๊ฐ ๋์ค๊ธฐ ์ด์ ์๋ MS์งํ ( C์ธ์ด)์์ ๋ง๋ ODBC API (Open DB Connectivity)๋ฅผ ์ ๊ณตํ์๋ค.
# JDBC์ ๊ธฐ๋ฅ
์ฐธ๊ณ ๋ก JDBC๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์๋ ์ฌ๋ฌ๊ฐ์ง ์ ํ์ด ์๊ธดํ๋ [์ ํ 4] ์ด์ธ ์ง์ ์ฌ์ฉํ ์ผ์ ๊ฑฐ์ ์๋ค๊ณ ๋ณด๋ฉด ๋๋ค.
- ์ ํ I : JDBC- ODBC ๋ธ๋ฆฌ์ง ( Java <-> JDBC <-> ODBC <-> DB)
- ์ ํ II : ๋ค์ดํฐ๋ธ APT-๋ถ๋ถ์ ์ผ๋ก Java ๋๋ผ์ด๋ฒ ( ์ ํ 1์์ ODBC๋ถ๋ถ์ ๊ฐ๋ฐ์๊ฐ ์ฝ๋๋ก ์ง์ ๊ตฌํ)
- ์ ํ III : ๋คํธ์ํฌ ํ๋กํ ์ฝ-์์ Java ๋๋ผ์ด๋ฒ ( ์์ฉ ํ๋ก๊ทธ๋จ๋จ์์ ์๋ฐ๋ก ๋คํธ์ํฌ ์ง์ ๊ตฌํ, ์ถ์ฒ X)
- ์ ํ IV : Thin Driver- Fully Java Driver ( DB ์
์ฒด๋ณ๋ก JDBC ๋๋ผ์ด๋ฒ ์ ๊ณต )
ํด๋ผ์ด์ธํธ JVM์ ์ง์ ์ค์น๋์ด ๋ณ๋์ ์ํํธ์จ์ด๊ฐ ํ์์๊ณ , DB๊ณต๊ธ ์ ์ฒด์์ ์ง์ JDBC ๋๋ผ์ด๋ฒ ๊ฐ๋ฐ.
# JDBC ์ฐ๊ฒฐํ๊ธฐ
# 1. Import ํจํค์ง
JDBC API 4.0(2017๋ ) ๊ธฐ์ค, java.sql ํจํค์ง์ javax.sql(ํ์ฅ API, ์๋ฒ์ธก ๋ฐ์ดํฐ ์ฒ๋ฆฌ๊ธฐ๋ฅ ์ ๊ณต) ํจํค์ง๋ฅผ ์ ๊ณตํ๋ค.
# 2. JDBC Driver ์ฐ๊ฒฐ
Importํ API๋ฅผ ์ฌ์ฉํด์ ์ฌ์ฉํ๊ณ ์ํ๋ JDBC ๋๋ผ์ด๋ฒ๋ฅผ ์๋ฐ ์ฑ์ผ๋ก ๊ฐ์ ธ์ ์ฌ์ฉํ ์ ์๋ค.
- Class.forName()
Class.forName("JDBC ๋๋ผ์ด๋ฒ ์ด๋ฆ")
Class.forName(“sun.jdbc.odbc.JdbcOdbcDriver”); // MS-SQL ๋๋ผ์ด๋ฒ ๋ฑ๋ก
Class.forName(“postgresql.Driver”); // PostgreSQL ๋๋ผ์ด๋ฒ ๋ฑ๋ก
Class.forName(“oracle.jdbc.driver.OracleDriver”); // Oracle ๋๋ผ์ด๋ฒ ๋ฑ๋ก
* Java 1.6, JDBC 4.0 ์ดํ์ JDBC์์๋ ์๋น์ค ๋ก๋(java.util.ServiceLoader) ๊ธฐ๋ฐ์ผ๋ก JDBC Driver๊ฐ ์๋์ผ๋ก ๋ฑ๋ก๋ฉ๋๋ค. ์ฆ Class.forName("com.mysql.jdbc.Driver") ๋ฅ์ ์ฝ๋๋ฅผ ์๋์ผ๋ก ํธ์ถํ์ง ์์๋ ๋ฑ๋ก๋ฉ๋๋ค.
// JDBC๋ฅผ ์ฐ๊ฒฐํ๋ ์ฝ๋ ์์
Class.forName("oracle.jdbc.driver.OracleDriver"); //java 1.6 ์ดํ์์๋ ์๋ตํด๋ ๋ฑ๋ก๋จ.
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
stmt = conn.createStatement();
String sql = "select * from tablename";
rs = stmt.executeQuery(sql);
- Class.forName์ ๋์
์ฐ์ , 'Class' ๊ฐ์ฒด๋ JVM์์ ๋์ํ ํด๋์ค์ ์ ๋ณด๋ฅผ ๊ด๋ฆฌํ๋ Java์ Meta-Class๋ผ๊ณ ์๊ฐํ๋ฉด ๋ฉ๋๋ค. Class.forName("package.ClassName") ์ ํด๋น ๋ฌธ์์ด์ ํด๋นํ๋ ํด๋์ค ์์ฑ ํ ๋ฐํํด์ค๋๋ค. ์ฐธ๊ณ ๋ก ๋ชจ๋ JDBC ํจํค์ง์ ๋ด๋ถ๋ ์๋์ ๋น์ทํ ๊ฐ์ ๊ตฌ์กฐ๋ฅผ ๊ฐ์ง๋๋ค.
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static { // static!!
try {
// ์๋ก์ด ๋๋ผ์ด๋ฒ๋ฅผ ๋ฑ๋กํ๋ ์ฝ๋
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
...
}
์ฆ, ๋ด๋ถ์ ์ผ๋ก DriverManager.registerDriver(new Driver()); ๋ฅผ ์ด์ฉํ์ฌ ๋๋ผ์ด๋ฒ ๊ฐ์ฒด๋ฅผ ๋ง๋ญ๋๋ค. ์ด๋ ๊ฒ ์์ฑํ ๋๋ผ์ด๋ฒ ๊ฐ์ฒด๋, DriverManager.getConnection(~)์ ์ด์ฉํ์ฌ ์ปค๋ฅ์ ์ด ์์ฑ๋๋ ์์ ์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
pakage.SomeClass obj = new pakage.SomeClass(); ์ผ๋ก ์ฌ์ฉํ์ง์๊ณ ๊ตณ์ด Class.forName()์ ์ฌ์ฉํ๋ ์ด์ ๋ static ๊ฐ์ฒด๋ก ๊ด๋ฆฌ๋์ด์ง๊ธฐ ๋๋ฌธ์ ๋๋ค. ๋ง์ฝ new๋ก ๊ฐ์ฒด๋ฅผ ์์ฑํด๋ฒ๋ฆฌ๋ฉด JDBC ๋๋ผ์ด๋ฒ ๊ฐ์ฒด๋ ์ธ์คํด์ค๋ฅผ ๋ฐ๋ ์ฐธ์กฐ๋ณ์๋, ๋์ ๋ ํ์ง ์๊ธฐ ๋๋ฌธ์ ๊ฐ์ฒด ์ฐธ์กฐ ์นด์ดํธ๊ฐ 0์ด ๋์ด JVM์ GC์ ๋์์ด ๋ฉ๋๋ค.
// Class.forName() ๋ฉ์๋ ์ ์. static ๋ฉ์๋์ด๋ค.
// ์ฆ, JDBC ๋๋ผ์ด๋ฒ ์์ฑ ๋ฉ์๋๊ฐ ๋ค๋ฅธ ๊ฐ์ฒด๋ณด๋ค ๋จผ์ ์์ฑ๋๋ค.
// java.sql.DriverManager.registerDriver(new Driver());
public static Class<?> forName(String className)
throws ClassNotFoundException
์ ์ ๋ฉ์๋์ธ Class.forName(~)์ ์ฌ์ฉํ๋ฉด ํด๋น ํด๋์ค์ ์ ๋ณด๊ฐ static ๋ธ๋ญ์ ๊ด๋ฆฌ๋์ด GC์ ๋์์ด ๋์ง์๊ณ , ๋ค๋ฅธ ํด๋์ค๋ณด๋ค ๋จผ์ JVM ๋ฉ๋ชจ๋ฆฌ์ ์ธ์คํด์ค์ ์์ฑ๊ณผ ์ด๊ธฐํ๊ฐ ์ด๋ฃจ์ด์ง๊ฒ ๋ฉ๋๋ค.
JDBC ๋๋ผ์ด๋ฒ์ ๊ด๋ จ๋ ๋ฐ์ดํธ์ฝ๋(.class) ํ์ผ์ ๋ฐํ์์ ๊ฐ์ฒด๋ก ์์ฑํ๋ ๋ฐฉ๋ฒ์ด๋ค. ์ฐธ๊ณ ๋ก Class.forName() ๋ด๋ถ์์ DriverManager.registerDriver()๋ฅผ ํธ์ถํจ์ผ๋ก์จ JDBC ๋๋ผ์ด๋ฒ๋ฅผ ๋ฑ๋กํ๊ณ ์ธ์คํด์ค๋ฅผ ์์ฑํ๋ค.
DBMS ์ด๋ฆ | JDBC ๋๋ผ์ด๋ฒ ํจํค์ง ๊ฒฝ๋ก(=์ด๋ฆ) |
MySQL | com.mysql.jdbc.Driver |
Oracle | oracle.jdbc.driver.OracleDriver |
MS SQL Server | com.microsoft.sqlserver.jdbc.SQLServerDriver |
MS Access | net.ucanaccess.jdbc.UcanaccessDriver |
PostgreSQL | org.postgresql.Driver |
IBM DB2 | com.ibm.db2.jdbc.net.DB2Driver |
- DriverManager.registerDriver()
ํน์ DB์ JDBC ๋๋ผ์ด๋ฒ๋ฅผ ๊ฐ๋ฐ์๊ฐ ์ง์ ๊ตฌํํ ๋ ์ฌ์ฉํ๋ค. Class.forName( " JDBC ํจํค์ง ์ด๋ฆ ") ์์, JDBC ํจํค์ง ๋ด๋ถ์์ ํด๋น ๋ฉ์๋๋ฅผ ์ด์ฉํด ๋๋ผ์ด๋ฒ ๊ฐ์ฒด๋ฅผ ์์ฑํ ์ ์๋ค.
DriverManager.registerDrivers(new oracle.jdbc.driver.OracleDriver()); // Oracle ๋๋ผ์ด๋ฒ ๋ฑ๋ก
// DB ๋๋ผ์ด๋ฒ ํจํค์ง ๋ด๋ถ์์ ์ฌ์ฉ๋๋ค.
// Class.forName("java.sql.Driver");
public class Driver extends NonRegisteringDriver implements java.sql.Driver {
static {
try {
java.sql.DriverManager.registerDriver(new Driver());
} catch (SQLException E) {
throw new RuntimeException("Can't register driver!");
}
}
...
}
# 2. DB Connection ๋ง๋ค๊ธฐ
๋ง๋ค์ด์ง ๋๋ผ์ด๋ฒ ๊ฐ์ฒด๋ฅผ ์ด์ฉํด ํด๋น DB์ ์ฐ๊ฒฐํ๋ค.
- getConnection (URL, ์ฌ์ฉ์ ์ด๋ฆ, ์ํธ); – URL(*jdbDriver ๊ฒฝ๋ก), ์ฌ์ฉ์ ์ด๋ฆ, ๋น๋ฐ๋ฒํธ๊ฐ ์๋ค.
- getConnection (URL); – URL(*jdbDriver ๊ฒฝ๋ก)์๋ ์ฌ์ฉ์ ์ด๋ฆ๊ณผ ๋น๋ฐ๋ฒํธ๊ฐ ํฌํจ๋์ด์ผํ๋ค.
DBMS | Connection URL |
MySQL | jdbc : mysql : // HOST_NAME : PORT / DATABASE_NAME |
Oracle | jdbc : oracle : thin : @HOST_NAME : PORT : SERVICE_NAME |
Ms SQL Server | jdbc : sqlserver : // HOST_NAME : PORT; DatabaseName = |
PostgreSQL | jdbc : postgresql : // HOST_NAME : PORT / DATABASE_NAME |
Class.forName("oracle.jdbc.driver.OracleDriver");
try {
// DriverManager.getConnection( jdbcDriver, dbUser, dbPassword)
conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");
// ์ฐ๊ฒฐ์ ์ฑ๊ณตํ๋ฉด ์๋์ ๊ฐ์ด ์ฌ์ฉ๊ฐ๋ฅ.
stmt = conn.createStatement();
String sql = "select * from tablename";
rs = stmt.executeQuery(sql);
} catch ( SQLException ex ) {
// ์์ธ์ฒ๋ฆฌ...
} finally {
if (conn != null )
try { conn.close()
} catch ( SQLException ex ){}
}
# 3. (SQL) Statement ์์ฑ & ์ฟผ๋ฆฌ ์คํ
// ์ ์ ์ธ(๊ณ ์ ๋) ์ฟผ๋ฆฌ๋ฌธ์ ์คํ ํ ๊ฒฝ์ฐ
Statement stmt = null; // Statement ๊ฐ์ฒด ์์ฑ
String sql = "select * from test";
stmt = conn.createStatement(sql);
// ํ๋ผ๋ฏธํฐ๋ฅผ ์
๋ ฅ ๋ฐ์ ๋์ ์ธ ์ฟผ๋ฆฌ๋ฌธ์ ์คํํ ๊ฒฝ์ฐ
PreparedStatement pstmt = null; // PreparedStatement ๊ฐ์ฒด ์์ฑ
String sql = "INSERT INTO test VALUES (?,?)";
pstmt = conn.prepareStatement(sql);
// ํ๋ผ๋ฉํ ์
๋ ฅ (3,"LEE")
pstmt.setInt(1,3);
pstmt.setString(2, "LEE");
//insert, update, delete๋ฑ ๋ฆฌํด ๊ฐ์ด ํ์ ์๋ ์ฟผ๋ฆฌ๋ฌธ์ผ ๋ ์ฌ์ฉ
pstmt.executeUpdate(SQL);
stmt.executeUpdate(SQL);
// select๋ฑ ๋ฆฌํด ๊ฐ์ด ํ์ํ ์ฟผ๋ฆฌ๋ฌธ์ผ ๋ ์ฌ์ฉ
ResultSEt rs = null;
rs = pstmt.executeQuery(SQL);
rs = stmt.executeQuery(SQL);
// ๋ฐ์์จ ResultSet์ iter์ฒ๋ผ ์ฌ์ฉ๊ฐ๋ฅ.
while(rs.next()){
String name = rs.getString("name");
}
# 4. Close Connection
๋ฐ์ดํฐ๋ฒ ์ด์ค ์ปค๋ฅ์ ์ ์์ฑํ ์ญ์์ผ๋ก ๋ฐ๋ฉ. ๋ณดํต finally ๋ธ๋ญ object.close() ํ์์ผ๋ก ์ฌ์ฉ๋๋ค.
์ฐธ๊ณ ๋ก Java7(1.7)๋ถํฐ ์ ๊ณต๋๋ Try-with-Resource ๊ตฌ๋ฌธ์ ์ฌ์ฉํ๋ฉด close๋ฅผ ์ฌ์ฉํ์ง ์๊ณ ๋ ์ฝ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค. ์ฐธ๊ณ ๋ก Java9 ๋ถํฐ๋ Try-with-Resource๋ฌธ์์ ๋ฐ์์ ์ ์ธ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์๋ ๋์ผํ๊ฒ ๊ด๋ฆฌํด์ค๋ค.
Try-with-Resource ์ ๋ํ์ฌ
conn.close() // dbDriver ์ปค๋ฅ์
pstmt.close() // ์ฟผ๋ฆฌ๋ฌธ
stmt.close();
public class Class1 {
public method1() throws Exception {
Connection conn = DriverManager.getConnection("...");
Statement stat = conn.createStatement();
ResultSet rs = stat.executeQuery("SELECT 1 from dual")
// Java9 ๋ถํฐ๋ ์ด๋ฐ ์์ผ๋ก ๋ฐ์์ ์ ์ธ๋ ๊ฐ์ฒด๋ฅผ ๊ฐ์ ธ์ ์ฌ์ฉํ ์๋์๋ค.
try (conn; stat; rs) {
// ...
} catch (Exception e) {
// ...
}
}
}
Connection connection=dataSource.getConnection();
// Java7 ๋ถํฐ ์ง์๋๋ try(์์) ๊ด๋ฆฌ ๊ธฐ๋ฅ.
// finally๋ก ๋ฐ๋ก close ํด์ค ํ์๊ฐ ์๋ค.
try(connection){
connection.setAutoCommit(false);
//execute some SQL statements...
connection.commit();
}catch(SQLException e){
connection.rollback();
}
* ํด๋น ์์ ์์ ๋์ค๋ ํธ๋์ญ์ ์ฒ๋ฆฌ๋ ๋ค์ ๊ธ( JDBC ํธ๋์ญ์ )์์ ๋ฐ๋ก ๋ค๋ฃฐ ์์ ์ด๋ค.
# ์ค์ ์ฌ์ฉ ์์
- ๋ฐ์ดํฐ ์ฝ์ด์ค๊ธฐ (๊ณ ์ ์ ์ธ ๋ฐฉ๋ฒ)
package test;
// JDBC API import
import java.sql.*;
import org.apache.log4j.Logger;
public class dbconn {
// ์ค์ DB ์ ๊ทผ ์ฝ๋์์ user์ pw์ ์ํธํํด์ ์ฌ์ฉํ๋ ๊ฒ์ ๊ถ์ฅํ๋ค.
// ํด๋น ์ฝ๋๊ฐ ํผ์ง๊ฑฐ๋ ํดํน๋นํ๋๋ผ๋ ์ถ๊ฐ์ ์ธ ํผํด๋ฅผ ๋ง์ ์ ์๋ค.
static Logger logger = Logger.getLogger(dbconn.class); // logging
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://192.168.0.143:3306/test";
static final String USERNAME = "root";
static final String PASSWORD = "1234";
public static void main(String[] args) throws SQLException {
Connection conn = null;
Statement stmt = null;
ResultSet rs = null;
try {
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
stmt = conn.createStatement();
String sql1 = "select * from test";
rs = stmt.executeQuery(sql1);
while (rs.next()) {
String no = rs.getString("no");
String name = rs.getString("name");
System.out.println("no = " + no + " , " + "name = " + name);
}
} catch (SQLException se1) {
// SQL ๊ด๋ จ ์์ธ์ฒ๋ฆฌ
} catch (Exception ex) {
// ๊ทธ ์ธ์ ์์ธ์ฒ๋ฆฌ
} finally {
// ์ฌ์ฉ์ ์๋ฃํ ๊ฐ์ฒด๋ค์ .close()๋ก ๋ฐํ.
rs.close();
stmt.close();
conn.close();
}
}
}
- ๋ฐ์ดํฐ ์ ๋ ฅํ๊ธฐ (Try-with-resource)
package test;
import java.sql.*;
public class dbpstmt {
static final String JDBC_DRIVER = "com.mysql.jdbc.Driver";
static final String DB_URL = "jdbc:mysql://192.168.0.143:3306/test";
static final String USERNAME = "root";
static final String PASSWORD = "1234";
public static void main(String[] args) throws SQLException {
Connection conn = null;
PreparedStatement pstmt = null;
// Try-with-Resource
try(
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
pstmt = conn.prepareStatement("INSERT INTO test VALUES (?,?)");
){
String sql = "INSERT INTO test VALUES (?,?)";
Class.forName(JDBC_DRIVER);
conn = DriverManager.getConnection(DB_URL, USERNAME, PASSWORD);
pstmt = conn.prepareStatement(sql);
pstmt.setInt(1, 3);
pstmt.setString(2, "LEE");
pstmt.executeUpdate();
} catch (SQLException e) {
// ์์ธ์ฒ๋ฆฌ
} catch (Exception e) {
// ์์ธ์ฒ๋ฆฌ
}
}
}
# ์ปค๋ฅ์ ํ (DataBase Connection Pool)
๋ฉํฐ ์ฐ๋ ๋์ ์ฐ๋ ๋ ํ์ฒ๋ผ, DB์ ์ฐ๊ฒฐํ๋ ์ปค๋ฅ์ ์ ๋ฏธ๋ฆฌ ์์ฑํด๋๊ณ ํ์ํ ๋ ๊บผ๋ด ์ฐ๋ ๊ธฐ๋ฒ์ ๋งํ๋ค. ์ปค๋ฅ์ ํ์ ์คํ์์ค์๋ ๋ํ์ ์ผ๋ก DBCP ์ C3P0๊ฐ ์๋๋ฐ, ์ฌ๊ธฐ์์๋ DBCP์ ๋ํด์ ๋ค๋ฃจ๊ณ ์ ํ๋ค.
JDBC๋ฅผ ์ด์ฉํด DB์ ์ ๊ทผํ๋ ๊ณผ์ ์ ๋ค์๊ณผ ๊ฐ์ด ์์ฝ ๊ฐ๋ฅํ๋ค.
- DB ์ ์์ ์ํ JDBC ๋๋ผ์ด๋ฒ ๋ก๋
- getConnection Method๋ก ๋ถํฐ DB ์ปค๋ฅ์ ๊ฐ์ฒด๋ฅผ ์ป์
- ์ฟผ๋ฆฌ ์ํ์ ์ํ PreparedStatement, Statement ๊ฐ์ฒด ์์ฑ
- excuteQuery๋ฅผ ์คํํด์ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ์์ด.
- ์ฒ๋ฆฌ๊ฐ ์๋ฃ๋๋ฉด ๋ฆฌ์์ค๋ค์ closeํ์ฌ ๋ฐํ (๋๋ try-with-resoucre๋ฌธ ์ฌ์ฉ์ผ๋ก ํด๋น ๊ณผ์ ์๋ต)
Java์์ DB์ ์ ๊ทผํ ๋๋ง๋ค Driver๋ฅผ ๋ก๋ํ๊ณ , ์ปค๋ฅ์ ๊ฐ์ฒด๋ฅผ ์์ฑํ๋ ๊ฒ์ ์๋นํ ๋นํจ์จ์ ์ธ ์์ ์ด๋ค. ๊ทธ๋์ WAS๋ฑ์ ์ฌ์ฉํ ๋ ๋ฏธ๋ฆฌ ์ผ์ ๋์ DB Connection ๊ฐ์ฒด๋ฅผ ์์ฑํ๊ณ ์ด๋ฅผ ํ ๋น๋ฐ๋ ๋ฐฉ๋ฒ(Connection Pool)์ผ๋ก ์ฌ์ฉํ ์ ์๊ฒ ๋ง๋ค์ด์ค๋ค.
์ปค๋ฅ์ ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ก๋ ๋ฌด๋ฃ์ธ DBCP๊ฐ ๋ง์ด ์ฌ์ฉ๋์๊ณ , ์ต๊ทผ(2021)์ ์ฌ์ฉ๋๋ ์คํ๋ง ๋ถํธ 2.0๋ถํฐ๋ HikariCP ๋ฅผ ์ฌ์ฉํ๋ค๊ณ ํ๋ค.
HikariCP
HikariCP๋ ์คํ๋ง ๋ถํธ 2.0๋ถํฐ ์ค์ ๋ default JDBC Connection Pool์ ๋๋ค.๊ธฐ์กด์ DBCP๋ค ๋ณด๋ค ๋น ๋ฅด๊ฒ ์์ ์ ์ฒ๋ฆฌํ๊ณ ๊ฐ๋ณ์ต๋๋ค.๋ง์ Connection pool ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ค์ PreparedStatement caching์ ์ง์ํ์ง๋ง HikariCP๋ ์ง์ํ์ง ์์ต๋๋ค. ์ฆ HikariCP ๋ Statement Cache ๋ฅผ ์ฌ์ฉํ์ง ์์ต๋๋ค.
- ๋๋ถ๋ถ์ JDBC ๋๋ผ์ด๋ฒ๋ค์ Statement cache ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค. (ex. Oracle, MySQL, DB2)
- ์ด๋ฐ ๋๋ผ์ด๋ฒ๋ค์ ํน์ง ์ค ํ๋๋ ์คํ ๊ณํ์ ์ปค๋ฅ์ ๊ฐ ๊ณต์ ํ๋ ๊ธฐ๋ฅ์ด ์๋ ๊ฒ์ ๋๋ค.
- Connection Pool Layer์์ PreparedStatement Caching ์ connection ํ๋๋น ์บ์๊ฐ ์ด๋ฃจ์ด์ง๋๋ค.
- ์ดํ๋ฆฌ์ผ์ด์ ์ด 100๊ฐ์ ์คํ๋ ์ฟผ๋ฆฌ์ 10๊ฐ์ connection pool ์ ๊ฐ์ง๊ณ ์๋ค๋ฉด ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ 1000๊ฐ์ ์คํ ๊ณํ์ holding ํ๊ณ ์๋ ์ ์ด์ฃ .
- ์ด ์ปค๋ฅ์ ํ์ ์คํ๊ณํ๊ณผ ํจ๊ป preparedStatement๋ ๋ง์ด caching ๋์ด ์๋ ์ํ์ ๋๋ค.
- ์์์ ์ ๊ธฐํ 1000๊ฐ์ ์คํ ๊ณํ์ ์ปค๋ฅ์ ํ์์ hoding ํ๋ ๊ฒ๋ณด๋ค ๋ฐ์ดํฐ๋ฒ ์ด์ค ๋ด์ 100๊ฐ์ ์ฟผ๋ฆฌ๋ฅผ ์บ์ฑํ๋ ๊ฒ์ด ๋ซ๋ค๋ ๊ฒ์ด Statement Cache๋ฅผ ์ฌ์ฉํ์ง ์๋ ์ด์ ์ ๋๋ค. ์ด๋ ๊ฒํ๋ฉด ์ฑ๋ฅ์ ํฅ์ ์ํฌ ์ ์์ต๋๋ค.
HikariCP๋ ์ด์ฒ๋ผ Statement ์บ์ฑ์ Connection Pool์ ์ค์ ํ๋ ๊ฒ์ด ์๋ Driver์ ์ค์ ํ๋ค๋ ํน์ง์ด ์์ต๋๋ค. ์ค์ ์ด ๋ฐฉ์์ ์ด์ฉํ์ฌ ๋ค๋ฅธ DBCP๋ณด๋ค ๋ฒค์น๋งํน์ ๋ ๋์ ์ฑ๋ฅ์ ๋ณด์ฌ์ฃผ๊ณ ์์ต๋๋ค.
์ถ์ฒ: github.com/brettwooldridge/HikariCP (HikariCP ๊ฐ๋ฐ์์ ๊นํ๋ธ)
์ฐธ๊ณ ๋ก HikariCP๋ง๊ณ ์ฌ์ฉ๋๋ DBCP๋ค์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
- C3P0 (๊ณผ๊ฑฐ ํ์ด๋ฒ๋ค์ดํธ์์ ์ถ์ฒ, ์ฑ๋ฅ์ด ํ CP์ ๋นํด์ ๋ณ๋ก)
- DBCP (์ํ์น์์ ๊ด๋ฆฌ, C3P0๋ณด๋ค ์ฑ๋ฅ์ด ์ข์)
- proxool (์ ๋ง ์ข์์ง๋ง 2008๋
์ดํ ์
๋ฐ์ดํธ๊ฐ ์์)
- Bone CP (JDBC, C3P0์ ๋๋ฆผ์ด ์ซ์ด์ ๋น ๋ฆ์ ์ปจ์
์ผ๋ก ๊ฐ๋ฐ, JDBC CP๊ธฐ๋ฐ)
- HikariCP (Bone CP๋ณด๋ค ๋น ๋ฆ. ํ์ฌ Spring์์ ๋ฐ๊ณ ์๋ CP)
# Commons DBCP (= Apache DBCP)
๋ํ์ ์ธ ์ปค๋ฅ์ ํ ์คํ์์ค ๋ผ์ด๋ธ๋ฌ๋ฆฌ์ด๋ค. ํ์ฌ DBCP๋ ์ํ์น ์ฌ์ดํธ์์ JAR ํ์ผ์ ๋ค์ด ๋ฐ์ ์ ์๋๋ฐ, DBCP ๋ด๋ถ์์ ์ฌ์ฉํ Pool์ธ Commons Pool ๊ณผ ๋ก๊ทธ๊ธฐ๋ก์ ์ฌ์ฉ๋๋ Commons Logging์ ํจ๊ป ๋ฐ์์ผ ์ฌ์ฉ ํ ์ ์๋ค.
Commons DBCP2 : http://commons.apache.org/proper/commons-dbcp/
Commons Pool2 : http://commons.apache.org/proper/commons-pool/
Commons Logging : http://commons.apache.org/proper/commons-logging/
JSP์์ ์ฌ์ฉํ๋ ค๋ฉด ์ฌ์ดํธ์์ ํ์ํ JARํ์ผ๋ค์ ๋ค์ด๋ฐ์ WEB-INF/lib ๋๋ ํ ๋ฆฌ์ ๋ณต์ฌํ๋ฉด ์ฌ์ฉ ๊ฐ๋ฅํ๋ค. ๋ค์ด๋ก๋ํ DBCP๋ ์๋ธ๋ฆฟ์ผ๋ก ์ด๊ธฐํํ๊ณ ๋ ๋ค, ์ปค๋ฅ์ ๊ฐ์ฒด๋ฅผ [DBCP ์ปค๋ฅ์ ํ]์์ ๋ฐ์์ ์ฌ์ฉํ ์ ์๋ค.
# web.xml์์ DBCP ์ด๊ธฐํ ์๋ธ๋ฆฟ ๋ฑ๋ก.
<load-on-stratup> ํ๊ทธ๋ฅผ ์ด์ฉํด ์ฑ์ด ์คํ๋ ๋ ํด๋น ์๋ธ๋ฆฟ์ด ๋์ํ๋๋ก ์ค์ ํ ์ ์๋ค.
<servlet>
<servlet-name>DBCPInit</servlet-name>
<servlet-class>jdbc.DBCPInit</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
# ์ปค๋ฅ์ ํ์์ ์ปค๋ฅ์ ์ ๊ฐ์ ธ์ค๋ ๋ฐฉ๋ฒ
web.xml์ DBCP ์ด๊ธฐํ ์๋ธ๋ฆฟ์ ๋ฑ๋กํ๋ค๋ฉด, ๋ค์๊ณผ ์ปค๋ฅ์ ์ ๊ฐ์ ธ์ ์ฌ์ฉํ ์ ์๋ค.
String jdbcDriver = "jdbc:apache:commons:dbcp:cp";
...
conn = DriverManager.getConnection(jdbcDriver);
# DBCP ์ด๊ธฐํ ์๋ธ๋ฆฟ (DBCPInit.java)
์ฐธ๊ณ ๋ก ํด๋น ์๋ธ๋ฆฟ์์ DBCP์ ์ค์ ๊ฐ์ ์ง์ ํด์ค ์ ์๋ค.
package jdbc;
import java.sql.DriverManager;
import java.util.Properties;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import org.apache.commons.dbcp2.ConnectionFactory;
import org.apache.commons.dbcp2.DriverManagerConnectionFactory;
import org.apache.commons.dbcp2.PoolableConnection;
import org.apache.commons.dbcp2.PoolableConnectionFactory;
import org.apache.commons.dbcp2.PoolingDriver;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
public class DBCPInit extends HttpServlet {
@Override
public void init() throws ServletException {
loadJDBCDriver();
initConnectionPool();
}
private void loadJDBCDriver() {
try {
//์ปค๋ฅ์
ํ์์ ์ฌ์ฉํ jdbc ๋๋ผ์ด๋ฒ๋ฅผ ๋ก๋ฉ
Class.forName("com.mysql.jdbc.Driver");
} catch (ClassNotFoundException ex) {
throw new RuntimeException("fail to load JDBC Driver", ex);
}
}
private void initConnectionPool() {
try {
String jdbcUrl = "jdbc:mysql://localhost:3306/chap14?" + "useUnicode=true&characterEncoding=utf8";
String username = "phs1116";
String pw = "1234";
//์ปค๋ฅ์
ํฉํ ๋ฆฌ ์์ฑ. ์ปค๋ฅ์
ํฉํ ๋ฆฌ๋ ์๋ก์ด ์ปค๋ฅ์
์ ์์ฑํ ๋ ์ฌ์ฉํ๋ค.
ConnectionFactory connFactory = new DriverManagerConnectionFactory(jdbcUrl, username, pw);
//DBCP๊ฐ ์ปค๋ฅ์
ํ์ ์ปค๋ฅ์
์ ๋ณด๊ดํ ๋ ์ฌ์ฉํ๋ PoolableConnectionFactory ์์ฑ
//์ค์ ๋ก ๋ด๋ถ์ ์ผ๋ก ์ปค๋ฅ์
์ ๋ด๊ณ ์๊ณ ์ปค๋ฅ์
์ ๊ด๋ฆฌํ๋๋ฐ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค. ex)์ปค๋ฅ์
์ closeํ๋ฉด ์ข
๋ฃํ์ง ์๊ณ ์ปค๋ฅ์
ํ์ ๋ฐํ
PoolableConnectionFactory poolableConnFactory = new PoolableConnectionFactory(connFactory, null);
//์ปค๋ฅ์
์ด ์ ํจํ์ง ํ์ธํ ๋ ์ฌ์ฉํ๋ ์ฟผ๋ฆฌ๋ฅผ ์ค์ ํ๋ค.
poolableConnFactory.setValidationQuery("select 1");
//์ปค๋ฅ์
ํ์ ์ค์ ์ ๋ณด๋ฅผ ์์ฑํ๋ค.
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
//์ ํด ์ปค๋ฅ์
๊ฒ์ฌ ์ฃผ๊ธฐ
poolConfig.setTimeBetweenEvictionRunsMillis(1000L * 60L * 1L);
//ํ์ ์๋ ์ปค๋ฅ์
์ด ์ ํจํ์ง ๊ฒ์ฌ ์ ๋ฌด ์ค์
poolConfig.setTestWhileIdle(true);
//์ปค๋ฅ์
์ต์๊ฐฏ์ ์ค์
poolConfig.setMinIdle(4);
//์ปค๋ฅ์
์ต๋ ๊ฐฏ์ ์ค์
poolConfig.setMaxTotal(50);
//์ปค๋ฅ์
ํ ์์ฑ. ์ธ์๋ก๋ ์์์ ์์ฑํ PoolabeConnectionFactory์ GenericObjectPoolConfig๋ฅผ ์ฌ์ฉํ๋ค.
GenericObjectPool<PoolableConnection> connectionPool = new GenericObjectPool<>(poolableConnFactory,
poolConfig);
//PoolabeConnectionFactory์๋ ์ปค๋ฅ์
ํ์ ์ฐ๊ฒฐ
poolableConnFactory.setPool(connectionPool);
//์ปค๋ฅ์
ํ์ ์ ๊ณตํ๋ jdbc ๋๋ผ์ด๋ฒ๋ฅผ ๋ฑ๋ก.
Class.forName("org.apache.commons.dbcp2.PoolingDriver");
PoolingDriver driver = (PoolingDriver) DriverManager.getDriver("jdbc:apache:commons:dbcp:");
//์์์ ์ปค๋ฅ์
ํ ๋๋ผ์ด๋ฒ์ ์์ฑํ ์ปค๋ฅ์
ํ์ ๋ฑ๋ฃํ๋ค. ์ด๋ฆ์ cp์ด๋ค.
driver.registerPool("cp", connectionPool);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
# Tomcat DBCP ์ด์ฉํ๊ธฐ
๋ฐ๋ก ๋ค์ด๋ก๋ ๋ฐ์ง์๊ณ Tomcat WAS์ ๋ด์ฅ๋ Tomcat DBCP๋ฅผ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ์ด๋ค.
ํฐ์บฃ์ ์ค์นํ๋ค๋ฉด $CATALINA_HOME/lib/tomcat-dbcp.jar ๊ฒฝ๋ก์ ํด๋น DBCP๊ฐ ํจ๊ป ์ค์น๋์๋ค.
1. Tomcat/conf/server.xml ์ ์๋ GlobalNamingResources ํ๊ทธ ์ฌ์ด์ DBCP ์ ๋ณด๋ฅผ ์ ๋๋ค.
ํด๋น ์์ ๋ ์ค๋ผํด์ ์ฌ์ฉํด์ driverClassName = "oracle.jdbc.driver.OracleDriver" ๋ผ๊ณ ์ค์ ํด์ฃผ์๋ค. ๋๋จธ์ง๋ DBCP ์ค์ ๊ฐ์ด๋ค. maxIdle์ ํ์์์ ๊ฐ์ง๊ณ ์๋ ์ปค๋ฅ์ ๊ฐ์ฒด ์, maxTotal ์ ์ต๋ ์๋ฅผ ์๋ฏธํ๋ค.
Tomcat/conf/server.xml
<GlobalNamingResources>
<!-- Editable user database that can also be used by UserDatabaseRealm
to authenticate users -->
<!-- My DBCP Setting ========================= -->
<Resource auth="Container"
driverClassName="oracle.jdbc.driver.OracleDriver" maxIdle="10"
maxTotal="20" maxWaitMillis="-1" name="jdbc/myshop" password="tiger"
type="javax.sql.DataSource" url="jdbc:oracle:thin:@127.0.0.1:1521:XE"
username="myshop" />
<!-- ========================================= -->
</GlobalNamingResources>
2. ๊ทธ๋ฆฌ๊ณ context.xml์ ์์์ ์ง์ ํ DBCP์ ์ด๋ฆ์ ๋ฑ๋กํด์ค๋ค.
Tomcat/conf/context.xml
<!-- MyDBCP Setting =================================== -->
<ResourceLink global="jdbc/myshop" name="jdbc/myshop" type="org.apache.tomcat.dbcp.dbcp2.BasicDataSource"/>
<!-- ================================================== -->
3. ์ดํ WEB-INF/web.xml์ DBCP ์ธํ ์ ํด์ฃผ๋ฉด ํฐ์บฃ์ ๋ด์ฅ๋ DBCP๋ฅผ ์ฌ์ฉํ ์ ์๋ค.
<web-app>
<!-- My DBCP Setting ================================== -->
<resource-ref>
<description>Oracle Datasource example</description>
<res-ref-name>jdbc/myshop</res-ref-name>
<res-type>javax.sql.DataSource</res-type>
<res-auth>Container</res-auth>
</resource-ref>
<!-- ================================================== -->
</web-app>
4. ์ดํ ์๋์ ๊ฐ์ด ์๋ฐ์ฝ๋์์ DBCP ์ปค๋ฅ์ ์ ๋ฐ์์ฌ ์ ์๋ค.
Context initContext = new InitialContext();
// Initialcontext ์์ฑ -> ์ด๋ฆ์ผ๋ก ๊ฐ์ฒด ์ฐพ์ ์ ์๋๋ก ๋์์ค๋ค.
Context envContext = (Context)initContext.lookup("java:/comp/env");
// ํฐ์บฃ(์๋ฒ)์ ๋จผ์ ์ฐพ๋๋ค.
// ํฐ์บฃ์ ์ฐพ์ ๋๋ java:comp/env ๋ก ์ฐพ๋๋ค.
DataSource ds = (DataSource)envContext.lookup("jdbc/myshop");
// server.xml์ ๋ฑ๋กํ๋ ์ด๋ฆ myshop์ ์ฐพ๋๋ค.(ํ์
์ DataSource ํ์
)
// ์ฐธ๊ณ ๋ก ์ด๋ ๊ฒ ์ด๋ฆ์ผ๋ก ๊ฐ์ฒด๋ฅผ ์ฐพ๋ ๋ฐฉ์์ JNDI(Java Naming Directory Interface)๋ผ ํ๋ค.
Connection conn = ds.getConnection();
System.out.println("<h1>๋ฐ์ดํฐ ์์ค ๋ฃฉ์
์ฑ๊ณต: "+ds +"</h1>");
System.out.println("<h2> con="+ conn + "</h2>");
if(conn!=null) conn.close();
// ์ปค๋ฅ์
์ฐ๊ฒฐ์ ๋๋ ๊ฒ์ด ์๋๋ผ ์ปค๋ฅ์
ํ์ ์๋์ผ๋ก ๋ฐ๋ฉ์ ํ๋ค.
'๐ฑBackend > Java' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
#21 Servlet Context Listener (0) | 2021.07.21 |
---|---|
#20 JDBC ํธ๋์ญ์ (Spring -@Transaction) (0) | 2021.07.21 |
#18 JSP Model1, Model2 (MVC) (0) | 2021.07.18 |
#17 Servlet Filter (0) | 2021.07.18 |
#16 Servlet ์ดํด (1) | 2021.07.18 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
JiwonDev
JiwonDev