Connecting with DataSource Objects
DataSource 객체 연결하기
이 섹션에서는 데이터 소스에 대한 연결을 얻는 기본 방법인 DataSource 객체를 다룹니다. 다른 장점 외에도 DataSource 객체는 Connection Pooling 및 분산 트랜잭션을 제공할 수 있습니다. 이 기능은 엔터프라이즈 데이터베이스 컴퓨팅에 필수적입니다. 특히 Enterprise JavaBeans(EJB) 기술의 핵심입니다.
이 섹션에서는 DataSource 인터페이스를 사용하여 연결을 얻는 방법과 분산 트랜잭션 및 연결 풀링을 사용하는 방법을 보여줍니다. 이 두 가지 모두 JDBC 애플리케이션에서 코드 변경이 거의 필요하지 않습니다.
시스템 관리자가 도구(예: Apache Tomcat 또는 Oracle WebLogic Server)를 사용하여 일반적으로 수행하는 이러한 작업을 가능하게 하는 클래스를 배포하는 작업은 배포되는 DataSource 객체의 유형에 따라 다릅니다. 결과적으로 이 섹션의 대부분은 프로그래머가 DataSource 객체를 사용하여 연결을 얻을 수 있도록 시스템 관리자가 환경을 설정하는 방법을 보여주는 데 할애됩니다.
다음 주제를 다룹니다.
- DataSource 객체를 사용하여 연결 얻기
- 기본 DataSource 객체 배포
- 기타 DataSource 구현 배포
- 풀링된 연결 가져오기 및 사용
- 분산 트랜잭션 배포
- 분산 트랜잭션에 연결 사용
- DataSource 객체를 사용하여 연결 얻기
- 연결 설정에서 DriverManager 클래스를 사용하여 연결을 얻는 방법을 배웠습니다. 이 섹션에서는 선호되는 방법인 DataSource 객체를 사용하여 데이터 소스에 대한 연결을 얻는 방법을 보여줍니다.
DataSource를 구현하는 클래스에 의해 인스턴스화된 객체는 특정 DBMS 또는 파일과 같은 다른 데이터 소스를 나타냅니다. DataSource 객체는 특정 DBMS 또는 파일과 같은 다른 데이터 소스를 나타냅니다. 회사가 둘 이상의 데이터 소스를 사용하는 경우 각 데이터 소스에 대해 별도의 DataSource 객체를 배포합니다. DataSource 인터페이스는 드라이버 공급업체에서 구현합니다. 다음과 같은 세 가지 다른 방법으로 구현할 수 있습니다.
- 기본 DataSource 구현은 풀링되지 않거나 분산 트랜잭션에 사용되지 않는 표준 연결 객체를 생성합니다.
- Connection Pooling을 지원하는 DataSource 구현은 연결 풀링에 참여하는 연결 객체(즉, 재활용할 수 있는 연결)를 생성합니다.
- 분산 트랜잭션을 지원하는 DataSource 구현은 분산 트랜잭션(즉, 둘 이상의 DBMS 서버에 액세스하는 트랜잭션)에 사용할 수 있는 연결 객체를 생성합니다.
JDBC 드라이버는 최소한 기본 DataSource 구현을 포함해야 합니다. 예를 들어, Java DB JDBC 드라이버에는 org.apache.derby.jdbc.ClientDataSource 구현이 포함되어 있고 MySQL의 경우 com.mysql.jdbc.jdbc2.optional.MysqlDataSource가 포함되어 있습니다. 클라이언트가 Java 8 컴팩트 프로필 2에서 실행되는 경우 Java DB JDBC 드라이버는 org.apache.derby.jdbc.BasicClientDataSource40입니다. 이 튜토리얼의 샘플에는 컴팩트 프로필 3 이상이 필요합니다.
분산 트랜잭션을 지원하는 DataSource 클래스는 일반적으로 연결 풀링에 대한 지원도 구현합니다. 예를 들어, EJB 공급업체에서 제공하는 DataSource 클래스는 거의 항상 연결 풀링과 분산 트랜잭션을 모두 지원합니다.
이전 예제의 번창하는 커피 브레이크 체인점 소유자가 인터넷을 통해 커피를 판매하여 사업을 더욱 확장하기로 결정했다고 가정합니다. 예상되는 많은 온라인 비즈니스를 통해 소유자는 연결 풀링이 반드시 필요할 것입니다. 연결을 열고 닫는 데는 많은 오버헤드가 발생하며, 소유자는 이 온라인 주문 시스템에 상당한 수의 쿼리 및 업데이트가 필요할 것으로 예상합니다. 커넥션 풀링을 사용하면 커넥션 풀을 반복해서 사용하여 모든 데이터베이스 액세스에 대해 새 연결을 생성하는 비용을 피할 수 있습니다. 또한 소유자는 최근 인수한 커피 로스팅 회사의 데이터를 포함하는 두 번째 DBMS를 보유하고 있습니다. 즉, 소유자는 이전 DBMS 서버와 새 DBMS 서버를 모두 사용하는 분산 트랜잭션을 작성할 수 있기를 원할 것입니다.
체인점 소유자는 새로운 대규모 고객 기반을 지원하기 위해 컴퓨터 시스템을 재구성했습니다. 소유자는 분산 트랜잭션을 사용하고 연결 풀링으로 제공되는 성능 향상을 얻기 위해 최신 JDBC 드라이버와 함께 작동하는 EJB 애플리케이션 서버를 구입했습니다. 최근 구입한 EJB 서버와 호환되는 많은 JDBC 드라이버를 사용할 수 있습니다. 소유자는 이제 중간 계층에 새로운 EJB 애플리케이션 서버와 JDBC 드라이버가 있고 세 번째 계층에 두 개의 DBMS 서버가 있는 3계층 아키텍처를 갖추고 있습니다. 요청하는 클라이언트 컴퓨터는 첫 번째 계층입니다.
기본 DataSource 객체 배포
시스템 관리자는 커피 브레이크 프로그래밍 팀이 DataSource 객체를 사용할 수 있도록 배포해야 합니다. DataSource 객체를 배포하는 것은 세 가지 작업으로 구성됩니다.
- DataSource 클래스의 인스턴스 생성
- 속성 설정
- JNDI(Java Naming and Directory Interface) API를 사용하는 명명 서비스에 등록
먼저 연결 풀링 또는 분산 트랜잭션을 지원하지 않는 DataSource 인터페이스의 기본 구현을 사용하는 가장 기본적인 경우를 고려하십시오. 이 경우 배포해야 하는 DataSource 객체는 하나뿐입니다. DataSource의 기본 구현은 DriverManager 클래스가 생성하는 것과 동일한 유형의 연결을 생성합니다.
DataSource 클래스의 인스턴스 생성 및 속성 설정
기본 DataSource 구현만 원하는 회사가 JDBC 공급업체 DB Access, Inc.에서 드라이버를 구입했다고 가정합니다. 이 드라이버에는 DataSource 인터페이스를 구현하는 com.dbaccess.BasicDataSource 클래스가 포함되어 있습니다. 다음 코드 발췌문은 BasicDataSource 클래스의 인스턴스를 생성하고 해당 속성을 설정합니다. BasicDataSource의 인스턴스가 배포된 후 프로그래머는 DataSource.getConnection 메서드를 호출하여 회사의 데이터베이스인 CUSTOMER_ACCOUNTS에 대한 연결을 얻을 수 있습니다. 먼저 시스템 관리자는 기본 생성자를 사용하여 BasicDataSource 객체 ds를 생성합니다. 그런 다음 시스템 관리자는 세 가지 속성을 설정합니다. 다음 코드는 일반적으로 배포 도구에서 실행됩니다.
com.dbaccess.BasicDataSource ds = new com.dbaccess.BasicDataSource();
ds.setServerName("grinder");
ds.setDatabaseName("CUSTOMER_ACCOUNTS");
ds.setDescription("Customer accounts database for billing");
이제 변수 ds는 서버에 설치된 데이터베이스 CUSTOMER_ACCOUNTS를 나타냅니다. BasicDataSource 객체 ds에서 생성된 모든 연결은 데이터베이스 CUSTOMER_ACCOUNTS에 대한 연결입니다.
JNDI API를 사용하는 명명 서비스에 DataSource 객체 등록
속성이 설정되면 시스템 관리자는 BasicDataSource 객체를 JNDI(Java Naming and Directory Interface) 명명 서비스에 등록할 수 있습니다. 사용되는 특정 명명 서비스는 일반적으로 시스템 속성에 의해 결정되며 여기에는 표시되지 않습니다. 다음 코드 발췌문은 BasicDataSource 객체를 등록하고 논리적 이름 jdbc/billingDB에 바인딩합니다.
Context ctx = new InitialContext();
ctx.bind("jdbc/billingDB", ds);
이 코드는 JNDI API를 사용합니다. 첫 번째 줄은 파일 시스템의 루트 디렉토리와 유사하게 이름의 시작점 역할을 하는 InitialContext 객체를 생성합니다. 두 번째 줄은 BasicDataSource 객체 ds를 논리적 이름 jdbc/billingDB에 연결하거나 바인딩합니다. 다음 코드 발췌문에서는 명명 서비스에 이 논리적 이름을 제공하고 BasicDataSource 객체를 반환합니다. 논리적 이름은 모든 문자열일 수 있습니다. 이 경우 회사는 CUSTOMER_ACCOUNTS 데이터베이스의 논리적 이름으로 billingDB 이름을 사용하기로 결정했습니다.
이전 예제에서 jdbc는 파일 시스템의 루트 디렉토리 아래의 디렉토리가 하위 디렉토리인 것처럼 초기 컨텍스트 아래의 하위 컨텍스트입니다. 이름 jdbc/billingDB는 경로 이름과 유사하며 경로의 마지막 항목은 파일 이름과 유사합니다. 이 경우 billingDB는 BasicDataSource 객체 ds에 지정된 논리적 이름입니다. 하위 컨텍스트 jdbc는 DataSource 객체에 바인딩할 논리적 이름을 위해 예약되어 있으므로 jdbc는 항상 데이터 소스의 논리적 이름의 첫 번째 부분이 됩니다.
배포된 DataSource 객체 사용
시스템 관리자가 기본 DataSource 구현을 배포한 후 프로그래머가 사용할 준비가 되었습니다. 즉, 프로그래머는 DataSource 클래스의 인스턴스에 바인딩된 논리적 데이터 소스 이름을 제공할 수 있으며 JNDI 명명 서비스는 해당 DataSource 클래스의 인스턴스를 반환합니다. 그런 다음 getConnection 메서드를 해당 DataSource 객체에서 호출하여 해당 객체가 나타내는 데이터 소스에 대한 연결을 얻을 수 있습니다. 예를 들어, 프로그래머는 다음 두 줄의 코드를 작성하여 데이터베이스 CUSTOMER_ACCOUNTS에 대한 연결을 생성하는 DataSource 객체를 얻을 수 있습니다.
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/billingDB");
첫 번째 코드 줄은 DataSource 객체를 검색하기 위한 시작점으로 초기 컨텍스트를 가져옵니다. 논리적 이름 jdbc/billingDB를 lookup 메서드에 제공하면 메서드는 시스템 관리자가 배포 시 jdbc/billingDB에 바인딩한 DataSource 객체를 반환합니다. lookup 메서드의 반환 값은 Java 객체이므로 변수 ds에 할당하기 전에 더 구체적인 DataSource 유형으로 캐스팅해야 합니다.
변수 ds는 DataSource 인터페이스를 구현하는 com.dbaccess.BasicDataSource 클래스의 인스턴스입니다. ds.getConnection 메서드를 호출하면 CUSTOMER_ACCOUNTS 데이터베이스에 대한 연결이 생성됩니다.
Connection con = ds.getConnection("fernanda","brewed");
getConnection 메서드는 변수 ds에 데이터베이스 이름 및 위치와 같은 CUSTOMER_ACCOUNTS 데이터베이스와의 연결을 설정하는 데 필요한 나머지 정보가 있으므로 사용자 이름과 암호만 필요합니다.
DataSource 객체의 장점
해당 속성 때문에 DataSource 객체는 연결을 얻기 위한 DriverManager 클래스보다 더 나은 대안입니다. 프로그래머는 더 이상 애플리케이션에 드라이버 이름이나 JDBC URL을 하드 코딩할 필요가 없으므로 이식성이 향상됩니다. 또한 DataSource 속성을 사용하면 코드 유지 관리가 훨씬 간단해집니다. 변경 사항이 있는 경우 시스템 관리자는 데이터 소스 속성을 업데이트하고 데이터 소스에 연결하는 모든 애플리케이션을 변경하는 것에 대해 걱정할 필요가 없습니다. 예를 들어 데이터 소스가 다른 서버로 이동된 경우 시스템 관리자는 serverName 속성을 새 서버 이름으로 설정하기만 하면 됩니다.
이식성 및 유지 관리 용이성 외에도 DataSource 객체를 사용하여 연결을 얻으면 다른 이점을 얻을 수 있습니다. DataSource 인터페이스가 ConnectionPoolDataSource 구현과 함께 작동하도록 구현되면 해당 DataSource 클래스의 인스턴스에서 생성된 모든 연결은 자동으로 풀링된 연결이 됩니다. 마찬가지로 DataSource 구현이 XADataSource 클래스와 함께 작동하도록 구현되면 생성되는 모든 연결은 자동으로 분산 트랜잭션에 사용할 수 있는 연결이 됩니다. 다음 섹션에서는 이러한 유형의 DataSource 구현을 배포하는 방법을 보여줍니다.
기타 DataSource 구현 배포
시스템 관리자 또는 해당 역할을 수행하는 다른 사람은 생성하는 연결이 풀링된 연결이 되도록 DataSource 객체를 배포할 수 있습니다. 이렇게 하려면 먼저 ConnectionPoolDataSource 객체를 배포한 다음 함께 작동하도록 구현된 DataSource 객체를 배포합니다. ConnectionPoolDataSource 객체의 속성은 연결이 생성될 데이터 소스를 나타내도록 설정됩니다. ConnectionPoolDataSource 객체가 JNDI 명명 서비스에 등록된 후 DataSource 객체가 배포됩니다. 일반적으로 DataSource 객체에 대해 description 및 dataSourceName의 두 가지 속성만 설정해야 합니다. dataSourceName 속성에 제공된 값은 이전에 배포된 ConnectionPoolDataSource 객체를 식별하는 논리적 이름이며, 연결을 만드는 데 필요한 속성을 포함하는 객체입니다.
ConnectionPoolDataSource 및 DataSource 객체가 배포되면 DataSource 객체에서 DataSource.getConnection 메서드를 호출하고 풀링된 연결을 얻을 수 있습니다. 이 연결은 ConnectionPoolDataSource 객체의 속성에 지정된 데이터 소스에 대한 연결입니다.
다음 예에서는 커피 브레이크의 시스템 관리자가 풀링된 연결을 제공하도록 구현된 DataSource 객체를 배포하는 방법을 설명합니다. 시스템 관리자는 일반적으로 배포 도구를 사용하므로 이 섹션에 표시된 코드 조각은 배포 도구가 실행하는 코드입니다.
성능 향상을 위해 커피 브레이크 회사는 ConnectionPoolDataSource 인터페이스를 구현하는 com.dbaccess.ConnectionPoolDS 클래스를 포함하는 DB Access, Inc.에서 JDBC 드라이버를 구입했습니다. 시스템 관리자는 이 클래스의 인스턴스를 생성하고 해당 속성을 설정하고 JNDI 명명 서비스에 등록합니다. 커피 브레이크는 EJB 서버 공급업체인 Application Logic, Inc.에서 DataSource 클래스인 com.applogic.PooledDataSource를 구입했습니다. com.applogic.PooledDataSource 클래스는 ConnectionPoolDataSource 클래스 com.dbaccess.ConnectionPoolDS에서 제공하는 기본 지원을 사용하여 연결 풀링을 구현합니다.
ConnectionPoolDataSource 객체를 먼저 배포해야 합니다. 다음 코드는 com.dbaccess.ConnectionPoolDS의 인스턴스를 생성하고 해당 속성을 설정합니다.
com.dbaccess.ConnectionPoolDS cpds = new com.dbaccess.ConnectionPoolDS();
cpds.setServerName("creamer");
cpds.setDatabaseName("COFFEEBREAK");
cpds.setPortNumber(9040);
cpds.setDescription("Connection pooling for " + "COFFEEBREAK DBMS");
ConnectionPoolDataSource 객체가 배포된 후 시스템 관리자는 DataSource 객체를 배포합니다. 다음 코드는 com.dbaccess.ConnectionPoolDS 객체 cpds를 JNDI 명명 서비스에 등록합니다. cpds 변수와 연결된 논리적 이름에 계층적 파일 시스템에서 다른 하위 디렉토리에 하위 디렉토리를 추가하는 것과 유사하게 하위 컨텍스트 jdbc 아래에 하위 컨텍스트 풀이 추가됩니다. com.dbaccess.ConnectionPoolDS 클래스의 모든 인스턴스의 논리적 이름은 항상 jdbc/pool로 시작됩니다. Oracle은 모든 ConnectionPoolDataSource 객체를 하위 컨텍스트 jdbc/pool 아래에 배치할 것을 권장합니다.
Context ctx = new InitialContext();
ctx.bind("jdbc/pool/fastCoffeeDB", cpds);
다음으로 cpds 변수 및 com.dbaccess.ConnectionPoolDS 클래스의 다른 인스턴스와 상호 작용하도록 구현된 DataSource 클래스가 배포됩니다. 다음 코드는 이 클래스의 인스턴스를 생성하고 해당 속성을 설정합니다. 이 com.applogic.PooledDataSource 인스턴스에 대해 두 가지 속성만 설정됩니다. description 속성은 항상 필요하므로 설정됩니다. 설정된 다른 속성인 dataSourceName은 com.dbaccess.ConnectionPoolDS 클래스의 인스턴스인 cpds의 논리적 JNDI 이름을 제공합니다. 즉, cpds는 DataSource 객체에 대한 연결 풀링을 구현할 ConnectionPoolDataSource 객체를 나타냅니다.
배포 도구에서 실행될 가능성이 높은 다음 코드는 PooledDataSource 객체를 생성하고 해당 속성을 설정하고 논리적 이름 jdbc/fastCoffeeDB에 바인딩합니다.
com.applogic.PooledDataSource ds = new com.applogic.PooledDataSource();
ds.setDescription("produces pooled connections to COFFEEBREAK");
ds.setDataSourceName("jdbc/pool/fastCoffeeDB");
Context ctx = new InitialContext();
ctx.bind("jdbc/fastCoffeeDB", ds);
이 시점에서 애플리케이션이 데이터베이스 COFFEEBREAK에 대한 풀링된 연결을 얻을 수 있는 DataSource 객체가 배포됩니다.
풀링된 연결 가져오기 및 사용
연결 풀은 데이터베이스에 연결하기 위해 애플리케이션에서 사용할 수 있는 물리적 데이터베이스 연결을 나타내는 데이터베이스 연결 객체의 캐시입니다. 런타임 시 애플리케이션은 풀에서 연결을 요청합니다. 풀에 요청을 충족할 수 있는 연결이 포함되어 있으면 연결을 애플리케이션에 반환합니다. 연결을 찾을 수 없으면 새 연결이 생성되어 애플리케이션에 반환됩니다. 애플리케이션은 연결을 사용하여 데이터베이스에서 일부 작업을 수행한 다음 객체를 풀로 다시 반환합니다. 그러면 연결을 다음 연결 요청에 사용할 수 있습니다.
연결 풀은 연결 객체의 재사용을 촉진하고 연결 객체가 생성되는 횟수를 줄입니다. 연결 풀은 연결 객체 생성에 시간과 리소스 모두 비용이 많이 들기 때문에 데이터베이스 집약적인 애플리케이션의 성능을 크게 향상시킵니다.
이제 이러한 DataSource 및 ConnectionPoolDataSource 객체가 배포되었으므로 프로그래머는 DataSource 객체를 사용하여 풀링된 연결을 얻을 수 있습니다. 풀링된 연결을 얻는 코드는 다음 두 줄에 표시된 것처럼 풀링되지 않은 연결을 얻는 코드와 같습니다.
ctx = new InitialContext();
ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB");
변수 ds는 데이터베이스 COFFEEBREAK에 대한 풀링된 연결을 생성하는 DataSource 객체를 나타냅니다. ds 변수에서 getConnection 메서드를 호출하면 ds 변수가 나타내는 DataSource 객체가 풀링된 연결을 생성하도록 구성되었으므로 자동으로 풀링된 연결이 생성됩니다.
연결 풀링은 일반적으로 프로그래머에게 투명합니다. 풀링된 연결을 사용할 때 수행해야 하는 작업은 두 가지뿐입니다.
- DriverManager 클래스 대신 DataSource 객체를 사용하여 연결을 얻습니다. 다음 코드 줄에서 ds는 풀링된 연결을 생성하도록 구현 및 배포된 DataSource 객체이고 username과 password는 데이터베이스에 액세스할 수 있는 사용자의 자격 증명을 나타내는 변수입니다.
Connection con = ds.getConnection(username, password);
- finally 문을 사용하여 풀링된 연결을 닫습니다. 다음 finally 블록은 풀링된 연결이 사용된 코드에 적용되는 try/catch 블록 뒤에 나타납니다.
try {
Connection con = ds.getConnection(username, password);
// ... 풀링된 연결 con을 사용하는 코드
} catch (Exception ex {
// ... 예외를 처리하는 코드
} finally {
if (con != null) con.close();
}
그렇지 않으면 풀링된 연결을 사용하는 애플리케이션은 일반 연결을 사용하는 애플리케이션과 동일합니다. 연결 풀링이 수행될 때 애플리케이션 프로그래머가 알 수 있는 유일한 다른 사항은 성능이 향상된다는 것입니다.
다음 샘플 코드는 데이터베이스 COFFEEBREAK에 대한 연결을 생성하는 DataSource 객체를 가져오고 이를 사용하여 COFFEES 테이블의 가격을 업데이트합니다.
import java.sql.*;
import javax.sql.*;
import javax.ejb.*;
import javax.naming.*;
public class ConnectionPoolingBean implements SessionBean {
// ...
public void ejbCreate() throws CreateException {
ctx = new InitialContext();
ds = (DataSource)ctx.lookup("jdbc/fastCoffeeDB");
}
public void updatePrice(float price, String cofName,
String username, String password)
throws SQLException{
Connection con;
PreparedStatement pstmt;
try {
con = ds.getConnection(username, password);
con.setAutoCommit(false);
pstmt = con.prepareStatement("UPDATE COFFEES " +
"SET PRICE = ? " +
"WHERE COF_NAME = ?");
pstmt.setFloat(1, price);
pstmt.setString(2, cofName);
pstmt.executeUpdate();
con.commit();
pstmt.close();
} finally {
if (con != null) con.close();
}
}
private DataSource ds = null;
private Context ctx = null;
}
이 코드 샘플의 연결은 다음이 참이므로 연결 풀링에 참여합니다.
- ConnectionPoolDataSource를 구현하는 클래스의 인스턴스가 배포되었습니다.
- DataSource를 구현하는 클래스의 인스턴스가 배포되었으며 dataSourceName 속성에 설정된 값은 이전에 배포된 ConnectionPoolDataSource 객체에 바인딩된 논리적 이름입니다.
이 코드가 이전에 본 코드와 매우 유사하지만 다음과 같은 점에서 다르다는 점에 유의하십시오.
- java.sql 외에도 javax.sql, javax.ejb 및 javax.naming 패키지를 가져옵니다.
- DataSource 및 ConnectionPoolDataSource 인터페이스는 javax.sql 패키지에 있고 JNDI 생성자 InitialContext 및 메서드 Context.lookup은 javax.naming 패키지의 일부입니다. 이 특정 예제 코드는 javax.ejb 패키지의 API를 사용하는 EJB 구성 요소 형식입니다. 이 예제의 목적은 풀링된 연결을 풀링되지 않은 연결과 동일한 방식으로 사용한다는 것을 보여주는 것이므로 EJB API를 이해하는 것에 대해 걱정할 필요가 없습니다.
- DriverManager 기능 대신 DataSource 객체를 사용하여 연결을 가져옵니다.
- finally 블록을 사용하여 연결이 닫히도록 합니다.
풀링된 연결을 가져오고 사용하는 것은 일반 연결을 가져오고 사용하는 것과 유사합니다. 시스템 관리자 역할을 하는 사람이 ConnectionPoolDataSource 객체와 DataSource 객체를 올바르게 배포한 경우 애플리케이션은 해당 DataSource 객체를 사용하여 풀링된 연결을 가져옵니다. 그러나 애플리케이션은 finally 블록을 사용하여 풀링된 연결을 닫아야 합니다. 단순화를 위해 앞의 예에서는 finally 블록을 사용했지만 catch 블록은 사용하지 않았습니다. try 블록의 메서드에서 예외가 발생하면 기본적으로 예외가 발생하고 finally 절이 어떤 경우에도 실행됩니다.
분산 트랜잭션 배포
DataSource 객체를 배포하여 분산 트랜잭션에 사용할 수 있는 연결을 얻을 수 있습니다. 연결 풀링과 마찬가지로 두 개의 다른 클래스 인스턴스를 배포해야 합니다. XADataSource 객체와 함께 작동하도록 구현된 DataSource 객체입니다.
커피 브레이크 기업가가 구입한 EJB 서버에 com.applogic.TransactionalDS DataSource 클래스가 포함되어 있고 com.dbaccess.XATransactionalDS와 같은 XADataSource 클래스와 함께 작동한다고 가정합니다. 모든 XADataSource 클래스와 함께 작동한다는 사실은 EJB 서버를 JDBC 드라이버에서 이식 가능하게 만듭니다. DataSource 및 XADataSource 객체가 배포되면 생성된 연결은 분산 트랜잭션에 참여할 수 있습니다. 이 경우 com.applogic.TransactionalDS 클래스는 생성된 연결도 풀링된 연결이 되도록 구현됩니다. 이는 EJB 서버 구현의 일부로 제공되는 DataSource 클래스의 경우 일반적으로 그렇습니다.
XADataSource 객체를 먼저 배포해야 합니다. 다음 코드는 com.dbaccess.XATransactionalDS의 인스턴스를 생성하고 해당 속성을 설정합니다.
com.dbaccess.XATransactionalDS xads = new com.dbaccess.XATransactionalDS();
xads.setServerName("creamer");
xads.setDatabaseName("COFFEEBREAK");
xads.setPortNumber(9040);
xads.setDescription("Distributed transactions for COFFEEBREAK DBMS");
다음 코드는 com.dbaccess.XATransactionalDS 객체 xads를 JNDI 명명 서비스에 등록합니다. xads와 연결된 논리적 이름에 jdbc 아래에 하위 컨텍스트 xa가 추가됩니다. Oracle은 com.dbaccess.XATransactionalDS 클래스의 모든 인스턴스의 논리적 이름이 항상 jdbc/xa로 시작할 것을 권장합니다.
Context ctx = new InitialContext();
ctx.bind("jdbc/xa/distCoffeeDB", xads);
다음으로 xads 및 기타 XADataSource 객체와 상호 작용하도록 구현된 DataSource 객체가 배포됩니다. DataSource 클래스 com.applogic.TransactionalDS는 모든 JDBC 드라이버 공급업체의 XADataSource 클래스와 함께 작동할 수 있습니다. DataSource 객체를 배포하려면 com.applogic.TransactionalDS 클래스의 인스턴스를 생성하고 해당 속성을 설정해야 합니다. dataSourceName 속성은 com.dbaccess.XATransactionalDS와 연결된 논리적 이름인 jdbc/xa/distCoffeeDB로 설정됩니다. 이는 DataSource 클래스에 대한 분산 트랜잭션 기능을 구현하는 XADataSource 클래스입니다. 다음 코드는 DataSource 클래스의 인스턴스를 배포합니다.
com.applogic.TransactionalDS ds = new com.applogic.TransactionalDS();
ds.setDescription("Produces distributed transaction " +
"connections to COFFEEBREAK");
ds.setDataSourceName("jdbc/xa/distCoffeeDB");
Context ctx = new InitialContext();
ctx.bind("jdbc/distCoffeeDB", ds);
이제 com.applogic.TransactionalDS 및 com.dbaccess.XATransactionalDS 클래스의 인스턴스가 배포되었으므로 애플리케이션은 TransactionalDS 클래스의 인스턴스에서 getConnection 메서드를 호출하여 분산 트랜잭션에 사용할 수 있는 COFFEEBREAK 데이터베이스에 대한 연결을 얻을 수 있습니다.
분산 트랜잭션에 연결 사용
분산 트랜잭션에 사용할 수 있는 연결을 얻으려면 분산 트랜잭션 배포 섹션에 표시된 것처럼 올바르게 구현되고 배포된 DataSource 객체를 사용해야 합니다. 이러한 DataSource 객체를 사용하여 getConnection 메서드를 호출합니다. 연결이 설정된 후에는 다른 연결을 사용하는 것과 동일하게 사용합니다. jdbc/distCoffeesDB가 JNDI 명명 서비스의 XADataSource 객체와 연결되었으므로 다음 코드는 분산 트랜잭션에 사용할 수 있는 Connection 객체를 생성합니다.
Context ctx = new InitialContext();
DataSource ds = (DataSource)ctx.lookup("jdbc/distCoffeesDB");
Connection con = ds.getConnection();
이 연결이 분산 트랜잭션의 일부인 동안 사용하는 방법에 대한 몇 가지 사소하지만 중요한 제한 사항이 있습니다. 트랜잭션 관리자는 분산 트랜잭션이 시작되는 시점과 커밋 또는 롤백되는 시점을 제어하므로 애플리케이션 코드는 Connection.commit 또는 Connection.rollback 메서드를 호출해서는 안 됩니다. 애플리케이션은 자동 커밋 모드를 활성화하는 Connection.setAutoCommit(true)도 호출해서는 안 됩니다. 그러면 트랜잭션 경계에 대한 트랜잭션 관리자의 제어를 방해하기 때문입니다. 이는 분산 트랜잭션 범위에서 생성된 새 연결이 기본적으로 자동 커밋 모드를 비활성화하는 이유를 설명합니다. 이러한 제한 사항은 연결이 분산 트랜잭션에 참여하는 경우에만 적용됩니다. 연결이 분산 트랜잭션의 일부가 아닌 동안에는 제한 사항이 없습니다.
다음 예에서는 커피 주문이 배송되어 서로 다른 DBMS 서버에 있는 두 테이블에 대한 업데이트를 트리거한다고 가정합니다. 첫 번째 테이블은 새 INVENTORY 테이블이고 두 번째 테이블은 COFFEES 테이블입니다. 이러한 테이블이 서로 다른 DBMS 서버에 있으므로 두 테이블을 모두 포함하는 트랜잭션은 분산 트랜잭션이 됩니다. 연결을 가져오고 COFFEES 테이블을 업데이트하고 연결을 닫는 다음 예제의 코드는 분산 트랜잭션의 두 번째 부분입니다.
코드는 분산 트랜잭션의 범위가 중간 계층 서버의 기본 시스템 인프라에 의해 제어되므로 업데이트를 명시적으로 커밋하거나 롤백하지 않습니다. 또한 분산 트랜잭션에 사용되는 연결이 풀링된 연결이라고 가정하면 애플리케이션은 finally 블록을 사용하여 연결을 닫습니다. 이렇게 하면 예외가 발생하더라도 유효한 연결이 닫히도록 보장하여 연결이 재활용될 연결 풀로 반환되도록 보장합니다.
다음 코드 샘플은 클라이언트 컴퓨터에서 호출할 수 있는 메서드를 구현하는 클래스인 엔터프라이즈 Bean을 보여줍니다. 이 예제의 목적은 분산 트랜잭션에 대한 애플리케이션 코드가 Connection 메서드 commit, rollback 또는 setAutoCommit(true)를 호출하지 않는다는 점을 제외하고 다른 코드와 다르지 않다는 것을 보여주는 것입니다. 따라서 사용되는 EJB API를 이해하는 것에 대해 걱정할 필요가 없습니다.
import java.sql.*;
import javax.sql.*;
import javax.ejb.*;
import javax.naming.*;
public class DistributedTransactionBean implements SessionBean {
// ...
public void ejbCreate() throws CreateException {
ctx = new InitialContext();
ds = (DataSource)ctx.lookup("jdbc/distCoffeesDB");
}
public void updateTotal(int incr, String cofName, String username,
String password)
throws SQLException {
Connection con;
PreparedStatement pstmt;
try {
con = ds.getConnection(username, password);
pstmt = con.prepareStatement("UPDATE COFFEES " +
"SET TOTAL = TOTAL + ? " +
"WHERE COF_NAME = ?");
pstmt.setInt(1, incr);
pstmt.setString(2, cofName);
pstmt.executeUpdate();
stmt.close();
} finally {
if (con != null) con.close();
}
}
private DataSource ds = null;
private Context ctx = null;
}
출처 : https://docs.oracle.com/javase/tutorial/jdbc/basics/sqldatasources.html
Connecting with DataSource Objects (The Java™ Tutorials > JDBC Database Access > JDBC Basics)
The Java Tutorials have been written for JDK 8. Examples and practices described in this page don't take advantage of improvements introduced in later releases and might use technology no longer available. See Dev.java for updated tutorials taking advantag
docs.oracle.com