'JDBC테스트'에 해당되는 글 2건

  1. 2007.12.06 JDBC 버젼 및 정보 알아보기
  2. 2007.12.05 JDBC 액세스의 가속화
제2 외국어 영역2007. 12. 6. 23:35

펌:http://blog.naver.com/levin01?Redirect=Log&logNo=100020144838

DatabaseMetaData의 getDriverVersion() 을 이용하여 알아볼 수 있다.


Connection connection = getConnection();

..

DatabaseMetaData meta = connection.getMetaData();

System.out.println("JDBC version : " + meta.getDriverVersion());

System.out.println("JDBC name : " + meta.getDriverName());

System.out.println("JDBC Major : " + meta.getDriverMajorVersion());

System.out.println("JDBC Minor : " + meta.getDriverMinorVersion());


System.out.println("Database Name : " + meta.getDatabaseProductName());

System.out.println("Database Version : " + meta.getDatabaseProductVersion());

..


결과

JDBC version : 8.1.7.0.0
JDBC name : Oracle JDBC driver
JDBC Major : 8
JDBC Minor : 1
Database Name : Oracle
Database Version : Oracle8i Enterprise Edition Release 8.1.7.0.0 - Production
With the Partitioning option
JServer Release 8.1.7.0.0 - Production

Posted by is윤군

댓글을 달아 주세요

제5 외국어 영역2007. 12. 5. 12:35



JDBC 액세스의 가속화
Step by Step: Speeding Up JDBC Access

저자: Jason Price

자동 커밋을 비활성화하고 업데이트 일괄 처리(batch)를 사용하십시오.

Java API(application-programming interface)가 데이타베이스에 대한 연결을 제공하는 첫 번째 API로서 Oracle 및 기타 데이타베이스를 위한 애플리케이션을 생성할 때 많은 Java 개발자들이 JDBC(Java Database Connectivity)를 사용하고 있습니다. 이 기사에서 애플리케이션 성능을 현저히 향상시킬 수 있는 두 가지 기본 JDBC 기술에 대해 살펴볼 것입니다. 또한 첨부한 예제 코드를 다운로드한 후 컴파일 및 실행하면 이러한 기술이 어떻게 성능을 향상시키는 지도 살펴보겠습니다.

예제를 실행하기 전에 테스트 데이타를 위한 performance 테이블을 생성해야 합니다. 여기서는 이 테이블을 익숙한 scott 스키마로 생성했습니다. 따라서 여러분이 다른 스키마를 사용하는 경우에는 예제 애플리케이션에서 스키마 이름을 반드시 변경해야 합니다. 또한 Oracle 데이타베이스 서비스 이름도 변경해야 합니다. 여기서는 기본 ORCL 서비스 이름을 사용하고 로컬로 실행합니다. (비록 이것이 데이타베이스 연결 문자열 정보를 하드 코딩하는 데 있어 좋은 실습은 아닐지라도, 이 예제를 사용하여 실습해 보았더니 테스트 목적으로는 괜찮았습니다.)

이 SQL 문을 사용하여 성능 테이블을 생성합니다.

CREATE TABLE performance ( int_value INTEGER, varchar2_value VARCHAR2(10) ); 

여기에서 볼 수 있듯이 performance 테이블은 INTEGER 열(int_value)과 VARCHAR2 열(varchar2_value)을 포함하고 있습니다. 이 열들은 예제 프로그램이 생성하는 테스트 데이타로 채워지게 되며, 시작 및 종료 시간을 캡처하고 각 실행에서 둘의 차이를 계산합니다.

자동 커밋 모드를 비활성화하여 시작해 봅시다.

자동 커밋의 기능 및 자동 커밋을 비활성화해야 하는 이유

기본적으로 JDBC의 자동 커밋 모드는 활성화되어 있습니다. 즉, 데이타베이스로 전송되는 모든 SQL 문은 자동으로 데이타베이스에 커밋됩니다. 데이타베이스에 커밋된다는 것은 INSERT, UPDATE, DELETE SQL 문이 실행된 후 이러한 변경 사항이 데이타베이스에 영구히 기록된다는 것을 의미합니다. 애플리케이션 디자인 관점에서 봤을 때 자동 커밋 모드를 활성화하는 것은 이치에 맞지 않습니다. 왜냐하면 애플리케이션의 비즈니스 로직 수준에서 트랜잭션은 빈번히 하나의 INSERT, UPDATE, DELETE 문이 아닌 여러 개의 SQL 문으로 구성되기 때문입니다. 따라서 여러분은 개발자로서 트랜잭션이 구별되는 방법과 트랜잭션이 어떤 SQL 문을 포함해야 하는지에 대해 생각해 보아야 합니다.

예를 들어 트랜잭션이 한 계좌에서 다른 계좌로의 자금 이체에 영향을 주는 두 개의 UPDATE 문으로 구성되어 있는 경우, 이 자금 이체는 한 UPDATE 문을 사용하여 당좌 예금 계좌에서 예금을 빼내고 다른 UPDATE 문을 사용하여 보통 예금 계좌에 예금을 더합니다. 예금이 손실될 수도 있기 때문에 UPDATE 문 중 하나에서 오류가 발생하면, 커밋을 사용하여 둘 다 변경되지 않도록 하거나 롤백을 사용하여 둘 다 실행이 취소되도록 합니다.

만약 자동 커밋을 활성화한다면, 각 문은 실행되는 대로 커밋되어 데이타베이스가 일관성 없는 상태가 될 것입니다. 따라서 앞의 예에서 예금은 손실됩니다. (트랜잭션과 일관성 요구 사항에 대한 자세한 정보는 Oracle Magazine의 Oracle Developer 섹션의 "JDBC 트랜잭션 최적화" 기사의 "ACID 트랜잭션 속성" 사이드바와 "Java에서의 데이타베이스 트랜잭션 사용 방법"을 참조하십시오.)

여러분은 아마도 애플리케이션에 정의되어 있는 일반적인 트랜잭션이 하나 이상의 SQL 문으로 구성된 경우, 자동 커밋을 활성화하는 것이 이치에 맞지 않다고 말할 것입니다. 또한 자동 커밋을 비활성화하면 성능적 이점도 얻을 수 있습니다.

java.sql.Connection(또는 oracle.jdbc.OracleConnection) 객체에 대해 자동 커밋을 비활성화하기 전에 적절한 Oracle JDBC 드라이버를 등록합니다. 예를 들어,

DriverManager.registerDriver( new oracle.jdbc.OracleDriver() ); 

Next, you create a java.sql.Connection object:

Connection myConnection = DriverManager.getConnection( "jdbc:oracle:thin:@localhost:1521:ORCL", "scott", "tiger" ); 

그 다음, 자동 커밋 모드를 비활성화하려면 Connection 객체의 setAutoCommit() 메소드를 호출합니다. setAutoCommit() 메소드는 부울(true 또는 false) 매개변수를 받아들입니다. false는 우리가 바라는 대로 자동 커밋 모드를 비활성화합니다. 다음은 myConnection Connection 객체에 대해 자동 커밋 모드를 비활성화하는 문입니다.

myConnection.setAutoCommit(false); 

자동 커밋 모드를 활성화한 경우와 비활성화한 경우가 성능에 미치는 영향을 비교하도록 디자인된 애플리케이션을 살펴봅시다.

AutoCommit.java와의 시간 제한 게임

AutoCommit.java 예제 프로그램(목록 1 참조)을 사용하면, 자동 커밋 모드를 비활성화 할 경우에 성능이 향상된다는 주장을 증명할 수 있습니다. 이 예제를 컴파일 및 실행하려면 데이타베이스가 요구하는 대로 호스트 이름, 포트 번호, 데이타베이스 서비스 이름, 스키마 이름 및 암호를 변경해야 합니다. 데이타베이스 연결을 위해 JDBC API를 사용하는 Java 애플리케이션을 사용하면, AutoCommit.java 애플리케이션은 적절한 JDBC 드라이버(이 경우 Oracle Thin 드라이버)를 등록함으로써 시작하고 그런 다음, Connection 객체를 생성하여 데이타베이스에 연결합니다. (여러분은 java.sql.Connection 또는 oracle.jdbc.OracleConnection 객체를 사용할 수 있습니다. java.sql.Connection은 표준 JDBC인데 반해, oracle.jdbc.OracleConnection은 Oracle JDBC 확장이고 더 많은 기능과 더 높은 성능을 제공합니다.)

데이타베이스에 연결한 후에는 SQL 문(목록 1의 3단계)을 위한 문 객체를 생성합니다. 이 지점에서부터 프로그램은 데이타를 캡처하여 두 작업 모드의 성능 차이를 보여 줍니다. performance 테이블이 절단되어(단계 4 참조) 테이블에 존재하는 모든 행이 지워지고 나면, 자동 커밋이 활성화됩니다(Connection 객체(myConnection)에서 autoCommit() 메소드를 호출함). 프로그램은 1,000개의 행을 performance 테이블에 삽입하는 insertRows() 메소드를 호출합니다(SQL INSERT 문으로 구성되는 PreparedStatement 객체를 사용함). 프로그램은 삽입을 수행하는 데 걸린 시간을 1000분의 1초로 표시합니다. 그 다음 자동 커밋은 비활성화되고, performance 테이블이 절단되어 기존 데이타가 지워진 후 또 다른 1,000개의 행이 테이블에 삽입됩니다.

다음은 이 프로그램의 예제 실행입니다.

Enabling auto-commit mode Total time for inserting 1000 rows was 5688 milliseconds Disabling auto-commit mode Total time for inserting 1000 rows was 3515 milliseconds 

위에서 볼 수 있듯이 자동 커밋을 비활성화하면 성능이 현저히 향상됩니다. 또한 자동 커밋을 비활성화하는 것은 일반적으로 바람직한 정책이라고 할 수 있는데, 그 이유는 개발자인 여러분들이 애플리케이션의 비즈니스 로직에 대해 생각해야 하고 트랜잭션이 구별되는 방법을 결정해야 하기 때문입니다. 반면 자동 커밋을 활성화하는 것은 별로 좋지 않은 정책입니다. 왜냐하면 업데이트 일괄 처리(다음 단원에서 배우게 될 내용)를 비롯한 기타 많은 JDBC 성능 조정 기술은 자동 커밋이 비활성화되도록 요구하기 때문입니다.

성능 향상을 위해 업데이트 일괄 처리를 활용

기본적으로 여러분의 애플리케이션은 한 번에 하나씩 SQL 문을 데이타베이스로 보낼 것입니다. 생산 환경에서 애플리케이션은 보통 데이타베이스가 실행되는 컴퓨터와 다른 컴퓨터에서 실행되고, 여러분의 애플리케이션은 각 SQL 문을 네트워크를 통해 데이타베이스로 보냅니다. 데이타베이스는 이 SQL 문을 받아 실행하고 네트워크를 통해 다시 여러분의 애플리케이션으로 결과를 보냅니다. 이러한 전체 프로세스가 바로 라운드 트립(round trip)입니다.

상상할 수 있듯이 라운드 트립에는 상당히 오랜 시간이 걸리며, 한 번에 하나씩 SQL 문을 데이타베이스로 보내는 것은 일반적으로 비효율적입니다. 다행히도 여러분은 많은 SQL INSERT, UPDATE, DELETE 문을 일괄 처리로 묶을 수 있어 여러분의 애플리케이션은 이를 한 번에 데이타베이스로 보내서 실행할 수 있습니다. 따라서 라운드 트립의 횟수와 전체 처리 시간이 줄어 듭니다.

업데이트 일괄 처리는 동일한 기본 SQL INSERT, UPDATE, DELETE 문을 데이타베이스로 보낼 경우 효과가 좋습니다. 상이한 SQL 문을 일괄 처리에 추가할 경우 일괄 처리는 실행을 위해 즉시 데이타베이스로 전송되고, 상이한 SQL 문을 위한 새 일괄 처리가 생성됩니다. 이러한 이유로 인해 여러 가지 많은 SQL 문을 데이타베이스로 보내는 경우에는 업데이트 일괄 처리를 사용하는 것이 불편할 것입니다. 예를 들어 많은 INSERT 문을 데이타베이스로 보내는 경우 일괄 처리는 효과가 상당히 좋습니다. 하지만 INSERT, 뒤이어 UPDATE, 뒤이어 DELETE를 보내는 경우에는 업데이트 일괄 처리로 인한 이점을 얻을 수 없습니다.

Oracle JDBC는 서로 다른 두 가지 업데이트 일괄 처리 모델을 지원합니다.

  • · Java 표준 모델(Oracle 설명서에는 표준 업데이트 일괄 처리로 되어 있고, Sun 설명서에는 일괄 처리 업데이트로 되어 있음)
  • · JDBC에 대한 Oracle 확장을 지원하는 Oracle 특정 모델(Oracle 업데이트 일괄 처리)

대체적으로 Oracle 업데이트 일괄 처리가 표준 업데이트 일괄 처리보다 성능이 우수하다는 것을 알고 있을 것입니다. 그러나 Oracle 및 비 Oracle 데이타베이스 간의 코드 이식성이 중요하다면 표준 업데이트 일괄 처리를 사용해야 합니다. 표준 및 Oracle 업데이트 일괄 처리는 모두 SQL INSERT, UPDATE, DELETE 문과 비 LOB(large object) 데이타 유형에 대해서만 작용하므로 CLOB, BLOB, BFILE, LONG, LONG RAW 데이타는 일괄 처리 모드에 삽입할 수 없습니다. 일괄 처리는 SQL 문이 이러한 데이타 유형 중 한 가지를 포함하고 있으면 자동으로 비활성화됩니다.

여러분의 코드에서 사용하고 있는 객체의 유형은 또한 여러분이 사용해야 하는 업데이트 일괄 처리 모델을 지시합니다. 예를 들어 Oracle 업데이트 일괄 처리는 OraclePreparedStatement 객체와만 작용합니다. OraclePreparedStatement 객체는 더 많은 기능을 가지고 있다는 점을 제외하고는 PreparedStatement 객체와 비슷하여 Oracle 데이타베이스에서 사용할 수 있는 추가 기능을 처리합니다. 일반적으로 OraclePreparedStatement 객체는 또한 성능이 더 뛰어납니다.

여러분은 두 가지 일괄 처리 모델을 혼용할 수 없습니다. 즉, Oracle 업데이트 일괄 처리나 표준 업데이트 일괄 처리를 사용할 수 있지만 이 두 가지를 동시에 사용할 수는 없습니다. 다음 단원에서 각 일괄 처리 모델의 사용 방법에 대해 알아보도록 하겠습니다.

JDBC 액세스의 가속화
Step by Step: Speeding Up JDBC Access

저자: Jason Price

표준 JDBC의 업데이트 일괄 처리 사용 방법

앞에서 말한 것처럼 표준 업데이트 일괄 처리는 표준 JDBC의 일부로서, 비 Oracle 데이타베이스와의 코드 이식성이 중요한 경우에는 이 기술을 사용해야 합니다. 표준 업데이트 일괄 처리를 사용하면 다음과 같은 애플리케이션의 객체 유형이 수행하는 SQL 문을 일괄 처리할 수 있습니다.

Statement
OracleStatement
PreparedStatement
OraclePreparedStatement
CallableStatement
OracleCallableStatement

PreparedStatement 객체는 ?로 표시된 다른 값을 가진 동일한 SQL 문을 실행하는 데 재사용할 수 있는 선행 컴파일된 문입니다. CallableStatements 객체는 데이타베이스의 내장 프로시저입니다.

표준 JDBC에 대한 자세한 내용은 Statement, PreparedStatementCallableStatement 인터페이스에 대한 온라인 Javadocs를 참조하십시오.

Oracle* 객체들(OracleStatement 등)은 JDBC에 대한 Oracle 확장으로서, 여러분은 여전히 이러한 객체들로 표준 업데이트 일괄 처리를 사용할 수 있습니다. (JDBC에 대한 Oracle 확장, OracleStatement, OraclePreparedStatement 및 OracleCallableStatement에 관한 추가 정보는 Oracle9i JDBC Developer's Guide and Reference Release 2 (9.2)를 참조하십시오.

애플리케이션에서 표준 업데이트 일괄 처리를 사용하려면 다음의 다섯 가지 단계를 수행하십시오

1. 자동 커밋 모드를 비활성화합니다.
2. 문 객체를 생성합니다.
3. SQL 문을 일괄 처리에 추가합니다.
4. SQL 문 일괄 처리를 실행합니다.
5. 실행된 SQL 문 일괄 처리 전체를 커밋(또는 롤백)합니다.

1단계: 자동 커밋 모드를 비활성화합니다.

첫 번째 단계는 SQL 문 일괄 처리에 포함되어 있는 각 SQL 문이 일괄 처리가 전송된 후에 즉시 커밋되는 것을 방지하기 위해 자동 커밋을 비활성화 하는 것입니다. 앞에서 언급한 것처럼 여러분은 성능 때문에 자동 커밋을 비활성화하고 싶을 것입니다. 또한 자동 커밋을 비활성화하면 여러분이 일괄 처리를 실행하는 동안 오류가 발생하는 경우에 더 많은 제어를 가지게 되는데, 그 이유는 이미 실행된 일괄 처리에 포함된 문을 커밋할 것인지 롤백할 것인지 선택할 수 있기 때문입니다. 자동 커밋 모드가 활성화되어 있는 경우에는 문이 자동으로 커밋되므로 이러한 수준의 제어를 갖지 못 합니다. (오류 처리에 대한 자세한 내용은 이 기사의 뒷부분에서 설명할 것입니다.)

자동 커밋 모드를 비활성화 하려면 다음과 같이 Connection 객체의 setAutoCommit() 메소드의 부울을 false로 설정하면 됩니다.

myConnection.setAutoCommit(false);

2단계: 문 객체를 생성합니다.

두 번째 단계는 앞에서 열거한 문 유형(PreparedStatement, CallableStatement) 중 하나를 사용하여 적절한 문 객체를 생성하는 것입니다. 이 예는 한 행을 performance 테이블에 추가하기 위해 INSERT 문을 포함하는 PreparedStatement 객체(myPrepStatement)를 생성합니다.

PreparedStatement myPrepStatement =
  myConnection.prepareStatement(
    "INSERT INTO performance " +
    "(int_value, varchar2_value) VALUES (?, ?)"

  );

물음표(?)는 INSERT 문의 VALUES 절에서 값이 어디에 설정되는 지를 지시하는 위치 표시자입니다. 이 예에서는 performance 테이블의 int_value 및 varchar2_value 열에 값을 설정할 것입니다. 이 부분에 대해서는 다음 단계에서 살펴보겠습니다.

3단계: SQL 문을 일괄 처리에 추가합니다.

세 번째 단계는 SQL 문을 일괄 처리에 추가하는 것입니다. 트랜잭션에 있는 SQL 문의 개수에 따라 일괄 처리에 포함시킬 문의 개수를 정할 수 있습니다. 원하는 만큼의 문을 일괄 처리할 수는 있지만, 다수의 문을 일괄 처리하여 데이타베이스를 채워서는 안 됩니다. 5 ~ 30개의 SQL 문을 포함하는 일괄 처리가 가장 적당합니다. 이 예에서는 일괄 처리에 10개의 문이 포함되어 있습니다.

문 객체의 addBatch() 메소드를 사용하여 SQL 문을 일괄 처리에 추가합니다. 먼저 addBatch() 메소드를 호출하면 새 일괄 처리가 생성되고 첫 번째 SQL 문이 그 일괄 처리에 추가됩니다. 또 다른 SQL 문을 일괄 처리에 추가하려면 addBatch()를 다시 호출합니다. 필요한 만큼의 SQL 문을 추가한 다음 일괄 처리를 실행합니다. 일괄 처리를 실행하는 방법은 4단계에서 알 수 있습니다. 일괄 처리를 실행한 후 addBatch()를 다시 호출하면 새로운 일괄 처리가 생성되고, 모든 SQL 문을 실행할 때까지 이 과정이 반복됩니다.

이 아이디어를 구체화하려면 for 루프를 사용하여 문을 일괄 처리에 추가하는 코드를 살펴보아야 합니다. 이 루프는 myPrepStatement의 addBatch() 메소드를 사용하여 10개의 INSERT 문을 일괄 처리에 추가하고, INSERT 문의 두 개의 위치 표시자에 값을 설정합니다.

for (int count = 0; count < 10; count++) {
  myPrepStatement.setInt(1, count);
  myPrepStatement.setString(2, "Test" + count);
  myPrepStatement.executeUpdate();
}

setInt() 메소드는 정수를 위치 표시자에 할당하고, setString() 메소드는 문자열을 위치 표시자에 할당합니다. 이 메소드들은 각각 두 개의 매개변수(myPrepStatement의 위치 표시자의 수치 위치 및 이 위치 표시자의 값)를 받아들입니다. 예에서 setInt()의 첫 번째 매개변수는 1이고 INSERT 문의 int_value 행의 값을 지정하는 첫 번째 위치 표시자에 대응됩니다. 두 번째 매개변수는 count 변수로서, for 루프에서 위치 표시자에 0 ~ 9 값을 설정합니다. 비슷한 방식으로 setString() 메소드는 두 번째 위치 표시자에 "Test0" ~ "Test9" 문자열을 설정합니다. 이 루프의 마지막에서 일괄 처리는 각각 하나의 새로운 행을 performance 테이블에 추가(전체 10개의 행)할 10개의 INSERT 문을 포함하게 됩니다.

4단계: 문 일괄 처리를 실행합니다.

문 객체의 executeBatch() 메소드를 사용하여 문 일괄 처리를 실행합니다. 이 메소드는 문 일괄 처리를 데이타베이스에 보냅니다. 그런 다음 데이타베이스는 일괄 처리의 각 문을 실행하여 int 요소의 배열을 반환합니다.

다음 예에서는 myPrepStatement의 executeBatch() 메소드를 호출하는데, 이는 이전 단계에서 추가된 INSERT 문 일괄 처리를 실행하기 위해 데이타베이스에 보내는 것입니다.

int [] rowsInserted = myPrepStatement.executeBatch();

executeBatch()가 반환한 배열의 각 int 요소는 여러분이 사용하는 문 객체의 유형에 따라 서로 다른 것을 저장합니다. 다양한 문 객체에 대해 이러한 int 요소가 나타내는 것에 대해서는 "일괄 처리 오류 처리하기" 뒷부분의 "" 단원에서 알아볼 것입니다.

5단계: 실행된 문 일괄 처리를 커밋(또는 롤백)합니다.

일괄 처리에 포함된 모든 문을 실행한 후 연결 객체에서 commit() 또는 rollback() 메소드를 호출하여 마지막에는 일괄 처리를 커밋 또는 롤백해야 합니다. 예를 들어 myConnection이라는 이름의 연결 객체를 생성했다고 가정하면 다음과 같이 일괄 처리 전체를 커밋합니다.

myConnection.commit();

이는 4단계에서 실행됐던 10개의 INSERT 문을 커밋하게 됩니다. 일반적으로 Java 코드의 try{} 블록에서 커밋을 작성하고 catch{} 블록에서 롤백을 호출하는데, 이 catch 블록은 예외와 오류를 처리하는 곳입니다. 커밋은 일괄 처리된 문이 모두 오류 없이 실행된다는 것을 가정합니다. 다음 단원에서 배우게 될 내용을 참고하여 애플리케이션에서 오류를 적절하게 처리하십시오.

일괄 처리 오류 처리하기

일괄 처리에 포함된 SQL 문에 대한 오류가 발생하면 java.sql.BatchUpdateException 객체가 발생합니다. 여러분은 코드에서 이 예외 객체를 처리해야 하고 그 다음 BatchUpdateException 객체의 getUpdateCounts() 메소드를 호출해야 합니다.

getUpdateCounts() 메소드는 이전에 설명한 executeBatch() 메소드와 같은 값을 포함하고 있는 int 배열을 반환합니다. 또한 일반적으로 catch 블록에서 롤백을 수행하여 성공적으로 실행된 SQL 문을 실행 취소합니다.

다음의 코드 부분은 BatchUpdateException 객체를 처리하고 이 객체를 위해 getUpdateCounts() 메소드를 호출하는 방법을 보여 줍니다. commit() 메소드는 try 블록 내에서 호출되고 rollback() 메소드는 catch 블록 내에서 호출되어 성공적으로 실행된 SQL 문을 롤백합니다.

try {
  /*
    ... code that executes a batch of SQL statements
    using a statement object ...
  */

  myConnection.commit();
} catch (BatchUpdateException e) {
  int [] updateCounts = e.getUpdateCounts();
  myConnection.rollback();
}

getUpdateCounts() 메소드가 반환한 updateCounts int 배열은 SQL 문 일괄 처리를 수행하기 위해 try 블록에서 사용한 문 객체 유형(prepared 또는 callable)에 따라 여러 가지 값을 가지게 됩니다. 이러한 여러 가지 값들에 대해서는 다음 두 단원에서 설명할 것입니다. 여러분은 일괄 처리에 성공적으로 실행된 문을 롤백할 것인지 결정하기 전에 이러한 값들을 추가 확인으로 사용할 수 있습니다.

PreparedStatement 및 OraclePreparedStatement 객체의 배열 값

try 블록에서 PreparedStatement 또는 OraclePreparedStatement 객체를 사용하는 경우 updateCounts 배열의 int 요소는 일괄 처리의 모든 SQL 문이 성공적으로 실행되었는지를 나타냅니다. JDBC 드라이버가 일괄 처리의 어떤 SQL 문이 실패했는지를 정확하게 확인할 수 없기 때문에 int 요소 값은 일괄 처리의 모든 SQL 문에 적용됩니다.

int 요소가 -2 값을 가지고 있으면 일괄 처리된 모든 SQL 문이 성공적으로 실행된 것이며, int 요소가 -3 값을 가지고 있으면 일괄 처리된 문 중 하나 이상에 문제가 있다는 것을 뜻합니다.

예를 들어 10개의 INSERT 문 일괄 처리가 있는데 9번째 문까지는 성공했으나 10번째 문이 실패했다고 가정해 봅시다. 이 예가 그러한 경우라면 배열의 int 요소 10개 모두가 -3 값을 가지게 되어 하나 이상의 SQL 문에 문제가 있다는 것을 나타냅니다. 일부 SQL 문은 성공적으로 실행되었을 수도 있으므로 성공적으로 실행된 이 SQL 문을 롤백할 것인지 결정하기 전에 -3 값을 보고 추가로 확인할 수 있습니다.

다른 문 객체의 배열 값

try 블록에서 Statement, OracleStatement, CallableStatement, 또는 OracleCallableStatement 객체를 사용하는 경우, updateCounts 배열의 int 요소는 일괄 처리의 각 SQL 문으로부터 영향을 받은 행의 개수를 지정합니다.

예를 들어 2개의 DELETE 문 일괄 처리가 있는데 첫 번째 DELETE 문이 테이블에서 4개의 행을 제거했고 두 번째 DELETE 문이 테이블에서 2개의 행을 제거한 경우가 있다고 가정해 봅시다. 이 경우 updateCounts 배열은 2개의 int 요소를 가지는데 첫 번째 int은 4 값을 가지고 두 번째 int은 2 값을 가집니다. 이는 일괄 처리의 각 DELETE 문으로부터 영향을 받은 행의 개수를 나타내는 것입니다. 그러나 만약 일괄 처리의 두 번째 DELETE 문이 실패했다면 updateCounts 배열은 하나의 int 요소만 가지게 됩니다. 보다시피 예외가 있는 경우에는 updateCounts 배열의 요소의 개수는 1만큼 부족하게 됩니다. 여러분은 성공적으로 실행된 SQL 문을 롤백할 것인지 결정하기 전에 이 사실을 통해 추가로 확인할 수 있습니다.

예제 애플리케이션: StandardUpdateBatching.java

이름에서 짐작할 수 있듯이 StandardUpdateBatching.java 예제 프로그램(목록 2 참조)은 표준 업데이트 일괄 처리 사용 방법을 보여 줍니다. 이 클래스는 AutoCommit.java 예제에서처럼 Oracle JDBC Thin 드라이버를 등록하고, Connection 객체(scott 스키마를 통해)를 생성하며, 자동 커밋 모드를 비활성화합니다. 그런 다음 Statement 객체를 생성하고 performance 테이블을 절단하여 기존 행을 모두 지웁니다. 그리고 나서 애플리케이션은 일괄 처리 없이 1,000개의 행을 performance 테이블에 삽입하고, 삽입에 걸린 시간을 1000분의 1초로 표시합니다. (애플리케이션에 정의되어 있는 insertRows() 메소드가 삽입을 수행합니다.

다음으로 애플리케이션은 performance 테이블을 지우고 이번에는 표준 업데이트 일괄 처리를 사용하여 또 다른 1,000개의 행을 삽입합니다. 표준 업데이트 일괄 처리는 개발자에게 프로그래밍 로직을 기반으로 하여 명시적으로 일괄 처리를 실행할 것을 요구하기 때문에 이 예제에서는 10개의 SQL 문 크기의 일괄 처리를 사용하는 간단한 카운터 메커니즘을 사용하고 있습니다. "실제" 애플리케이션에서는 비즈니스 수준의 트랜잭션에 대응하는 다양한 문으로 구성된 일괄 처리를 생성하는 것과 같은 다른 로직을 사용하게 됩니다. Statement 및 Connection 객체가 닫힌 후에 삽입에 걸린 시간이 다시 표시됩니다. 애플리케이션 실행 출력 결과는 다음과 같습니다.

Inserting 1000 rows without batching
Total time for inserting 1000 rows was 4286 milliseconds
Inserting 1000 rows with standard update batching
Total time for inserting 1000 rows was 521 milliseconds

이 엄청난 결과에 주목하십시오. 일괄 처리를 사용하지 않은 경우보다 표준 업데이트 일괄 처리를 사용한 경우에 성능이 약 8배나 빠른 것으로 나타났습니다.

JDBC 액세스의 가속화
Step by Step: Speeding Up JDBC Access

저자: Jason Price

Oracle 확장의 업데이트 일괄 처리 사용 방법

앞에서 언급했듯이 Oracle 업데이트 일괄 처리는 일반적으로 표준 JDBC 업데이트 일괄 처리보다 빠르고 기능도 더 많습니다. 그렇지만 Oracle 업데이트 일괄 처리는 OraclePreparedStatement 객체와만 사용할 수 있다는 제한 사항이 있습니다. 따라서 JDBC PreparedStatement 객체를 포함한 코드를 사용하여 작업하고 있는 경우 Oracle 업데이트 일괄 처리를 사용하기 전에 JDBC PreparedStatement 객체를 OraclePreparedStatement 객체로 변환해야 합니다.

Oracle 업데이트 일괄 처리는 먼저 일괄 처리 값(일괄 처리에서 허용된 SQL 문의 최대 개수)을 설정한다는 점에서 표준 업데이트 일괄 처리와 다릅니다. addBatch() 또는 비슷한 메소드를 사용하여 SQL 문을 일괄 처리에 추가하는 대신, SQL 문을 자동으로 일괄 처리에 추가하는 executeUpdate() 메소드를 OraclePreparedStatement 객체에서 호출할 수 있습니다. 일괄 처리의 SQL 문의 개수가 정해진 일괄 처리 값에 도달하면 일괄 처리는 자동으로 실행을 위해 데이타베이스로 보내집니다. 예제 애플리케이션에서 일괄 처리 값은 10인데, 이는 10번째 executeUpdate()에서 10개의 INSERT 문 일괄 처리가 데이타베이스로 보내진다는 것을 뜻합니다.

최적의 일괄 처리 크기는 여러 요소에 따라 달라지기는 하지만 최적의 결과를 위한 좋은 법칙은 일괄 처리 값을 5 ~ 30(SQL 문의 개수)으로 두는 것입니다.

Oracle 업데이트 일괄 처리가 대개 표준 업데이트 일괄 처리보다 빠른 이유 중 하나는 일괄 처리 값 설정 때문입니다. JDBC 드라이버는 한 번에 몇 개의 SQL 문이 일괄 처리되는지 알기 때문에 일괄 처리 값을 근거로 하여 최적화할 수 있습니다.

Oracle 업데이트 일괄 처리의 경우 다음과 같이 코딩해야 합니다.

1. 자동 커밋 모드를 비활성화합니다.
2. 일괄 처리 값을 설정합니다.
3. SQL 문을 일괄 처리합니다.
4. 실행된 문을 커밋합니다.

1단계: 자동 커밋 모드를 비활성화합니다.

먼저 다음과 같이 Connection 객체의 setAutoCommit() 메소드의 부울을 false로 설정하여 자동 커밋을 비활성화합니다.

myConnection.setAutoCommit(false);

2단계: 일괄 처리 값을 설정합니다.

OracleConnection 또는 OraclePreparedStatement 객체에 대한 일괄 처리 값을 설정할 수 있습니다. OracleConnection 객체에 대한 일괄 처리 값을 설정하면 OracleConnection과 함께 생성되는 OraclePreparedStatement 객체는 자동으로 같은 일괄 처리 값을 사용하게 됩니다. 만약 OraclePreparedStatement 객체에 대한 일괄 처리 값을 설정할 경우, 이 일괄 처리 값은 이전에 OracleConnection 객체에 대해 설정했던 일괄 처리 값을 무효화합니다. OracleConnection 또는 OraclePreparedStatement 객체에 대한 기본 일괄 처리 값은 1이며, 이는 SQL 문이 일괄 처리되지는 않지만 한 번에 하나씩 데이타베이스로 보내진다는 것을 의미합니다.

다음 두 단원에서는 OracleConnection 객체와 OraclePreparedStatement 객체에 대한 각각의 일괄 처리 값 설정 방법을 살펴보도록 하겠습니다.

OracleConnection 객체에 대한 일괄 처리 값 설정

OracleConnection 객체에 대한 일괄 처리 값을 설정하려면 setDefaultExecuteBatch() 메소드를 사용합니다. 이 메소드는 다음과 같이 일괄 처리 값에 대한 int 매개변수를 받아들입니다.

myOracleConnection.setDefaultExecuteBatch(10);

여기서 myOracleConnection(OracleConnection 객체)는 일괄 처리를 위해 최대 10개의 SQL 문까지 설정됩니다.

또한 다음 예와 같이 기존의 연결 객체를 OracleConnection 객체로 변환한 다음 setDefaultExecuteBatch() 메소드를 호출할 수 있습니다.

((OracleConnection) myConnection).setDefaultExecuteBatch(10);

일반 Java 연결 객체인 myConnection 객체는 OracleConnection로 변환되고, 그 다음 setDefaultExecuteBatch() 메소드를 호출합니다.

OracleConnection 객체의 현재 일괄 처리 값 설정을 확인하려면 getDefaultExecuteBatch() 메소드를 사용합니다.

int batchSize = myOracleConnection.getDefaultExecuteBatch();

getDefaultExecuteBatch() 메소드는 int 값을 반환하는데 이 경우에는 그 값이 10이고, 이는 myOracleConnection 객체에 대한 일괄 처리 값을 10으로 설정했기 때문입니다.

OraclePreparedStatement 객체에 대한 일괄 처리 값 설정

setDefaultExecuteBatch() 메소드를 사용하면 OraclePreparedStatement 객체에 대한 일괄 처리 값을 설정할 수 있습니다. 이 메소드는 일괄 처리 값을 포함하고 있는 int 매개변수를 받아들이며, 이 값은 OracleConnection 객체에 대한 일괄 처리 값을 무효화합니다.

예를 들어 INSERT 문을 포함하고 있는 myOraclePrepStatement라는 이름의 OraclePreparedStatement 객체를 가지고 있다고 가정합시다.

OraclePreparedStatement myOraclePrepStatement =
  (OraclePreparedStatement) myConnection.prepareStatement(
    "INSERT INTO performance " +
    "(int_value, varchar2_value) VALUES (?, ?)"
  );

여기에서 INSERT 문은 표준 업데이트 일괄 처리 예에 있던 INSERT 문과 동일합니다. 첫 번째 위치 표시자는 int_value 열의 값을 지정하고, 두 번째 위치 표시자는 varchar2_value 열의 값을 지정합니다. 그 다음 myOraclePrepStatement의 setDefaultExecuteBatch() 메소드를 사용하여 일괄 처리 값을 20으로 설정합니다.

myOraclePrepStatement.setExecuteBatch(20);

이 일괄 처리 값은 이전에 myConnection에 대해 설정했던 일괄 처리 값 10을 무효화하므로, 데이타베이스로 전송되기 전에 myOraclePrepStatement를 사용하여 20개의 SQL 문을 일괄 처리할 수 있습니다.

getDefaultExecuteBatch() 메소드를 통해 OraclePreparedStatement 객체에 대한 현재 일괄 처리 값을 확인할 수 있습니다. 예를 들면 다음과 같습니다.

System.out.println("Batch value = " +
  myOraclePrepStatement.getExecuteBatch());

다음 단계는 SQL 문을 일괄 처리하는 것입니다.

3단계: SQL 문을 일괄 처리합니다.

일단 일괄 처리 값을 설정하면, SQL 문을 일괄 처리에 추가하기 위해 해야 하는 일은 OraclePreparedStatement 객체의 executeUpdate() 메소드를 호출하는 것이 전부입니다. 일괄 처리의 SQL 문의 개수가 일괄 처리 값에 도달하면, 일괄 처리는 자동으로 실행을 위해 데이타베이스로 보내집니다.

이 예는 20개의 INSERT 문을 일괄 처리에 추가하는 for 루프를 보여 주는데, 이는 각 INSERT 문에 대해 int_value 열의 값을 0 ~ 19로, varchar2_value 열의 값을 Test0 ~ Test19로 설정합니다.

for (int count = 0; count < 20; count++) {
  myOraclePrepStatement.setInt(1, count);
  myOraclePrepStatement.setString(2, "Test" + count);
  int rowsInserted = myOraclePrepStatement.executeUpdate();
}

2단계에서 myOraclePrepStatement 객체에 대한 일괄 처리 값을 20으로 설정했기 때문에 20번째 INSERT 문이 일괄 처리에 추가되면 일괄 처리는 자동으로 실행을 위해 데이타베이스로 보내집니다.

executeUpdate() 메소드가 반환하는 int 값은 SQL 문으로부터 영향을 받은 행의 개수입니다. SQL 문이 일괄 처리된 다음 하나의 단위로서 데이타베이스로 전송되었기 때문에, 반환된 이 int 값은 executeUpdate() 메소드가 단지 하나의 SQL 문을 일괄 처리에 추가하는 경우 0이 됩니다(SQL 문은 아직 실행되지 않았기 때문에 어떠한 행에도 영향을 주지 않았습니다). 그러나 executeUpdate() 메소드가 실행을 위해 실제로 일괄 처리 전체를 데이타베이스로 보내면, 반환된 int 값은 함께 추가된 모든 일괄 처리된 SQL 문으로부터 영향을 받은 행의 총 개수가 됩니다.

그러므로 for 루프의 예에서 executeUpdate()가 반환하는 int 값은 루프의 19번째 반복까지는 0이 됩니다(왜냐하면 INSERT 문은 일괄 처리에 추가만 되었고 실제로 실행되지는 않았기 때문입니다). 그러나 20번째 반복에서 일괄 처리는 데이타베이스로 보내지고 모든 문이 실행되므로 반환된 int 값은 20(20개의 일괄 처리된 INSERT 문에 의해 데이타베이스에 추가된 행의 개수)이 됩니다.

4단계: 실행된 문을 커밋합니다.

네 번째 단계는 Connection 객체에서 commit() 또는 rollback() 메소드를 호출하는 것입니다. 예를 들어 myConnection이라는 연결 객체를 생성했다면 다음과 같이 일괄 처리 전체를 커밋합니다.

myConnection.commit();

일괄 처리 강제 실행

또한 일괄 처리가 채워지기 전에 일괄 처리를 강제로 실행할 수 있습니다. 즉, sendBatch() 메소드를 호출하면 일괄 처리를 강제로 실행할 수 있습니다. 보통은 일괄 처리가 가득차지 않더라도 여러분이 커밋을 수행할 때마다 일괄 처리를 데이타베이스로 보낼 수 있기 때문에 이 메소드를 사용할 필요가 없습니다. 그러나 일괄 처리를 강제로 실행하고 싶은 경우가 생길 수도 있습니다.

sendBatch() 사용의 예를 살펴봅시다. 3개의 INSERT 문을 일괄 처리에 추가하는 경우가 있다고 가정합시다. 이 경우 다음과 같이 sendBatch()를 호출하고 OraclePreparedStatement 객체를 사용하여 이 3개의 문을 강제로 실행할 수 있습니다.

int rowsInserted = myOraclePrepStatement.sendBatch();

sendBatch() 메소드는 일괄 처리의 SQL 문으로부터 영향을 받은 행의 개수인 int 값을 반환합니다. 여기에서는 각 INSERT 문이 하나의 행만 삽입한다는 가정 하에서 sendBatch()가 일괄 처리의 문이 삽입한 행의 개수인 3을 반환하게 됩니다..

예제 애플리케이션: OracleUpdateBatching.java

OracleUpdateBatching.java 애플리케이션(목록 3 참조)은 Oracle 업데이트 일괄 처리의 사용 방법 및 성능에 미친 영향을 나타냅니다. 이 프로그램은 다음 사항을 수행합니다.

1. Oracle JDBC 드라이버를 등록합니다.
2. Connection 객체를 생성하고 사용자 scott으로서 데이타베이스에 연결합니다.
3. 자동 커밋 모드를 비활성화합니다.
4. 문 객체를 생성합니다.
5. performance 테이블을 절단합니다.
6. 일괄 처리를 사용하지 않으면서 1,000개의 행을 performance 테이블에 삽입하고, 삽입에 걸린 전체 시간을 1000분의 1초로 표시합니다. 애플리케이션에 정의되어 있는 insertRows() 메소드가 삽입을 수행합니다.
7. performance 테이블을 다시 절단하여 데이타를 지웁니다.
8. 이번에는 Oracle 업데이트 일괄 처리를 사용하여 다시 1,000개의 행을 performance 테이블에 삽입합니다. OraclePreparedStatement 객체에 대한 일괄 처리 값을 10으로 설정합니다.
9. 문과 Connection 객체를 닫습니다.

이 프로그램 실행의 예제 출력 결과는 다음과 같습니다.

Inserting 1000 rows without batching
Batch value = 1
Total time for inserting 1000 rows was 3785 milliseconds
Inserting 1000 rows with Oracle update batching
Setting the batch value to 10
Batch value = 10
Total time for inserting 1000 rows was 461 milliseconds

이 결과를 표준 업데이트 일괄 처리 결과와 비교해 보면 Oracle 업데이트 일괄 처리가 더 빠르다는 것을 알 수 있습니다. 삽입될 행의 값과 일괄 처리 값을 수정하면 결과는 더욱 분명해집니다. 예를 들어 일괄 처리 값을 50, 삽입될 행의 값을 10,000으로 하여 실행하면 업데이트 일괄 처리를 사용하지 않고 실행했을 때보다 25배나 더 빨라집니다

개선의 여지는 항상 있습니다.

Java 애플리케이션의 성능을 향상시키기 위해 자동 커밋 모드를 비활성화하고 표준 또는 Oracle 업데이트 일괄 처리를 사용하는 것은 애플리케이션의 성능을 높이기 위한 두 가지 성능 조정 기술입니다. 이러한 성능 조정 기술에 관한 자세한 내용이나 다중 행 사전 인출(prefetching), 결과 집합 열 사전 정의, 재사용을 위한 문 캐싱 및 SQL 문 조정 등 기타 다른 기술에 대해서는 본인이 집필한 Oracle9i JDBC Programming(McGraw-Hill/Osborne, 2002).을 참조하시기 바랍니다.

Jason Price (jmprice_314159@yahoo.com)는 소프트웨어 업계에서 10년 이상 몸담고 있는 Oracle 공인 데이타베이스 관리자 및 애플리케이션 개발자입니다. 기술 컨설턴트이자 테크니컬 라이터인 Price는 Oracle9i JDBC Programming(McGraw-Hill/Osborne, 2002)과 Java Programming with Oracle SQLJ(O'Reilly, 2001)의 저자이기도 합니다.

펌 : http://blog.naver.com/honeyc?Redirect=Log&logNo=80017058804

Posted by is윤군

댓글을 달아 주세요