JDBC, JNDI, DBCP 는 모두 JAVA에서 DB 커넥션을 할 때 사용하는 방법이다.
JDBC는 데이터베이스를 조작하는 표준 SQL 인터페이스 API이다. 즉, JDBC는 데이터 베이스 커넥션 인터페이스 이다.
일반적인 JDBC는 데이터 베이스 풀 방식을 사용하지 않고 DB에서 정보를 가져올 때 마다 매번 디비연결을 열고 닫는다.
따라서 상용 어플에는 JDBC 방식을 사용하는 경우가 거의 없다. (매우 비효율적이기 때문)
사용방법 (Oracle 기준)
데이터베이스 연결 설정에서 JDBC 파일을 선택한다.(ojdbc6.jar, ojdbc7.jar, ojdbc8.jar...)
드라이버 클래스 선택 후 아래의 접속 정보를 입력
항목 | 설명 |
---|---|
URL | 연결할 URL |
호스트 | 서버 포트 넘버 |
SID | Oracle SID(System Identifier) |
사용자 | DB 접속 아이디 |
비밀번호 | DB 접속 비밀번호 |
Connect AS | DB 연결 권한 |
기본적인 원리는 어플리케이션을 시작할 때 원하는 만큼 커넥션 객체를 만들어 놓고 pool에 넣어놓았다가 필요할 때 마다 갖다 쓰고 pool에 반납하는 방식으로 운영한다.
데이터 베이스 커넥션 풀을 어플리케이션 소스단에 설정한다.
다중 스레드를 스레드풀로 관리하는 것과 비슷한 방식이라고 한다.
JDBC 방식 보다는 일반적인 경우 이러한 Pool 방식을 사용한다.
사용예)
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);
}
}
}
<servlet>
<servlet-name>DBCPInit</servlet-name>
<servlet-class>jdbc.DBCPInit</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
String jdbcDriver = "jdbc:apache:commons:dbcp:cp";
...
conn = DriverManager.getConnection(jdbcDriver);
커넥션을 사용할 댄 기존 DB주소가 아닌 커넥션 풀의 주소를 사용한다.
디렉터리 서비스에서 제공하는 데이터 및 객체를 발견(discover)하고 참고(lookup)하기 위한 자바 API이다.
사용방법 (설정 및 사용법, Tomcat8.5 기준)
<GlobalNamingResources>
태그 사이에 셋팅 해준다. <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>
오라클을 사용하기 때문에
driverClassName="oracle.jdbc.driver.OracleDriver" 사용
maxldle="10"은 평상시에 커넥션 풀 객체를 10개 사용한다는 뜻이고
maxTotal="20"은 최대 20개 까지 객체를 만들겠다는 소리다.
오라클에서 사용하는 아이디와 비밀번호는
username과 password에 작성하면 된다.
type이 가장 중요하다. DataSource를 통해 객체에 이름을 등록해서 사용할 수 있다.
name="jdbc/myshop"은 커넥션풀의 이름을 정해주는 것으로 유일한 이름이어야 한다.
<Context>
태그 안에<!-- MyDBCP Setting =================================== -->
<ResourceLink
global="jdbc/myshop"
name="jdbc/myshop"
type="org.apache.tomcat.dbcp.dbcp2.BasicDataSource"/>
<!-- ================================================== -->
global="jdbc/myshop", name은 server.xml에서 설정했던 name과 동일한 이름으로 지정한다.
3) XXproject/WEB-INF/web.xml의 <web-app>
태그사이에 아래 부분 세팅
<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>
// Initialcontext 생성 -> 이름으로 객체 찾을 수 있도록 도와준다.
Context initContext = new InitialContext();
// 톰캣(서버)을 먼저 찾는다.
// 톰캣을 찾을 때는 java:comp/env 로 찾는다.
Context envContext = (Context)initContext.lookup("java:/comp/env");
// server.xml에 등록했던 이름 myshop을 찾는다.(타입은 DataSource 타입)
DataSource ds = (DataSource)envContext.lookup("jdbc/myshop");
Connection conn = ds.getConnection();
System.out.println("<h1>데이터 소스 룩업 성공: "+ds +"</h1>");
System.out.println("<h2> con="+ conn + "</h2>");
// 커넥션 연결을 끊는 것이 아니라 커넥션풀에 자동으로 반납을 한다.
if(conn!=null) conn.close();
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8" import="javax.naming.*, java.sql.*, javax.sql.*"%>
<%
// Initialcontext 생성 -> 이름으로 객체 찾을 수 있도록 도와줌
Context initContext = new InitialContext();
// 톰캣(서버)을 먼저 찾는다.
// 톰캣을 찾을 때는 java:comp/env 로 찾는다.
Context envContext = (Context)initContext.lookup("java:/comp/env");
// server.xml에 등록했던 이름 myshop을 찾는다.(타입은 DataSource 타입)
DataSource ds = (DataSource)envContext.lookup("jdbc/myshop");
//etc.
Connection conn = ds.getConnection();
out.println("<h1>데이터 소스 룩업 성공: "+ds +"</h1>");
out.println("<h2> con="+ conn + "</h2>");
// 커넥션 여결을 끊는 것이 아니라 커넥션풀에 자동으로 반납을 한다.
if(conn!=null) conn.close();
%>
좋은글이네요 !