웹개발하면서 DB의 사용은 필연적이기 때문에 java.sql.PreparedStatement의 사용은 필연적이다. Statement도 있기는 하지만 PreparedStatement는 한번 사용한 SQL문이저장되기 때문에 반복해서 사용할 경우 성능이 좋기 때문에 일반적으로는 PreparedStatement를 사용한다.



StringBuffer sql = new StringBuffer(" INSERT INTO poll (col1, col2 ) VALUES (?, ?) ");


psmt = conn.prepareStatement(sql.toString());

psmt.setString(1, "test");

psmt.setString(2, "test");

psmt.executeUpdate();




일반적으로 위와 같이 사용하는데 저렇게 사용해서 결과값 받아서 결과값 리턴해주고 끝인데 상황에 따라서는 쿼리를 반복적으로 사용해야할 때가 있다. 보통은 저게 DAO에 들어있기 때문에 메서드를 여러번 실행해도 되겠지만 그렇게 하면 Connection도 끝었다 다시하기 때문에 별로 효율적이지 못하다.



StringBuffer sql = new StringBuffer(" INSERT INTO poll (col1, col2 ) VALUES (?, ?) ");


for(int i = 0; i<5; i++) {

    psmt = conn.prepareStatement(sql.toString());

    psmt.setString(1, "test");

    psmt.setString(2, "test");

    psmt.executeUpdate();

}




하지만 여러번 반복해서 쿼리를 실행하기 위해서 위처럼 사용하면 안된다. 보기에는 크게 문제가 없고 일반적인 객체의 경우는 저렇게 재할당해서 사용해도 되기는 하지만 PreparedStatement는 다르다. 저렇게한 다음에 psmt.close();를 실행하면 아래쪽 맨 마지막psmt만 닫히고 앞의 psmt들은 닫히지 않는다. 정확히 말하면  앞에서 할당한 psmt는 결코 닫을수 없는 형태가 되어버린다.



StringBuffer sql = new StringBuffer(" INSERT INTO poll (col1, col2 ) VALUES (?, ?) ");

psmt = conn.prepareStatement(sql.toString());


for(int i = 0; i<5; i++) {

    psmt.setString(1, "test");

    psmt.setString(2, "test");

    psmt.executeUpdate();

    psmt.clearParameters();

}




이걸 위처럼 사용하고 있다. PreparedStatement의 객체를 새로할당하는게 아니라파라미터를 할당하고 실행한 다음에 psmt.clearParameters();로 파라미터를 클리어해버린다. 루프돌면서 다시 할당하고 이렇게 돌리면 PreparedStatement객체를 여러번 사용할 수 있다. 



StringBuffer sql = new StringBuffer(" INSERT INTO poll (col1, col2 ) VALUES (?, ?) ");

psmt = conn.prepareStatement(sql.toString());


for(int i = 0; i<5; i++) {

    psmt.setString(1, "test");

    psmt.setString(2, "test");

    psmt.addBatch();

    psmt.clearParameters();

}

psmt.executeBatch();




이걸 좀 더 세련(?)되게 하면 위와같이 사용할 수 있다. JDBC의 배치기능을 사용한 것이다. PreparedStatement의 배치기능은 다수의 쿼리를 한꺼번에 실행하기 위한 기능이다. 여러번에 나누어서 실행하지않고 배치기능을 이용해서 한번에 송신해서 실행함으로써 퍼포먼스를 높일 수 있다.

addBatch()는 쿼리와 파라미터 셋을 배치에 추가하고 이렇게 추가된 배치를 executeBatch()를 통해서 한꺼번에 실행한다. 정확한 테스트까지는 못해봤지만 이렇게 사용하는 배치 메모리의 크기 제한이 있기 때문에 너무 많은 배치를 추가할 경우에는 out of memory가 발생할 수 있기 때문에 많은 addBatch()를 실행해야 할 경우에는 중간중간 executeBatch()를 실행해 주어야 한다.



출처 : https://blog.outsider.ne.kr/266

'Server Enterprise > JDBC & DBCP' 카테고리의 다른 글

[Oracle] JDBC Connection  (0) 2013.07.17
Oracle DBCP Connection pool - Eclipse 환경  (0) 2013.02.07
DBCP 에서 JNDI 설정 방법  (0) 2012.07.20

Class.forName("oracle.jdbc.OracleDriver");

Connection c = DriverManager.getConnection(

"jdbc:oracle:thin:@localhost:1521:orcl", "scott", "tiger");



요거임.

과거 Tomcat 5.0 버전 까지는 커넥션 풀링을 구현하려면, DBCP, Collections, Pool library를 각각 설치해야 했지만, 자카르타 톰캣에서는 다음과 같이 하나의 라이브러리로 제공하고 있다.


Tomcat5.5의 경우 톰캣경로 /common/lib/naming-factory-dbcp.jar

Tomcat6.0의 경우 톰캣경로 /lib/tomcat-dbcp.jar


테스트환경

==============

Oracle 11g

Tomcat 6.0

Eclipse

==============





1. Context configuration


Tomcat Server - server.xml 설정

<Resource name="jdbc/myoracle" auth="Container"

                  type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver"

                  url="jdbc:oracle:thin:@127.0.0.1:1521:orcl"

                  username="scott" password="비밀번호" maxActive="20" maxIdle="10"

                  maxWait="-1"/>


2. web.xml configuration

[출처] Oracle DBCP Connection pool Eclipse환경|작성자 bench87


Project - web.xml 설정

<web-app>

....


<resource-ref>

                     <description>Oracle Datasource example</description>

                     <res-ref-name>jdbc/myoracle</res-ref-name>

                     <res-type>javax.sql.DataSource</res-type>

                     <res-auth>Container</res-auth>

</resource-ref>


</web-app


3. Code example


text page 작성 - jdbc6.0.jsp

<%@ page import="javax.naming.*,

                 java.sql.*,

                 javax.sql.*"  %>

<%

response.setContentType("text/html;");


Connection conn= null;

Statement stmt = null;

ResultSet rs   = null;


try {

    Context initContext = new InitialContext();

    Context envContext  = (Context)initContext.lookup("java:/comp/env");

    DataSource ds = (DataSource)envContext.lookup("jdbc/oracleDB");

    System.out.println("[DataSource] :: " + ds.toString());

    conn = ds.getConnection();


   

    // 

    stmt = conn.createStatement();


    // ResultSet 

    String query =

        "SELECT * FROM TEMPLET";

    rs = stmt.executeQuery(query);

%><table border="1" cellspacing="0">

<tr>

<td>Seq</td>

<td>Str1</td>

<td>Str2</td>

</tr>

<%

    while(rs.next()) {

%><tr>

<td><%=rs.getInt(1)%></td>

<td><%=rs.getString(2)%></td>

<td><%=rs.getString(3)%></td>

</tr>

<%

    } // end while

%></table><%


    rs.close();



    stmt.close();


} catch (SQLException e) {

    out.println("err:"+e.toString());

} finally {

   // conn.close();

}

%>

'Server Enterprise > JDBC & DBCP' 카테고리의 다른 글

PreparedStatement 객체 재사용하기  (0) 2016.06.22
[Oracle] JDBC Connection  (0) 2013.07.17
DBCP 에서 JNDI 설정 방법  (0) 2012.07.20

# [유형1] JNDI & DataSource
# 다음과 같이 JNDI lookup을 통한 DataSource를 사용하고 있을 경우는 특별한 설정
# 없이도, 자동으로 SQL을 추적합니다.
#
# InitialContext ctx = new InitialContext();
# DataSource ds = (DataSource)ctx.lookup("java:comp/env/jdbc/datasource");
# Connection conn = ds.getConnection();
#
# NOTE: 다음과 같이 사용하고 있는 유형은 추적하지 못하니, 한번의 lookup()을
# 사용하는 위 유형으로 어플리케이션 소스 변경을 하셔야 합니다.
# InitialContext ctx = new InitialContext();
# Context envCtx = (Context)ctx.lookup("java:comp/env");
# DataSource ds = (DataSource)envCtx.lookup("jdbc/datasource");
# (혹은 아래에 기술한 [유형3]방식을  고려해 보세요.)
#
#==============================================================================
# [유형2]: DriverManager.getConnection()
# JDBC SQL을 추적할 때, DriverManager.getConnection() 유형을 사용하는 경우에
# 아래의 파라메터를 설정하실 수 있습니다. 예를 들면, JEUS 4.0, Apache DBCP 
# Connection Pool, 혹은 단순히 DriverManager.getConnection() 유형 등입니다. 
# JDBC URL의 앞부분을 기술하시면 됩니다. 여러개라면 ","로 구분하여 기술하시면
# 됩니다.
# ----------
# (예제1) Tmaxsoft JEUS 4.0
# Class.forName("jeus.jdbc.pool.Driver");
# Connection conn = DriverManager.getConnection("jdbc:jeus:pool:mypool");
# ==>
#user_defined_jdbc_connectionpool_prefixes=jdbc:jeus:pool
# ----------
# (예제2) Apache DBCP JDBC Connection Pool
# conn = DriverManager.getConnection("jdbc:apache:commons:dbcp:/poolname");
# ==>
#user_defined_jdbc_connectionpool_prefixes=jdbc:apache:commons:dbcp
# ----------
# (예제3) Oracle Non-Pool사용시
# Class.forName("oracle.jdbc.driver.OracleDriver").newInstance();
# conn = DriverManager.getConnection("jdbc:oracle:thin:@localhost:1521:ORACL",
#                                    "scott", "tiget");
# ==>
#user_defined_jdbc_connectionpool_prefixes=jdbc:oracle:thin
# NOTE: 단 위 (예제3)위 경우, 직접 맺고 끝는 경우가 아니라, JDBC Connection Pool
# 내부에서 자체적으로 위와같이 사용되고 있는 경우는 Connection NOT CLOSED 예외를
# 감지하지 못합니다. 따라서, [유형2]의 경우는 특별한 경우를 제외하곤 사용하지 마십시요.
# 이 경우는 어플리케이션의 ConnUtil.getConnection()와 같은 유형의 메소드를
# 확인하여 아래의 [유형3] 방식으로 전환하여 사용하십시오.
#
#==============================================================================
# [유형 3] 자체제작한 db.DBConnectionManager.java 와 같은 유형
# JDBC Connection Pool을 자체 제작하여 사용하고 있을 때, getConnection()/
# freeConnection()등과 같이 JDBC연결을 얻어오는 부분과 반환하는 클래스 및 
# 메소드를 명시적으로 등록해 줄 수 있습니다. 이러한 유틸리티 클래스는
# 프레임웍상에 하나 이상의 존재할 수 있으므로, ";"으로 구분하여 여러개를 등록할
# 수 있습니다. 예를 들면 다음과 같습니다.
# ----------
# (예제1: 웹로직 5.x/6.x )
# Driver myDriver = (Driver)Class.forName("weblogic.jdbc.pool.Driver").newInstance( );
# Connection con = myDriver.connect("jdbc:weblogic:pool:demoPool", null);
# ==>
#jdbc_connection_get = weblogic.jdbc.pool.Driver.connect(String,Properties)
# ----------
# (예제2: Hans Bergsten's DBConnectionManager Pool)
#jdbc_connection_get   = db.DBConnectionManager.getConnection(String);db.DBConnectionManager.getConnection(String,long)
#jdbc_connection_close = db.DBConnectionManager.freeConnection(String,Connection)
# ----------
# (예제3: Oracle JDBC Driver Connection Pool)
#jdbc_connection_get   = oracle.jdbc.pool.OracleConnectionCacheImpl.getConnection()
# ----------
# (예제4): Oraccle ERP stadard JDBC connection SQL추적 기능 추가(Note: justget옵션)
#  jdbc_connection_justget = oracle.apps.fnd.common.Context.getJDBCConnection()
#  jdbc_connection_close = oracle.apps.fnd.common.Context.releaseJDBCConnection(Connection,String)
#
# NOTE: 
# (1) 앞부분의 패키지명/클래스명/메소드명은 반드시 full package명이 기술되어야
#     합니다. 
#    ConnUtil.getConnection() --> com.db.ConnUtil.getConnection()
# (2) jdbc_connection_get 혹은 jdbc_connection_justget 에 설정할 getConnection()류의 메소드는
#    반드시 return type이 java.sql.Connection 이어야 합니다.
# (3)  jdbc_connection_close 에 설정된 메소드에는 인자 중에 java.sql.Connection이 반드시
#    포함되어 있어야 합니다.(위치 상관없음)
# (4) 파라메터는 다음과 같의 full package 명을 기술해도 되고, 클래스명만 기술해도
#    됩니다.
#    com.db.DBUtil.getConnection(String) == com.db.DBUtil.getConneciton(java.lang.String)
# (5) 파라메터의 변수명도 지정 가능하며 내부적으로는 무시됩니다.
#    com.db.DBUtil.getConnection(String) == com.db.DBUtil.getConneciton(String name)
# (6) jdbc_connection_get과 jdbc_connection_close 가 항상 쌍으로 존재할 필요는
#    없습니다. 예를 들어 ConnUtil.getConntion()으로 DB연결을 얻어오나 
#    conn.close()를 통해 pool로 돌려보내는 유형이라면, jdbc_connection_get만
#    등록하면 됩니다.
# (7) 단 이 [유형3]의 경우는 설정 변경시 WAS의 재기동이 필요합니다.

#-----------------------------------------
# Oracle JDBC 9.x 버전에서 JDBC 2.0 표준 API가 아닌 Oracle 종속적인 CLOB/BLOB 형을
# 어플리케션에서 명시적으로 OracleResultSet으로 캐스팅(casting)하여 사용하고 있을 때,
# ClassCastException이 발생할 수 있습니다.
# 예: CLOB clob = ((OracleResultSet)rs).getCLOB(i);
# 사실 이 경우는 Oracle 10g JDBC Driver로 바꾸고 표준 JDBC 2.0 API로 수정할 것을
# 권고드리나, 이것이 여타의 이유로 불가능할 경우는 아래의 옵션을 설정하여
# OracleResultSet으로 캐스팅이 가능하게 하실 수 있습니다. (default: false)
#enable_jdbc_oracle_dependency_used = true

'Server Enterprise > JDBC & DBCP' 카테고리의 다른 글

PreparedStatement 객체 재사용하기  (0) 2016.06.22
[Oracle] JDBC Connection  (0) 2013.07.17
Oracle DBCP Connection pool - Eclipse 환경  (0) 2013.02.07

+ Recent posts