데이터 액세스에 연관된 예외

EJB(Enterprise JavaBeans) 2.x 스펙의 모든 엔터프라이즈 Bean CMP(Container-Managed Persistence)는 조작 실패 시에 표준 EJB 예외를 수신합니다. JDBC(Java™ Database Connectivity) 애플리케이션은 임의의 JDBC 조작이 실패할 때 표준 SQL 예외를 수신합니다. 제품은 현재 보류된 연결이 더 이상 유효하지 않음을 표시하기 위해 해당 관계형 자원 어댑터(RRA)에 대한 특수한 예외를 제공합니다.

참고: userDefinedErrorMap 사용자 정의 특성은 DataStoreHelper.setUserDefinedMap 메소드를 시작하여 오류 맵의 기존 항목을 오버레이합니다. 사용자 정의 특성을 사용하여 오류 맵의 항목을 추가, 변경 또는 제거할 수 있습니다.
  • 항목은 ;(세미콜론)으로 구분합니다.
  • 각 항목은 키와 값으로 구성되며 키는 오류 코드(숫자 값) 또는 인용 부호 안에 표기되는 텍스트인 SQLState입니다.
  • 키와 값은 =(등호 기호)로 구분됩니다.
예를 들어, SQLState S1000 맵핑을 제거하고 오류 코드 1062의 맵핑을 중복 키에 추가하며 SQLState 08004의 맵핑을 무효 연결에 추가하려면 userDefinedErrorMap에 다음 값을 지정할 수 있습니다.
"S1000"=;1062=com.ibm.websphere.ce.cm.DuplicateKeyException;"08004"=
com.ibm.websphere.ce.cm.StaleConnectionException
userDefinedErrorMap은 데이터 소스를 선택하고 사용자 정의 특성을 구성하여 관리 콘솔에서 찾을 수 있습니다.

무효 연결

제품은 관계형 데이터베이스에 액세스하기 위해 연결 풀링을 사용하는 java.sql.SQLException 클래스의 특수한 서브클래스를 제공합니다. 이 com.ibm.websphere.ce.cm.StaleConnectionException 서브클래스는 WebSphere® 4.0 데이터 소스 및 관계형 자원 어댑터를 사용하는 가장 최신 버전의 데이터 소스 모두에 존재합니다. 이 클래스는 현재 보류 중인 연결이 더 이상 유효하지 않음을 표시하기 위해 사용됩니다.

이 상황은 다음을 포함하여 많은 이유로 발생 가능합니다.
  • 애플리케이션은 연결을 시도하고 데이터베이스가 시작되지 않아서 실패합니다.
  • 데이터베이스 장애로 인해 연결이 더 이상 사용 불가능합니다. 애플리케이션이 이전에 확보한 연결을 사용하려고 할 때 연결이 더 이상 유효하지 않습니다. 이 경우 애플리케이션이 현재 사용 중인 모든 연결은 연결 사용 시도 시에 이 오류를 수신할 수 있습니다.
  • 연결은 고아가 되고(애플리케이션이 사용되지 않은 제한시간 초과 설정 값의 최대 두 배로 이를 사용하지 않아서) 애플리케이션은 고아가 된 연결 사용을 시도합니다. 이런 경우는 버전 4.0 데이터 소스에만 적용됩니다.
  • 애플리케이션은 무효 연결에서 확보한 명령문과 같은 JDBC 자원 사용을 시도합니다.
  • 연결은 버전 4.0의 데이터 소스 자동 연결 정리로 닫히며 더 이상 사용할 수 없습니다. 자동 연결 정리는 연결 관리가 작동하는 표준 모드입니다. 이 모드는 트랜잭션 종료 시에 트랜잭션 관리자가 해당 트랜잭션에 사용된 모든 연결을 닫습니다. 이를 통해 트랜잭션 관리자는 연결이 오랜 시간 동안 보류되지 않도록 하고 풀은 최대 연결 수에 너무 빨리 도달하지 않도록 할 수 있습니다.

    그렇지만 트랜잭션 관리자가 연결을 닫고 트랜잭션이 종료된 후 사용 가능한 풀로 연결을 리턴할 때 부정적인 결과가 발생합니다. 애플리케이션은 한 트랜잭션에서 연결을 확보할 수 없고 다른 트랜잭션에서 이를 사용하려고 시도합니다. 애플리케이션이 이를 시도하면 연결이 이미 닫혔기 때문에 결국 StaleConnectionException인 ObjectClosedException이 발생합니다.

다음 구성이나 설정을 사용하여 StaleConnectionExceptions 발생을 방지할 수 있습니다.
  • 최소 연결 풀 크기를 0으로 설정하여 애플리케이션 서버가 장시간 비활성화된 경우 연결 풀이 빈 상태로 유지됩니다. 그러면 데이터베이스 측 활동 유지보수로 인해 연결이 무효화되는 것을 방지할 수 있습니다.
  • 연결 풀 사용하지 않은 제한시간을 방화벽 제한시간에 대해 구성된 값보다 작은 값으로 설정하십시오. 그러면 연결이 사용하지 않은 제한시간까지는 무효 연결이 되지 않고 연결은 재사용 가능하도록 사용 가능 풀에 남게됩니다.
  • 연결 풀 Reap 시간을 사용하지 않은 제한시간보다 작은 값으로 설정하십시오. 값이 작아지면 풀이 스레드 검사를 더 자주 유지보수하고 사용하지 않음 타이머도 더 정확해 집니다. 그렇지만 빈번한 풀 유지보수 스레드 실행은 성능 저하를 초래합니다.

고아 연결 또는 자동 연결 정리로 사용 불가능해진 연결 사용을 시도하면 무효 연결 예외가 애플리케이션이 이미 연결 풀로 리턴된 연결 사용을 시도했음을 표시합니다. 이는 연결에 대한 실제 문제는 아닙니다. 그렇지만 다른 경우의 무효 연결 예외는 데이터베이스에 대한 연결이 잘못되었거나 무효화되었음을 표시합니다. 연결이 무효화되면 이를 복구할 수 없으며 이를 풀로 리턴하기보다는 연결을 완전히 닫아야 합니다.

무효 연결 발견

데이터베이스 연결이 무효화되며 해당 연결의 조작은 JDBC 드라이버에서 SQL 예외를 초래합니다. SQL 예외는 다소 일반적인 예외이기 때문에 예외의 의미 판별에 사용할 수 있는 상태 및 오류 코드 값을 포함합니다. 그렇지만 이 상태와 오류 코드 의미는 데이터베이스 벤더에 따라 다릅니다. 연결 풀 실행 시간은 지원되는 각 데이터베이스 벤더에 대해 무효 연결 예외를 표시하는 SQL 상태 및 오류 코드 맵핑을 유지보수합니다. 연결 풀 실행 시간이 SQL 예외를 발견하면 이 SQL 예외가 사용 중인 데이터베이스 서버의 무효 연결 예외로 고려되는지를 확인하기 위해 검사합니다.

무효 연결에서 복구
애플리케이션은 데이터 소스에 구성된 오류 발견 모델 유형에 따라 무효 연결 예외를 발견할 수 있습니다.
  • 오류 발견 모델이 예외 맵핑에 대해 구성된 경우 애플리케이션 서버는 JDBC 드라이버가 StaleConnectionException으로 감지한 예외를 대체합니다. 이 경우 애플리케이션은 무효 연결 예외에 대해 트랩할 수 있습니다.
  • 오류 발견 모델이 예외 검사로 구성된 경우 애플리케이션 서버는 연결 풀을 관리하기 위해 오류 맵을 여전히 참조하지만 예외를 대체하지는 않습니다. 이 경우 애플리케이션은 무효 연결 예외를 트랩하면 안됩니다.

오류 발견 모델 차이로 인해 애플리케이션 서버는 두 경우에서 무효 연결 식별에 사용할 수 있는 API를 제공합니다. API는 com.ibm.websphere.rsadapter.WSCallHelper.getDataStoreHelper(datasource).isConnectionError(sqlexception)입니다.

애플리케이션은 무효 연결 예외를 명시적으로 식별할 필요가 없습니다. 애플리케이션은 이미 java.sql.SQLException을 발견해야 하고 무효 연결 예외 또는 JDBC 드라이버가 감지하는 예외는 항상 java.sql.SQLException에서 데이터를 상속합니다. SQLException을 발생시키도록 선언된 모든 메소드에서 초래될 수 있는 무효 연결 예외는 일반 catch-block에서 자동으로 예외 처리됩니다. 그렇지만 명시적으로 무효 연결 예외 식별은 애플리케이션이 잘못된 연결에서 복구할 수 있도록 해줍니다. 애플리케이션 코드가 무효 연결 예외를 식별하면 명시적인 복구 단계를 수행해야 하며 여기에는 새 트랜잭션 및 새 연결에서 조작 재시도 등이 포함됩니다.

예: 데이터 액세스 예외 처리 - 무효 연결

이 코드 샘플은 다른 트랜잭션 시나리오에서 다른 유형의 데이터 액세스 클라이언트에 대한 무효 연결 예외를 프로그램화하여 처리하는 방법에 대해 설명합니다.

데이터베이스 조작 중에 무효 연결 예외를 애플리케이션이 수신하면 현재 보류 중인 연결이 더 이상 유효하지 않음을 표시합니다. 모든 데이터베이스 조작에서 무효 연결에 대한 예외를 가져올 수 있지만 연결이 처음 검색된 후에 무효 연결 예외가 발생하는 것이 가장 보편적입니다. 연결이 이미 풀되어 있기 때문에 데이터베이스 장애는 데이터베이스와의 첫 번째 통신 시도인 조작이 풀에서 해당 검색 바로 뒤에 올 때까지는 발견되지 않습니다. 연결이 오래된 것으로 표시되는 장애가 발생하는 경우에만 해당합니다. 데이터베이스에 액세스하는 각 메소드가 풀에서 새 연결을 가져오는 경우에는 무효 연결 예외가 덜 자주 발생합니다.

많은 무효 연결 예외는 데이터베이스 서버의 네트워크에 대한 간헐적 문제로 발생합니다. 새 연결을 가져오고 조작을 재시도하면 예외가 발생하지 않고 완료될 수 있습니다. 데이터베이스 서버의 복구 시간을 늘리기 위해 재시도 횟수 사이의 대기 시간을 적게 추가하면 유리한 경우도 있습니다. 그렇지만 애플리케이션은 데이터베이스가 확장 시간 중에 중단된 경우 조작을 무한정 재시도하면 안됩니다.
문제점 방지 문제점 방지: Eclipse와 같은 IDE(Integrated Development Environment)로 WebSphere Application Server에 대한 애플리케이션을 개발 중인 경우 app_server_root/plugins/com.ibm.ws.runtime.jar 파일을 개발 환경으로 가져와서 제공된 코드를 사용해야 할 수도 있습니다. gotcha

애플리케이션이 조작 재시도를 위해 새 연결을 가져오기 전에 원래 연결이 연관된 트랜잭션을 롤백하고 새 트랜잭션을 시작하십시오. 다음과 같은 두 개의 카테고리로 조치 세부사항을 나눌 수 있습니다.

Bean 관리 글로벌 트랜잭션 컨텍스트에서 실행 중인 오브젝트는 데이터베이스 액세스와 동일한 메소드로 시작됩니다.
Bean 관리 트랜잭션(BMT)이 사용되는 서블릿이나 세션 Bean은 네이밍 또는 Bean EJBContext 오브젝트에서 검색 가능한 javax.transaction.UserTransaction 오브젝트에서 begin()을 호출하여 명시적으로 글로벌 트랜잭션을 시작할 수 있습니다. Bean 관리 트랜잭션을 커미트하기 위해 애플리케이션은 commit()UserTransaction 오브젝트에서 호출합니다. 트랜잭션을 롤백하기 위해 애플리케이션은 rollback()을 호출합니다. 엔티티 Bean 및 BMT가 아닌 세션 Bean은 명시적으로 글로벌 트랜잭션을 시작할 수 없습니다.

Bean 관리 트랜잭션을 명시적으로 시작한 오브젝트가 데이터베이스 조작 중에 무효 연결 예외를 수신하는 경우 연결을 닫고 트랜잭션을 롤백하십시오. 이 시점에서 애플리케이션 개발자는 새 트랜잭션을 시작하고 새 연결을 가져오며 조작을 재시도하도록 결정할 수 있습니다.

다음 코드 단편은 이 시나리오에서 무효 연결 예외를 처리하는 예를 보여줍니다.
//get a userTransaction
javax.transaction.UserTransaction tran = getSessionContext().getUserTransaction();
//retry indicates whether to retry or not
//numOfRetries states how many retries have
// been attempted
boolean retry = false;
int numOfRetries = 0;
java.sql.Connection conn = null;
java.sql.Statement stmt = null;
do {
  try {
    //begin a transaction
    tran.begin();
    //Assumes that a datasource has already been obtained
    //from JNDI
    conn = ds.getConnection();
    conn.setAutoCommit(false);
    stmt = conn.createStatement();
    stmt.execute("INSERT INTO EMPLOYEES VALUES
              (0101, 'Bill', 'R', 'Smith')");
    tran.commit();
    retry = false;
  } catch(java.sql.SQLException sqlX)
  {
    // If the error indicates the connection is stale, then
    // rollback and retry the action
    if (com.ibm.websphere.rsadapter.WSCallHelper
        .getDataStoreHelper(ds)
        .isConnectionError(sqlX))
    {
      try {
        tran.rollback();
      } catch (java.lang.Exception e) {
        //deal with exception
        //in most cases, this can be ignored
      }
      if (numOfRetries < 2) {
        retry = true;
        numOfRetries++;
              } else {
        retry = false;
      }
    }
    else
    {
      //deal with other database exception
      retry = false
    }
    } finally {
    //always cleanup JDBC resources
    try {
      if(stmt != null) stmt.close();
    } catch (java.sql.SQLException sqle) {
      //usually can ignore
    }
    try {
      if(conn != null) conn.close();
    } catch (java.sql.SQLException sqle) {
      //usually can ignore
    }
  }
} while (retry) ;
글로벌 트랜잭션 컨텍스트에서 실행 중인 오브젝트 및 데이터베이스 액세스와 동일한 메소드로 시작되지 않은 트랜잭션.
무효 연결 예외를 수신하는 오브젝트가 트랜잭션에 대해 직접 제어가 없는 경우(예를 들어, 컨테이너 관리 트랜잭션의 경우), 이 오브젝트는 트랜잭션을 롤백으로 표시하고 해당 호출자에게 트랜잭션을 재시도하도록 표시해야 합니다. 대부분의 경우 이는 해당 조작 재시도를 표시하는 애플리케이션 예외를 작성하여 수행합니다. 그렇지만 이 조치가 항상 허용되는 것은 아니며 메소드가 특정 예외만을 작성하도록 정의되기도 합니다. 이는 엔터프라이즈 Bean의 ejbLoad() 및 ejbStore() 메소드에 연관됩니다. 다음 두 예는 이 시나리오 각각에 대해 설명합니다.
예 1: 데이터베이스 액세스 메소드가 애플리케이션 예외를 작성
데이터베이스에 액세스하는 메소드가 필요한 예외에 상관없이 자유롭게 작성할 수 있는 경우 우수 사례는 무효 연결 예외를 발견하고 메소드 재시도를 해석할 수 있는 몇 개의 애플리케이션 예외를 작성하는 것입니다. 다음 예는 트랜잭션 구분 TX_REQUIRED로 엔티티 Bean에서 메소드를 호출하는 EJB 클라이언트를 보여주며 이는 컨테이너가 insertValue() 호출 시 글로벌 트랜잭션을 시작하는 것을 의미합니다.
public class MyEJBClient
{
  //... other methods here ...

  public void myEJBClientMethod()
  {
    MyEJB myEJB = myEJBHome.findByPrimaryKey("myEJB");
    boolean retry = false;
    do
    {
      try 
      {
        retry = false;
        myEJB.insertValue();
      }
      catch(RetryableConnectionException retryable)
      {
        retry = true;
      }
      catch(Exception e) { /* handle some other problem */ }
    }
    while (retry);
  }  
}  //end MyEJBClient

public class MyEJB implements javax.ejb.EntityBean
{
  //... other methods here ...
  public void insertValue() throws RetryableConnectionException,
         java.rmi.EJBException
  {
    try 
    {
      conn = ds.getConnection();
      stmt = conn.createStatement();
      stmt.execute("INSERT INTO my_table VALUES (1)");
    }
    catch(java.sql.SQLException sqlX)
    {
      // Find out if the error indicates the connection is stale
      if (com.ibm.websphere.rsadapter.WSCallHelper
          .getDataStoreHelper(ds)
          .isConnectionError(sqlX))
      {
        getSessionContext().setRollbackOnly();
        throw new RetryableConnectionException();
      }
      else
      {
        //handle other database problem
      }
    }
    finally
    {
      //always cleanup JDBC resources
      try 
      {
        if(stmt != null) stmt.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //usually can ignore
      }
      try 
      {
        if(conn != null) conn.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //usually can ignore
      }
    }
  }
}  //end MyEJB

MyEJBClient는 JNDI(Java Naming and Directory Interface)에서 이미 검색되었다는 가정 하에 우선 홈 인터페이스에서 MyEJB Bean을 가져옵니다. 그런 다음 Bean에서 insertValue()를 호출합니다. Bean의 메소드는 연결을 가져오고 값을 테이블에 삽입하려고 시도합니다. 메소드 중 하나가 무효 연결 예외로 인해 실패하는 경우, rollbackOnly(호출자가 이 트랜잭션을 강제로 롤백하도록 하는)에 대한 트랜잭션을 표시하고 예외 처리되기 전에 자원을 정리하여 새 retryable connection 예외를 작성합니다. 재시도 가능 연결 예외는 단순히 호출자가 메소드를 재시도하도록 지시하는 애플리케이션 정의 예외입니다. 호출자는 재시도 가능 연결 예외를 모니터하며 감지되는 경우 메소드를 재시도합니다. 이 예에서는, 컨테이너가 트랜잭션을 시작하고 종료하므로 클라이언트 또는 서버에서 트랜잭션 관리가 필요하지 않습니다. 물론, 클라이언트가 트랜잭션을 커미트하거나 롤백한다면 클라이언트는 Bean 관리 트랜잭션을 시작할 수 있고 동작은 여전히 동일합니다.

예 2: 데이터베이스 액세스 메소드가 onlyRemote 예외 또는 EJB 예외 작성
모든 메소드가 애플리케이션에서 정의된 예외를 처리할 수 있는 것은 아닙니다. BMP(Bean-Managed Persistence)를 사용하는 경우 ejbLoad()ejbStore() 메소드를 사용하여 Bean 상태를 저장하십시오. 이 메소드에서 발행되는 유일한 예외는 java.rmi.Remote 예외 또는 javax.ejb.EJB 예외이기 때문에 이전 예와 유사한 것은 사용할 수 없습니다.
CMP(Container-Managed Persistence)를 사용하는 경우 컨테이너는 Bean의 지속성을 관리하고 이 컨테이너는 무효 연결 예외를 확인하는 컨테이너입니다. 무효 연결이 발견되면 예외가 클라이언트에 리턴될 때 이는 단순한 원격 예외로 단순 catch-block은 충분하지 않습니다. 원격 예외의 근본 원인이 무효 연결 예외인지를 판별하는 방법이 있습니다. 원격 예외가 다른 예외를 랩핑하기 위해 작성되는 경우, 원래 예외는 일반적으로 유지됩니다. 모든 원격 예외 인스턴스는 유형 java.lang.Throwable의 세부사항 특성을 포함합니다. 이 세부사항을 사용하여 원래 예외를 다시 추적하고 무효 연결 예외인 경우 트랜잭션을 재시도하십시오. 실제로 이 원격 예외 중 하나가 임의의 JVM(Java Virtual Machine) API에서 다음으로 플로우되는 경우, 세부사항은 유실되기 때문에 데이터베이스 액세스가 발생한 동일한 서버에서 트랜잭션을 시작하는 것이 좋습니다. 이런 이유로 다음 예는 Bean 관리 트랜잭션 구분을 사용하는 세션 Bean에서 액세스하는 엔티티 Bean을 표시합니다.
public class MySessionBean extends javax.ejb.SessionBean
{
  ... other methods here ...
  public void mySessionBMTMethod() throws
    java.rmi.EJBException
  {
    javax.transaction.UserTransaction tran =
    getSessionContext().getUserTransaction();
    boolean retry = false;
    do
    {
      try 
      {
        retry = false;
        tran.begin();
        // causes ejbLoad() to be invoked
        myBMPBean.myMethod();
        // causes ejbStore() to be invoked
        tran.commit();
      }
      catch(java.rmi.EJBException re)
      {
        try 
        {
          tran.rollback();
        }
        catch (Exception e)
        {
          //can ignore
        }
        if (causedByStaleConnection(re))
          retry = true;
        else
          throw re;
      }
      catch (Exception e)
      {
        // handle some other problem
      }
      finally
      {
        //always cleanup JDBC resources
        try 
        {
          if(stmt != null) stmt.close();
        }
        catch (java.sql.SQLException sqle)
        {
          //usually can ignore
        }
        try 
        {
          if(conn != null) conn.close();
        }
        catch (java.sql.SQLException sqle)
        {
          //usually can ignore
        }
      }
    }
    while (retry);
  }

  public boolean causedByStaleConnection(java.rmi.EJBException re)
  {
    // Search the exception chain for errors
    // indicating a stale connection
    for (Throwable t = re; t != null; t = t.getCause())
      if (t instanceof RetryableConnectionException)
        return true;

    // Not found to be stale
    return false;
  }
}

public class MyEntityBean extends javax.ejb.EntityBean
{
  ... other methods here ...
  public void ejbStore() throws java.rmi.EJBException
  {
    try 
    {
      conn = ds.getConnection();
      stmt = conn.createStatement();
      stmt.execute("UPDATE my_table SET value=1 WHERE
      primaryKey=" + myPrimaryKey);
    }
    catch(java.sql.SQLException sqlX)
    {
      // Find out if the error indicates the connection is stale
      if (com.ibm.websphere.rsadapter.WSCallHelper
          .getDataStoreHelper(ds)
          .isConnectionError(sqlX))
      {
        // rollback the tran when method returns
        getEntityContext().setRollbackOnly();
        throw new java.rmi.EJBException(
          "Exception occurred in ejbStore",
          new RetryableConnectionException(sqlX));
      }
      else
      {
        // handle some other problem
      }
    }
    finally
    {
      //always cleanup JDBC resources
      try 
      {
        if(stmt != null) stmt.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //usually can ignore
      }
      try 
      {
        if(conn != null) conn.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //usually can ignore
      }
    }
  }
}
이전 예에서 mySessionBMTMethod():
  • 우선 세션 Bean은 세션 컨텍스트에서 UserTransaction 오브젝트를 검색하고 글로벌 트랜잭션을 시작합니다.
  • 그리고 엔티티 Bean에서 메소드를 호출하며 이는 ejbLoad() 메소드를 호출합니다. ejbLoad()가 제대로 실행되면 클라이언트가 트랜잭션을 호출하고 이로 인해 ejbStore() 메소드가 호출됩니다.
  • ejbStore()에서 엔티티 Bean은 연결을 가져오고 해당 상태를 데이터베이스에 기록합니다. 검색된 연결이 무효화된 경우 트랜잭션은 rollbackOnly로 표시되고 RetryableConnectionException을 랩핑하는 새 EJBException이 처리됩니다. 그러면 해당 예외는 클라이언트에서 발견되어 JDBC 자원을 정리하고 트랜잭션을 롤백하며 무효 연결 예외가 예외 중에 묻히는지 판별하는 causedByStaleConnection()을 호출합니다.
  • 메소드가 true를 리턴하면 재시도 플래그가 설정되고 트랜잭션이 재시도됩니다. 그렇지 않으면 예외가 호출자에게 다시 발행됩니다.
  • causedByStaleConnection() 메소드는 원래 예외를 찾기 위해 세부사항 속성 체인을 통해 검색합니다. 예외에 대한 다중 랩핑은 예외가 마침내 클라이언트로 돌아올 때 발생 가능하기 때문에 메소드는 무효 연결 예외를 찾고 true가 리턴될 때까지 계속 검색해야 합니다. 그렇지 않으면 목록에는 무효 연결 예외가 없고 false가 리턴됩니다.
  • BMP Bean이 아니라 CMP Bean에 전달하는 경우 세션 Bean은 동일합니다. CMP Bean ejbStore() 메소드는 거의 비어 있으며 호출 후의 컨테이너는 생성된 코드를 사용하여 Bean을 지속시킵니다.
  • 지속성이 유지되는 동안 무효 연결 예외가 발생하면 원격 예외로 랩핑되어 호출자에게 리턴됩니다. causedByStaleConnection() 메소드는 예외 체인을 통해 검색하고 무효 연결 예외인 루트 예외를 찾습니다.
로컬 트랜잭션 컨텍스트에서 운영되는 오브젝트
데이터베이스 조작이 글로벌 트랜잭션 컨텍스트 밖에서 발생하면 로컬 트랜잭션은 내재적으로 컨테이너로 인해 시작됩니다. 여기에는 UserTransaction 인터페이스로 트랜잭션을 시작하지 않는 서블릿 또는 JSP와 지정되지 않은 트랜잭션 컨텍스트에서 실행 중인 엔터프라이즈 Bean이 포함됩니다. 글로벌 트랜잭션을 사용하여 조작이 재시도되기 전에 로컬 트랜잭션을 롤백해야 합니다. 이 경우, 로컬 트랜잭션 포함은 일반적으로 비즈니스 메소드가 종료될 때 종료됩니다. 이는 활동 세션을 사용하는 경우만 예외적입니다. 이 경우, 활동 세션은 새 연결을 가져오기 전에 종료되어야 합니다.

로컬 트랜잭션이 지정되지 않은 트랜잭션 컨텍스트에서 실행 중인 엔터프라이즈 Bean에서 발생하면 로컬 트랜잭션 포함 밖의 엔터프라이즈 Bean 클라이언트 오브젝트는 이전 글머리표에서 설명한 메소드를 사용하여 트랜잭션을 재시도할 수 있습니다. 그렇지만 로컬 트랜잭션 포함은 서블릿이나 JSP 파일의 파트로 수행되기 때문에 조작을 재시도할 수 있는 클라이언트 오브젝트가 없습니다. 이런 이유로 서블릿 및 JSP 파일이 사용자 트랜잭션의 파트인 경우를 제외하고는 여기에서 데이터베이스 조작을 피해야 합니다.

Linux 시스템에서의 무효 연결

Linux 플랫폼에서 애플리케이션 서버의 DB2® 데이터베이스에 액세스하려면 루프백을 설정해야 할 수도 있습니다.

Linux 세마포어 문제는 이 구성 중 하나에서 DB2 데이터베이스에 대한 JDBC 액세스를 방해할 수 있습니다.
  • DB2 Universal JDBC 유형 2 드라이버를 사용하여 로컬 DB2 데이터베이스에 연결
  • 애플리케이션 서버와 동일한 머신의 DB2 Connect™ 설치를 통해 DB2 Universal JDBC 유형 2 드라이버를 사용하여 DB2 for z/OS®에 액세스. 문제는 DB2 Connect가 로컬 클라이언트가 에이전트 내에서 실행되는 것을 제한하는 경우에만 발생합니다. (즉, DB2_IN_APP_PROCESS 설정이 기본값이 아니거나 또는 설정이 Yes인 경우입니다. 값을 No로 설정하여 문제를 해결하고 다음 프로시저 수행은 피하십시오.)
문제로 인해 JVM 로그가 트리거되어 DB2 무효 연결 예외 SQL1224가 표시되는 경우가 있습니다. SQL 예외 코드가 다를 수 있기 때문에 무효 연결이 발생하면 여하튼 DB2 추적 로그를 검사하십시오. 다음 오류 데이터가 표시되면 Linux 세마포어 동작이 문제입니다.
'71' -SQLCC_ERR_CONN_CLOSED_BY_PARTNER and SQLCODE -XXXX
문제를 임시로 해결하려면 데이터베이스에 대해 루프백을 설정하십시오. 예를 들어, 데이터베이스 이름이 WAS, 호스트 이름이 LHOST, 데이터베이스 서비스 포트 번호가 50000인 경우 DB2 명령행 창에서 다음 명령을 실행하십시오.
db2 catalog TCPIP node RHOST remote LHOST server 50000
db2 uncatalog db WAS
db2 catalog db WAS as WASAlias at node loop authentication server
//If you connect to WASAlias, it is connect through loopback;
//If you connect to WAS, it is "normal" connect. 
db2 catalog db WASAlias as WAS at node RHOST

예: 서블릿 JDBC 연결 예외 처리

다음 코드 샘플은 트랜잭션 관리와 연결 관리 특성(예: 조작 재시도)을 설정하여 서블릿 JDBC 트랜잭션 내에서 무효 연결 예외를 처리하는 방법을 설명합니다.

이 예 코드는 다음 조치를 수행합니다.
  • 서블릿 초기화
  • 데이터 소스 검색
  • 오류 메시지, 연결 재시도, 트랜잭션 롤백 요구사항 지정
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
import java.util.*;
// Import JDBC packages and naming service packages.
import java.sql.*;
import javax.sql.*;
import javax.naming.*;
import javax.transaction.*;
import com.ibm.websphere.ce.cm.ConnectionWaitTimeoutException;
import com.ibm.websphere.rsadapter.WSCallHelper;

public class EmployeeListTran extends HttpServlet {
    private static DataSource ds   = null;   
    private UserTransaction ut = null;
    private static String title    = "Employee List";    

// ****************************************************************
// * Initialize servlet when it is first loaded.                  *
// * Get information from the properties file, and look up the    *
// * DataSource object from JNDI to improve performance of the    *
// * the servlet's service methods.                               *
// ****************************************************************
    public void init(ServletConfig config)
    throws ServletException
    {
        super.init(config);
        getDS();
    }

// ****************************************************************
// * Perform the JNDI lookup for the DataSource and               *
// * User Transaction objects.                                    *
// * This method is invoked from init(), and from the service     *
// * method of the DataSource is null                             *
// ****************************************************************
    private void getDS() {
        try {
            Hashtable parms = new Hashtable();
            parms.put(Context.INITIAL_CONTEXT_FACTORY, 
 com.ibm.websphere.naming.WsnInitialContextFactory);
            InitialContext ctx = new InitialContext(parms);
            // Perform a naming service lookup to get the DataSource object.
            ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
            ut = (UserTransaction) ctx.lookup("java:comp/UserTransaction");
        } catch (Exception e) {
            System.out.println("Naming service exception:" + e.getMessage());
            e.printStackTrace();
        }
    }

// ****************************************************************
// * Respond to user GET request                                  *
// ****************************************************************
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
    {
        Connection conn  = null;
        Statement stmt = null;
        ResultSet rs = null;
        Vector employeeList = new Vector();
        // Set retryCount to the number of times you would like to retry after a
        // stale connection exception
        int retryCount = 5;      
        // If the Database code processes successfully, we will set error = false
        boolean error = true;
        do
        {
            try 
            {          
                //Start a new Transaction
                ut.begin();
                // Get a Connection object conn using the DataSource factory.
                conn = ds.getConnection();
                // Run DB query using standard JDBC coding.
                stmt = conn.createStatement();
                String query   = "Select FirstNme, MidInit, LastName" + 
                                     "from Employee ORDER BY LastName";
                rs   = stmt.executeQuery(query);
                while (rs.next())
                {
                    employeeList.addElement(rs.getString(3) + ", "+ rs.getString(1)" +     " + rs.getString(2));
                }                           
                //Set error to false to indicate successful completion of the database work
                error=false;                    
            }
            catch (SQLException sqlX)
            {
              // Determine if the connection request timed out.
              // This code works regardless of which error detection
              // model is used. If exception mapping is enabled, then
              // we need to look for ConnectionWaitTimeoutException.
              // If exception checking is enabled, then look for
              // SQLTransientConnectionException with a chained
              // ConnectionWaitTimeoutException.

              if ( sqlX instanceof ConnectionWaitTimeoutException
                || sqlX instanceof SQLTransientConnectionException
                   && sqlX.getCause() instanceof ConnectionWaitTimeoutException)
              {
                // This exception is thrown if a connection can not be obtained from the
                // pool within a configurable amount of time.  Frequent occurrences of
                // this exception indicate an incorrectly tuned connection pool

                System.out.println("Connection Wait Timeout Exception during get connection or 
process SQL:" + c.getMessage());  
     
                //In general, we do not want to retry after this exception, so set retry count to 0
                //and roll back the transaction
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se)
                {
                    //Thrown to indicate that the thread is not allowed to roll back the transaction.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise)
                {
                    //Thrown if the current thread is not associated with a transaction.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye)
                {
                    //Thrown if the transaction manager encounters an unexpected error condition
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                retryCount=0;   
              }
              else if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(sqlX))
              {
                // This exception indicates that the connection to the database is no longer valid.
                //Roll back the transaction, then retry several times to attempt to obtain a valid  
                //connection, display an error message if the connection still can not be obtained.

                System.out.println("Connection is stale:" + sc.getMessage());
                
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se)
                {
                    //Thrown to indicate that the thread is not allowed to roll back the transaction.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise)
                {
                    //Thrown if the current thread is not associated with a transaction.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye)
                {
                    //Thrown if the transaction manager encounters an unexpected error condition
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                if (--retryCount == 0)
                {
                    System.out.println("Five stale connection exceptions, displaying error page.");
                }
              } 
              else
              {
                System.out.println("SQL Exception during get connection or process SQL: " + sq.getMessage());

                //In general, we do not want to retry after this exception, so set retry count to 0
                //and rollback the transaction
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se)
                {
                    //Thrown to indicate that the thread is not allowed to roll back the transaction.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise)
                {
                    //Thrown if the current thread is not associated with a transaction.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye)
                {
                    //Thrown if the transaction manager encounters an unexpected error condition
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                retryCount=0;
              } 
            }
            catch (NotSupportedException nse)
            {
                //Thrown by UserTransaction begin method if the thread is already associated with a
                //transaction and the Transaction Manager implementation does not support nested  
                //transactions.
                System.out.println("NotSupportedException on User Transaction begin:" + nse.getMessage());
            } 
            catch (SystemException se)
            {
                //Thrown if the transaction manager encounters an unexpected error condition
                System.out.println("SystemException in User Transaction:" +se.getMessage());
            } 
            catch (Exception e)
            {
                System.out.println("Exception in get connection or process SQL:" + e.getMessage());
                //In general, we do not want to retry after this exception, so set retry count to 5
                //and roll back the transaction
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se)
                {
                    //Thrown to indicate that the thread is not allowed to roll back the transaction.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise)
                {
                    //Thrown if the current thread is not associated with a transaction.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye)
                {
                    //Thrown if the transaction manager encounters an unexpected error condition
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                retryCount=0;
            } 
            finally
            {
                // Always close the connection in a finally statement to ensure proper
                // closure in all cases. Closing the connection does not close and 
                // actual connection, but releases it back to the pool for reuse.

                if (rs != null)
                {
                   try 
                   {
                      rs.close();
                   } 
                   catch (Exception e)
                   {
                      System.out.println("Close Resultset Exception:" + e.getMessage());
                   }
                }
                if (stmt != null)
                {
                   try 
                   {
                      stmt.close();
                   } 
                   catch (Exception e)
                   {
                      System.out.println("Close Statement Exception:" + e.getMessage());
                   }
                }
                if (conn != null)
                {
                   try 
                   {
                      conn.close();
                   } 
                   catch (Exception e)
                   {
                      System.out.println("Close connection exception:" + e.getMessage());
                   }
                }
                try 
                {
                    ut.commit();
                } 
                catch (RollbackException re)
                {
                    //Thrown to indicate that the transaction has been rolled back rather than committed.
                    System.out.println("User Transaction Rolled back!" + re.getMessage());
                } 
                catch (SecurityException se)
                {
                    //Thrown to indicate that the thread is not allowed to commit the transaction.
                    System.out.println("Security Exception thrown on transaction commit:" + se.getMessage());
                } 
                catch (IllegalStateException ise)
                {
                    //Thrown if the current thread is not associated with a transaction.
                    System.out.println("Illegal State Exception thrown on transaction commit:" + ise.getMessage());
                } 
                catch (SystemException sye)
                {
                    //Thrown if the transaction manager encounters an unexpected error condition
                    System.out.println("System Exception thrown on transaction commit:" + sye.getMessage());
                } 
                catch (Exception e)
                {
                    System.out.println("Exception thrown on transaction commit:" + e.getMessage());
                }
            }
        }
        while ( error==true && retryCount > 0 );

        // Prepare and return HTML response, prevent dynamic content from being cached
        // on browsers.
        res.setContentType("text/html");
        res.setHeader("Pragma", "no-cache");
        res.setHeader("Cache-Control", "no-cache");
        res.setDateHeader("Expires", 0);
        try 
        {
            ServletOutputStream out = res.getOutputStream();
            out.println("<HTML>");
            out.println("<HEAD><TITLE>" + title + "</TITLE></HEAD>");
            out.println("<BODY>");                  
            if (error==true)
            {
                out.println("<H1>There was an error processing this request.</H1>" +
                  "Please try the request again, or contact" +
                   "the <a href='mailto:sysadmin@my.com'>System Administrator</a>");
            } 
            else if (employeeList.isEmpty())
            {
               out.println("<H1>Employee List is Empty</H1>");
            } 
            else
            {
               out.println("<H1>Employee List </H1>");
               for (int i = 0; i < employeeList.size(); i++)
               {
                  out.println(employeeList.elementAt(i) + "<BR>"); 
               }
            }
            out.println("</BODY></HTML>");
            out.close();
        } 
        catch (IOException e)
        {
           System.out.println("HTML response exception:" + e.getMessage());
        }
    }
}

예: 컨테이너 관리 데이터베이스 트랜잭션에서 세션 Bean을 위한 연결 예외 처리

다음 코드 샘플은 무효 연결 예외가 발생하는 경우에 트랜잭션을 롤백하고 Bean 클라이언트에 예외를 발행하는 방법에 대해 설명합니다.

//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

import java.util.*;
import java.sql.*;
import javax.sql.*;
import javax.ejb.*;
import javax.naming.*;
import com.ibm.websphere.ce.cm.ConnectionWaitTimeoutException;
import com.ibm.websphere.rsadapter.WSCallHelper;

/*************************************************************************************
* This bean is designed to demonstrate Database Connections in a                      
* Container Managed Transaction Session Bean.  Its transaction attribute               *
* should be set to TX_REQUIRED or TX_REQUIRES_NEW.                                     *
**************************************************************************************
*/
public class ShowEmployeesCMTBean implements SessionBean {
		 private javax.ejb.SessionContext mySessionCtx = null;
		 final static long serialVersionUID = 3206093459760846163L;
		 
		 private javax.sql.DataSource ds;

//************************************************************************************
//* ejbActivate calls the getDS method, which does the JNDI lookup for the DataSource.
//* Because the DataSource lookup is in a separate method, we can also invoke it from 
//* the getEmployees method in the case where the DataSource field is null.		 		 
//************************************************************************************
public void ejbActivate() throws java.rmi.EJBException {
		 getDS();
}
/**
 * ejbCreate method
 * @exception javax.ejb.CreateException
 * @exception java.rmi.EJBException
 */
public void ejbCreate() throws javax.ejb.CreateException, java.rmi.EJBException {}
/**
 * ejbPassivate method 
 * @exception java.rmi.EJBException
 */
public void ejbPassivate() throws java.rmi.EJBException {}
/**
 * ejbRemove method 
 * @exception java.rmi.EJBException 
 */
public void ejbRemove() throws java.rmi.EJBException {}

//************************************************************************************
//* The getEmployees method runs the database query to retrieve the employees.
//* The getDS method is only called if the DataSource variable is null.	
//* Because this session bean uses Container Managed Transactions, it cannot retry the
//* transaction on a StaleConnectionException.  However, it can throw an exception to
//* its client indicating that the operation is retriable.
//************************************************************************************

public Vector getEmployees() throws ConnectionWaitTimeoutException, SQLException,
       RetryableConnectionException
{
   Connection conn  = null;
   Statement stmt = null;
   ResultSet rs = null;
   Vector employeeList = new Vector();

   if (ds == null) getDS();
   		 
   try 
   {
      // Get a Connection object conn using the DataSource factory.
      conn = ds.getConnection();
      // Run DB query using standard JDBC coding.
      stmt = conn.createStatement();
      String query   = "Select FirstNme, MidInit, LastName" + 
                       "from Employee ORDER BY LastName;"
      rs   = stmt.executeQuery(query);
      while (rs.next())
      {
         employeeList.addElement(rs.getString(3) + ", "+ rs.getString(1)" + " + rs.getString(2));
      }                           
   } 
   catch (SQLException sqlX)
   {
     // Determine if the connection is stale
     if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(sqlX))
     {
       // This exception indicates that the connection to the database is no longer valid.
       // Roll back the transaction, and throw an exception to the client indicating they
       // can retry the transaction if desired.

       System.out.println("Connection is stale:" + sqlX.getMessage());
       System.out.println("Rolling back transaction and throwing  RetryableConnectionException");

       mySessionCtx.setRollbackOnly();
       throw new RetryableConnectionException(sqlX.toString());
     }
     // Determine if the connection request timed out.
     else if ( sqlX instanceof ConnectionWaitTimeoutException
            || sqlX instanceof SQLTransientConnectionException
               && sqlX.getCause() instanceof ConnectionWaitTimeoutException)
     {
       // This exception is thrown if a connection can not be obtained from the
       // pool within a configurable amount of time.  Frequent occurrences of
       // this exception indicate an incorrectly tuned connection pool

       System.out.println("Connection Wait Timeout Exception during get connection or process SQL:" +
       sqlX.getMessage());
       throw sqlX instanceof ConnectionWaitTimeoutException ?
             sqlX :
             (ConnectionWaitTimeoutException) sqlX.getCause();
     } 
     else
     {
       //Throwing a remote exception will automatically roll back the container managed 
       //transaction

       System.out.println("SQL Exception during get connection or process SQL:" +
		 		 		 		 sqlX.getMessage());
       throw sqlX;
     } 
   }
   finally
   {
     // Always close the connection in a finally statement to ensure proper 
     // closure in all cases. Closing the connection does not close and 
     // actual connection, but releases it back to the pool for reuse.

     if (rs != null)
     {
       try 
       {
         rs.close();
       } 
       catch (Exception e)
       {
         System.out.println("Close Resultset Exception:" + 
                       e.getMessage());
       }
     }
     if (stmt != null)
     {
       try 
       {
         stmt.close();
       } 
       catch (Exception e)
       {
         System.out.println("Close Statement Exception:" + 
                       e.getMessage());
       }
     }
     if (conn != null)
     {
       try 
       {
         conn.close();
       } 
       catch (Exception e)
       {
         System.out.println("Close connection exception:" + e.getMessage());
       }
     }
   }
   return employeeList;
}

/**
 * getSessionContext method
 * @return javax.ejb.SessionContext
 */
public javax.ejb.SessionContext getSessionContext() {
		 return mySessionCtx;
}
//************************************************************************************
//* The getDS method performs the JNDI lookup for the data source.	
//* This method is called from ejbActivate, and from getEmployees if the data source	  
//* object is null.	
//************************************************************************************

private void getDS() {
		 try {
		 		 Hashtable parms = new Hashtable();
		 		 parms.put(Context.INITIAL_CONTEXT_FACTORY, 
		 		 		 		 com.ibm.websphere.naming.WsnInitialContextFactory);
		 		 InitialContext ctx = new InitialContext(parms);
		 		 // Perform a naming service lookup to get the DataSource object.
		 		 ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
		 } 
             catch(Exception e){
		 		 System.out.println("Naming service exception:" + e.getMessage());
		 		 e.printStackTrace();
		 }
}
/**
 * setSessionContext method 
 * @param ctx javax.ejb.SessionContext
 * @exception java.rmi.EJBException
 */
public void setSessionContext(javax.ejb.SessionContext ctx) throws java.rmi.EJBException {
		 mySessionCtx = ctx;
}
}

//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * This is a Home interface for the Session Bean
 */
public interface ShowEmployeesCMTHome extends javax.ejb.EJBHome {

/**
 * create method for a session bean
* @return WebSphereSamples.ConnPool.ShowEmployeesCMT
 * @exception javax.ejb.CreateException
 * @exception java.rmi.RemoteException
 */
WebSphereSamples.ConnPool.ShowEmployeesCMT create() throws javax.ejb.CreateException,
   java.rmi.RemoteException;
}

//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * This is an Enterprise Java Bean Remote Interface
 */
public interface ShowEmployeesCMT extends javax.ejb.EJBObject {

/**
 * 
 * @return java.util.Vector
 */
java.util.Vector getEmployees() throws java.sql.SQLException, java.rmi.RemoteException,
 ConnectionWaitTimeoutException, WebSphereSamples.ConnPool.RetryableConnectionException;
}
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * Exception indicating that the operation can be retried
 * Creation date: (4/2/2001 10:48:08 AM)
 * @author: Administrator
 */
public class RetryableConnectionException extends Exception {
/**
 * RetryableConnectionException constructor.
 */
public RetryableConnectionException() {
		 super();
}
/**
 * RetryableConnectionException constructor.
 * @param s java.lang.String
 */
public RetryableConnectionException(String s) {
		 super(s);
}
}

예: Bean 관리 데이터베이스 트랜잭션에서 세션 Bean에 대한 연결 예외 처리

다음 코드 샘플은 무효 연결 예외 처리를 위한 옵션을 설명합니다. 다른 트랜잭션 관리 및 연결 관리 매개변수(예: 조작 재시도 횟수, 연결 제한시간 간격)를 설정할 수도 있습니다.

//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

import java.util.*;
import java.sql.*;
import javax.sql.*;
import javax.ejb.*;
import javax.naming.*;
import javax.transaction.*;
import com.ibm.websphere.ce.cm.ConnectionWaitTimeoutException;
import com.ibm.websphere.rsadapter.WSCallHelper;

/**********************************************************************************
* This bean is designed to demonstrate Database Connections in a                  *
* Bean-Managed Transaction Session Bean.  Its transaction attribute               *
* should be set to TX_BEANMANAGED.                                                 
**********************************************************************************/
public class ShowEmployeesBMTBean implements SessionBean {
		 private javax.ejb.SessionContext mySessionCtx = null;
		 final static long serialVersionUID = 3206093459760846163L;

		 private javax.sql.DataSource ds;

		 private javax.transaction.UserTransaction userTran;

//************************************************************************************
//* ejbActivate calls the getDS method, which makes the JNDI lookup for the DataSource
//* Because the DataSource lookup is in a separate method, we can also invoke it from  
//* the getEmployees method in the case where the DataSource field is null.		 		 
//************************************************************************************
public void ejbActivate() throws java.rmi.EJBException {
		 getDS();
}
/**
 * ejbCreate method 
 * @exception javax.ejb.CreateException
 * @exception java.rmi.EJBException
 */
public void ejbCreate() throws javax.ejb.CreateException, java.rmi.EJBException {}
/**
 * ejbPassivate method 
 * @exception java.rmi.EJBException
 */
public void ejbPassivate() throws java.rmi.EJBException {}
/**
 * ejbRemove method 
 * @exception java.rmi.EJBException
 */
public void ejbRemove() throws java.rmi.EJBException {}

//************************************************************************************
//* The getEmployees method runs the database query to retrieve the employees.	    
//* The getDS method is only called if the DataSource or userTran variables are null.
//* If a stale connection occurs, the bean retries the transaction 5 times,		 
//* then throws an EJBException.
//************************************************************************************

public Vector getEmployees() throws EJBException {
   Connection conn  = null;
   Statement stmt = null;
   ResultSet rs = null;
   Vector employeeList = new Vector();

   // Set retryCount to the number of times you would like to retry after a
   // stale connection
   int retryCount = 5;  
    
   // If the Database code processes successfully, we will set error = false
   boolean error = true;
   
   if (ds == null || userTran == null) getDS();
   do
   {		 		 
         try 
         { 
            //try/catch block for UserTransaction work
            //Begin the transaction
            userTran.begin();
            try 
            { 
               //try/catch block for database work
               //Get a Connection object conn using the DataSource factory.
               conn = ds.getConnection();
               // Run DB query using standard JDBC coding.
               stmt = conn.createStatement();
               String query   = "Select FirstNme, MidInit, LastName" + 
		 		 		     "from Employee ORDER BY LastName";
               rs   = stmt.executeQuery(query);
               while (rs.next())
               {
                  employeeList.addElement(rs.getString(3) + ", "+ rs.getString(1) +" " + rs.getString(2));
               }
               //Set error to false, as all database operations are successfully completed
               error = false;
            } 
            catch (SQLException sqlX)
            {
              if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(sqlX))
              {
                // This exception indicates that the connection to the database is no longer valid.
                // Rollback the transaction, and throw an exception to the client indicating they
                // can retry the transaction if desired.

                System.out.println("Stale connection:" +
                se.getMessage());
                userTran.rollback();
                if (--retryCount == 0)
                {
                  //If we have already retried the requested number of times, throw an EJBException.
                  throw new EJBException("Transaction Failure:" + sqlX.toString());
                } 
                else
                {
                  System.out.println("Retrying transaction, retryCount =" +          
                         retryCount);
                }
              } 
              else if (sqlX instanceof ConnectionWaitTimeoutException
                    || sqlX instanceof SQLTransientConnectionException
                       && sqlX.getCause() instanceof ConnectionWaitTimeoutException)
              {
                // This exception is thrown if a connection can not be obtained from the
                // pool within a configurable amount of time.  Frequent occurrences of
                // this exception indicate an incorrectly tuned connection pool

                System.out.println("Connection request timed out:" + 
                sqlX.getMessage());
                userTran.rollback();
                throw new EJBException("Transaction failure:" + sqlX.getMessage());
              } 
              else
              {                   
		  	  // This catch handles all other SQL Exceptions
                System.out.println("SQL Exception during get connection or process SQL:" +
		 		 		 		 sqlX.getMessage());
                userTran.rollback();
                throw new EJBException("Transaction failure:" + sqlX.getMessage());
              } 
            finally
            {
              // Always close the connection in a finally statement to ensure proper 
              // closure in all cases. Closing the connection does not close and 
              // actual connection, but releases it back to the pool for reuse.

              if (rs != null) {
               try {
                  rs.close();
               } 
                     catch(Exception e){
                  System.out.println("Close Resultset Exception:" + e.getMessage());
               }
            }
            if (stmt != null) {
               try {
                  stmt.close();
 } 
                  catch(Exception e){
               System.out.println("Close Statement Exception:" + e.getMessage());
            }
         }         
         if (conn != null) {
            try {
               conn.close();
            } 
                  catch(Exception e){
               System.out.println("Close connection exception:" + e.getMessage());
            }
         }
      }		   		 
      if (!error) {
         //Database work completed successfully, commit the transaction
         userTran.commit();
      }
      //Catch UserTransaction exceptions
      } 
      catch (NotSupportedException nse) {

//Thrown by UserTransaction begin method if the thread is already associated with a 
//transaction and the Transaction Manager implementation does not support nested transactions.
 System.out.println("NotSupportedException on User Transaction begin:" +
                                 nse.getMessage());
         throw new EJBException("Transaction failure:" + nse.getMessage());
      } 
      catch (RollbackException re) {
//Thrown to indicate that the transaction has been rolled back rather than committed.
         System.out.println("User Transaction Rolled back!" + re.getMessage());
         throw new EJBException("Transaction failure:" + re.getMessage());
      } 
      catch (SystemException se) {
		   //Thrown if the transaction manager encounters an unexpected error condition
         System.out.println("SystemException in User Transaction:" + se.getMessage());
         throw new EJBException("Transaction failure:" + se.getMessage());
      } 
            catch(Exception e){
         //Handle any generic or unexpected Exceptions
         System.out.println("Exception in User Transaction:" + e.getMessage());
         throw new EJBException("Transaction failure:" + e.getMessage());		 		 
      }
   } 
   while (error);
   return employeeList;
}
/**
 * getSessionContext method comment
 * @return javax.ejb.SessionContext
 */
public javax.ejb.SessionContext getSessionContext() {
		 return mySessionCtx;
}

//************************************************************************************
//* The getDS method performs the JNDI lookup for the DataSource.		 		 		 
//* This method is called from ejbActivate, and from getEmployees if the DataSource		 
//* object is null.		 		 		 		 		 		 		 		 		 
//************************************************************************************
private void getDS() {
   try {
      Hashtable parms = new Hashtable();
parms.put(Context.INITIAL_CONTEXT_FACTORY, 
         com.ibm.websphere.naming.WsnInitialContextFactory);
      InitialContext ctx = new InitialContext(parms);

      // Perform a naming service lookup to get the DataSource object.
      ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
      //Create the UserTransaction object
      userTran = mySessionCtx.getUserTransaction();
   } 
         catch(Exception e){
      System.out.println("Naming service exception:" + e.getMessage());
      e.printStackTrace();
}
}
/**
 * setSessionContext method
 * @param ctx javax.ejb.SessionContext
 * @exception java.rmi.EJBException
 */
public void setSessionContext(javax.ejb.SessionContext ctx) throws java.rmi.EJBException {
		 mySessionCtx = ctx;
}
}
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * This is a Home interface for the Session Bean
 */
public interface ShowEmployeesBMTHome extends javax.ejb.EJBHome {

/**
 * create method for a session bean
 * @return WebSphereSamples.ConnPool.ShowEmployeesBMT
 * @exception javax.ejb.CreateException
 * @exception java.rmi.RemoteException
 */
WebSphereSamples.ConnPool.ShowEmployeesBMT create() throws javax.ejb.CreateException,
    java.rmi.RemoteException;
}
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * This is an Enterprise Java Bean Remote Interface
 */
public interface ShowEmployeesBMT extends javax.ejb.EJBObject {

/**
 * 
 * @return java.util.Vector
 */
java.util.Vector getEmployees() throws java.rmi.RemoteException, javax.ejb.EJBException;
}

예: 컨테이너 관리 데이터베이스 트랜잭션에서 BMP Bean을 위한 연결 예외 처리

다음 코드 샘플은 무효 연결 예외가 발생하는 경우에 트랜잭션을 롤백하고 Bean 클라이언트에 예외를 발행하는 방법에 대해 설명합니다.

//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2005,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

import java.util.*;
import javax.ejb.*;
import java.sql.*;
import javax.sql.*;
import javax.ejb.*;
import javax.naming.*;
import com.ibm.websphere.rsadapter.WSCallHelper;

/**
 * This is an Entity Bean class with five BMP fields
 * String firstName, String lastName, String middleInit
 * String empNo, int edLevel
 */
public class EmployeeBMPBean implements EntityBean {
       private javax.ejb.EntityContext entityContext = null;
       final static long serialVersionUID = 3206093459760846163L;

       private java.lang.String firstName;
       private java.lang.String lastName;
       private String middleInit;
       private javax.sql.DataSource ds;
       private java.lang.String empNo;
       private int edLevel;
/**
 * ejbActivate method 
 * ejbActivate calls getDS(), which performs the 
 * JNDI lookup for the datasource.
 */
public void ejbActivate() {
       getDS();
}
/**
 * ejbCreate method for a BMP entity bean
 * @return WebSphereSamples.ConnPool.EmployeeBMPKey
 * @param key WebSphereSamples.ConnPool.EmployeeBMPKey
 * @exception javax.ejb.CreateException 
 */
public WebSphereSamples.ConnPool.EmployeeBMPKey ejbCreate(String empNo, 
String firstName, String lastName, String middleInit, int edLevel) throws 
javax.ejb.CreateException {

   Connection conn = null;
   PreparedStatement ps = null;
       
   if (ds == null) getDS();
              
   this.empNo = empNo;
   this.firstName = firstName;
   this.lastName = lastName;
   this.middleInit = middleInit;
   this.edLevel = edLevel;

   String sql = "insert into Employee (empNo, firstnme, midinit, lastname,
        edlevel) values (?,?,?,?,?)";
              
   try {
      conn = ds.getConnection();
      ps = conn.prepareStatement(sql);                     
      ps.setString(1, empNo);
      ps.setString(2, firstName);
      ps.setString(3, middleInit);
      ps.setString(4, lastName);
      ps.setInt(5, edLevel);
              
 if (ps.executeUpdate() != 1){
         System.out.println("ejbCreate Failed to add user.");
         throw new CreateException("Failed to add user.");
      }
   } 
   catch (SQLException se)
   {
      if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(se))
      {
         // This exception indicates that the connection to the database is no longer valid.
         // Rollback the transaction, and throw an exception to the client indicating they
         // can retry the transaction if desired.

         System.out.println("Connection is stale:" +  se.getMessage());
         throw new CreateException(se.getMessage());
      } 
      else
      {
         System.out.println("SQL Exception during get connection or process SQL:" +
                          se.getMessage());
         throw new CreateException(se.getMessage());
      } 
   }
   finally
   {
      // Always close the connection in a finally statement to ensure proper 
      // closure in all cases. Closing the connection does not close an
      // actual connection, but releases it back to the pool for reuse.
      if (ps != null)
      {
         try 
         {
            ps.close();
         } 
         catch (Exception e)
         {
            System.out.println("Close Statement Exception:" + e.getMessage());
         }
      }
      if (conn != null)
      {
         try 
         {
            conn.close();
         } 
         catch (Exception e)
         {
            System.out.println("Close connection exception:" + e.getMessage());
         }
      }
   }
   return new EmployeeBMPKey(this.empNo);
}
/**
 * ejbFindByPrimaryKey method
 * @return WebSphereSamples.ConnPool.EmployeeBMPKey
 * @param primaryKey WebSphereSamples.ConnPool.EmployeeBMPKey
 * @exception javax.ejb.FinderException
 */
public WebSphereSamples.ConnPool.EmployeeBMPKey
     ejbFindByPrimaryKey(WebSphereSamples.ConnPool.EmployeeBMPKey primaryKey)
                 javax.ejb.FinderException {
       loadByEmpNo(primaryKey.empNo);
       return primaryKey;
}
/**
 * ejbLoad method
 */
public void ejbLoad() {
       try {
              EmployeeBMPKey pk = (EmployeeBMPKey) entityContext.getPrimaryKey();
              loadByEmpNo(pk.empNo);
       } catch (FinderException fe) {
              throw new EJBException("Cannot load Employee state from database.");
       }       
}
/**
 * ejbPassivate method
 */
public void ejbPassivate() {}
/**
 * ejbPostCreate method for a BMP entity bean
 * @param key WebSphereSamples.ConnPool.EmployeeBMPKey
 */
public void ejbPostCreate(String empNo, String firstName, String lastName, String middleInit,
    int edLevel) {}
/**
 * ejbRemove method
 * @exception javax.ejb.RemoveException
 */
public void ejbRemove() throws javax.ejb.RemoveException
{
       
   if (ds == null) 
      GetDS();

   String sql = "delete from Employee where empNo=?";
   Connection con = null;
   PreparedStatement ps = null;
   try 
   {                     
      con = ds.getConnection();   
      ps = con.prepareStatement(sql);   
      ps.setString(1, empNo);
      if (ps.executeUpdate() != 1)
      {
         throw new EJBException("Cannot remove employee:" + empNo);
      }
   } 
   catch (SQLException se)
   {
      if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(se))
      {
         // This exception indicates that the connection to the database is no longer valid.
         // Rollback the transaction, and throw an exception to the client indicating they
         // can retry the transaction if desired.

         System.out.println("Connection is stale:" + se.getMessage());
         throw new EJBException(se.getMessage());   
      } 
      else
      {
         System.out.println("SQL Exception during get connection or process SQL:" +
                          se.getMessage());
         throw new EJBException(se.getMessage());   
      } 
   }
   finally
   {
      // Always close the connection in a finally statement to ensure proper 
      // closure in all cases. Closing the connection does not close an
      // actual connection, but releases it back to the pool for reuse.
      if (ps != null)
      {
         try 
         {
            ps.close();
         } 
         catch (Exception e)
         {
            System.out.println("Close Statement Exception:" + e.getMessage());
         }
      }
      if (con != null)
      {
         try 
         {
            con.close();
         } 
         catch (Exception e)
         {
            System.out.println("Close connection exception:" + e.getMessage());
         }
      }
   }
}
/**
 * Get the employee's edLevel
 * Creation date: (4/20/2001 3:46:22 PM)
 * @return int
 */
public int getEdLevel() {
       return edLevel;
}
/**
 * getEntityContext method
 * @return javax.ejb.EntityContext
 */
public javax.ejb.EntityContext getEntityContext() {
       return entityContext;
}
/**
 * Get the employee's first name
 * Creation date: (4/19/2001 1:34:47 PM)
 * @return java.lang.String
 */
public java.lang.String getFirstName() {
               return firstName;
}
/**
 * Get the employee's last name
 * Creation date: (4/19/2001 1:35:41 PM)
 * @return java.lang.String
 */
public java.lang.String getLastName() {
       	return lastName;
}
/**
* get the employee's middle initial
 * Creation date: (4/19/2001 1:36:15 PM)
 * @return char
 */
public String getMiddleInit() {
       return middleInit;
}
/**
 * Lookup the DataSource from JNDI
 * Creation date: (4/19/2001 3:28:15 PM)
 */
private void getDS() {
       try {
              Hashtable parms = new Hashtable();
              parms.put(Context.INITIAL_CONTEXT_FACTORY, 
                            com.ibm.websphere.naming.WsnInitialContextFactory);
              InitialContext ctx = new InitialContext(parms);
              // Perform a naming service lookup to get the DataSource object.
              ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
       } 
             catch(Exception e){
              System.out.println("Naming service exception:" + e.getMessage());
              e.printStackTrace();
       }
}
/**
 * Load the employee from the database
 * Creation date: (4/19/2001 3:44:07 PM)
 * @param empNo java.lang.String
 */
private void loadByEmpNo(String empNoKey) throws javax.ejb.FinderException
{
       String sql = "select empno, firstnme, midinit, lastname, edLevel from employee where empno = ?";
       Connection conn = null;
       PreparedStatement ps = null;
       ResultSet rs = null;

       if (ds == null) getDS();
       
       try 
       {
              // Get a Connection object conn using the DataSource factory.
              conn = ds.getConnection();
              // Run DB query using standard JDBC coding.
              ps = conn.prepareStatement(sql);
              ps.setString(1, empNoKey);
              rs = ps.executeQuery();
              if (rs.next())
              {
                     empNo= rs.getString(1);
                     firstName=rs.getString(2);
                     middleInit=rs.getString(3);
                     lastName=rs.getString(4); 
                     edLevel=rs.getInt(5);
              } 
              else
              {
                throw new ObjectNotFoundException("Cannot find employee number" +
                                                   empNoKey);
              }
       } 
       catch (SQLException se)
       {
         if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(se))
         {
           // This exception indicates that the connection to the database is no longer valid.
           // Roll back the transaction, and throw an exception to the client indicating they
           // can retry the transaction if desired.

           System.out.println("Connection is stale:" + se.getMessage());
           throw new FinderException(se.getMessage());
         } 
         else
         {
           System.out.println("SQL Exception during get connection or process SQL:" +
                               se.getMessage());
           throw new FinderException(se.getMessage());
         } 
       }
       finally
       {
         // Always close the connection in a finally statement to ensure 
         // proper closure in all cases. Closing the connection does not 
         // close an actual connection, but releases it back to the pool 
         // for reuse.
         if (rs != null)
         {
            try 
            {
               rs.close();
            } 
            catch (Exception e)
            {
               System.out.println("Close Resultset Exception:" + e.getMessage());
            }
         }
         if (ps != null)
         {
            try 
            {
               ps.close();
            } 
            catch (Exception e)
            {
               System.out.println("Close Statement Exception:" + e.getMessage());
            }
         }
         if (conn != null)
         {
            try 
            {
               conn.close();
            } 
            catch (Exception e)
            {
               System.out.println("Close connection exception:" + e.getMessage());
            }
         }
       }      
}
/**
 * set the employee's education level
 * Creation date: (4/20/2001 3:46:22 PM)
 * @param newEdLevel int
 */
public void setEdLevel(int newEdLevel) {
       edLevel = newEdLevel;
}
/**
 * setEntityContext method
 * @param ctx javax.ejb.EntityContext
 */
public void setEntityContext(javax.ejb.EntityContext ctx) {
       entityContext = ctx;
}
/**
 * set the employee's first name
 * Creation date: (4/19/2001 1:34:47 PM)
 * @param newFirstName java.lang.String
 */
public void setFirstName(java.lang.String newFirstName) {
       firstName = newFirstName;
}
/**
 * set the employee's last name
 * Creation date: (4/19/2001 1:35:41 PM)
 * @param newLastName java.lang.String
 */
public void setLastName(java.lang.String newLastName) {
       lastName = newLastName;
}
/**
 * set the employee's middle initial
 * Creation date: (4/19/2001 1:36:15 PM)
 * @param newMiddleInit char
 */
public void setMiddleInit(String newMiddleInit) {
       middleInit = newMiddleInit;
}
/**
 * unsetEntityContext method
 */
public void unsetEntityContext() {
       entityContext = null;
}
}

//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * This is an Enterprise Java Bean Remote Interface
 */
public interface EmployeeBMP extends javax.ejb.EJBObject {

/**
 * 
 * @return int
  */
int getEdLevel() throws java.rmi.RemoteException;
/**
 * 
 * @return java.lang.String
 */
java.lang.String getFirstName() throws java.rmi.RemoteException;
/**
 * 
 * @return java.lang.String
 */
java.lang.String getLastName() throws java.rmi.RemoteException;
/**
 * 
 * @return java.lang.String
 */
java.lang.String getMiddleInit() throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newEdLevel int
 */
void setEdLevel(int newEdLevel) throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newFirstName java.lang.String
 */
void setFirstName(java.lang.String newFirstName) throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newLastName java.lang.String
 */
void setLastName(java.lang.String newLastName) throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newMiddleInit java.lang.String
 */
void setMiddleInit(java.lang.String newMiddleInit) throws java.rmi.RemoteException;
}
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
 * This is an Enterprise Java Bean Remote Interface
 */
public interface EmployeeBMP extends javax.ejb.EJBObject {

/**
 * 
 * @return int
  */
int getEdLevel() throws java.rmi.RemoteException;
/**
 * 
 * @return java.lang.String
 */
java.lang.String getFirstName() throws java.rmi.RemoteException;
/**
 * 
 * @return java.lang.String
 */
java.lang.String getLastName() throws java.rmi.RemoteException;
/**
 * 
 * @return java.lang.String
 */
java.lang.String getMiddleInit() throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newEdLevel int
 */
void setEdLevel(int newEdLevel) throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newFirstName java.lang.String
 */
void setFirstName(java.lang.String newFirstName) throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newLastName java.lang.String
 */
void setLastName(java.lang.String newLastName) throws java.rmi.RemoteException;
/**
 * 
 * @return void
 * @param newMiddleInit java.lang.String
 */
void setMiddleInit(java.lang.String newMiddleInit) throws java.rmi.RemoteException;
}
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
/**
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//===================END_PROLOG========================================

package WebSphereSamples.ConnPool;

/**
* This is a Primary Key Class for the Entity Bean
**/
public class EmployeeBMPKey implements java.io.Serializable { 
		 public String empNo;
		 final static long serialVersionUID = 3206093459760846163L;

/**
* EmployeeBMPKey() constructor 
*/
public EmployeeBMPKey()  {
}
/**
* EmployeeBMPKey(String key) constructor 
*/
public EmployeeBMPKey(String key)  {
		 empNo = key;
}
/**
* equals method
* - user must provide a proper implementation for the equal method. The generated 
*   method assumes the key is a String object.
*/
public boolean equals (Object o)  {
		 if (o instanceof EmployeeBMPKey) 
		 		 return empNo.equals(((EmployeeBMPKey)o).empNo);
		 else
		 		 return false;
}
/**
* hashCode method
* - user must provide a proper implementation for the hashCode method. The generated
*    method assumes the key is a String object.
*/
public int hashCode ()  {
		 return empNo.hashCode();

예: 데이터 액세스 예외 - ConnectionWaitTimeoutException(JDBC API용)

이 코드 샘플은 애플리케이션 서버가 JDBC 애플리케이션에 대해 ConnectionWaitTimeoutException을 발생하는 조건을 지정하는 방법에 대해 설명합니다.

ConnectionWaitTimeoutException이 발견되는 모든 상황에서 복구할 수 있는 방법은 거의 없습니다.

public void test1() {
		 		 java.sql.Connection conn = null;
		 		 java.sql.Statement stmt = null;
		 		 java.sql.ResultSet rs = null;

		 		 try {
		 		 		 // Look for datasource
		 		 		 java.util.Properties props = new java.util.Properties();
		 		 		 props.put(
		 		 		 		 javax.naming.Context.INITIAL_CONTEXT_FACTORY,
		 		 		 		 com.ibm.websphere.naming.WsnInitialContextFactory);
		 		 		 ic = new javax.naming.InitialContext(props);
		 		 		 javax.sql.DataSource ds1 = (javax.sql.DataSource) ic.lookup(jndiString);

		 		 		 // Get Connection.
		 		 		 conn = ds1.getConnection();
		 		 		 stmt = conn.createStatement();
		 		 		 rs = stmt.executeQuery("select * from mytable where this = 54");
		 		 }
		 		 catch (java.sql.SQLException sqlX) {
					if (sqlX instanceof com.ibm.websphere.ce.cm.ConnectionWaitTimeoutException
					 || sqlX instanceof java.sql.SQLTransientConnectionException
					    && sqlX.getCause() instanceof com.ibm.websphere.ce.cm.ConnectionWaitTimeoutException)
					{
		 		 		 //notify the user that the system could not provide a 
		 		 		 //connection to the database.  This usually happens when the 
		 		 		 //connection pool is full and there is no connection 
		 		 		 //available for to share.
		 			}
					else
					{
		 		 		 // handle other database problems.
					}
		 		 }
		 		 finally {
		 		 		 if (rs != null)
		 		 		 		 try {
		 		 		 		 		 rs.close();
		 		 		 		 }
		 		 		 		 catch (java.sql.SQLException sqle1) {
		 		 		 		 }
		 		 		 if (stmt != null)
		 		 		 		 try {
		 		 		 		 		 stmt.close();
		 		 		 		 }
		 		 		 		 catch (java.sql.SQLException sqle1) {
		 		 		 		 }
		 		 		 if (conn != null)
		 		 		 		 try {
		 		 		 		 		 conn.close();
		 		 		 		 }
		 		 		 		 catch (java.sql.SQLException sqle1) {
		 		 		 		 }
		 		 }
		 }

예: 데이터 액세스 예외 처리 - Java EE 커넥터 아키텍처용 ConnectionWaitTimeoutException

이 코드 샘플은 WebSphere Application Server가 JCA 애플리케이션에 대한 ConnectionWaitTimeout 예외를 발행하는 조건을 지정하는 방법을 설명합니다.

ConnectionWaitTimeout 예외가 발견되는 모든 상황에서 복구할 수 있는 방법은 거의 없습니다.

다음 코드 단편은 Java Platform, Enterprise Edition(Java EE) Connector Architecture(JCA)에서 이 예외를 사용하는 방법을 보여줍니다.

/**
 * This method does a simple Connection test. 
 */
public void testConnection()
   throws javax.naming.NamingException, javax.resource.ResourceException, 
       com.ibm.websphere.ce.j2c.ConnectionWaitTimeoutException {
   javax.resource.cci.ConnectionFactory factory = null;
   javax.resource.cci.Connection conn = null;
   javax.resource.cci.ConnectionMetaData metaData = null;
   try {
      // lookup the connection factory
      if (verbose) System.out.println("Look up the connection factory...");
try {
factory = 
	 (javax.resource.cci.ConnectionFactory) (new InitialContext()).lookup("java:comp/env/eis/Sample");
  }
   catch (javax.naming.NamingException ne) {
      // Connection factory cannot be looked up.
      throw ne;
   }
    // Get connection
      if (verbose) System.out.println("Get the connection...");
      conn = factory.getConnection();
      // Get ConnectionMetaData
      metaData = conn.getMetaData();
      // Print out the metadata Information.
      System.out.println("EISProductName" is + metaData.getEISProductName());
   }
   catch (com.ibm.websphere.ce.j2c.ConnectionWaitTimeoutException cwtoe) {
      // Connection Wait Timeout
      throw cwtoe;
   }
   catch (javax.resource.ResourceException re) {
      // Something wrong with connections.
      throw re;
   }
   finally {
      if (conn != null) {
         try {
            conn.close();
         }
         catch (javax.resource.ResourceException re) {
         }
      }
   }
}

예: 데이터 액세스 예외 처리 - DataStoreHelper의 오류 맵핑

애플리케이션 서버는 다른 데이터베이스 SQL 오류 코드를 애플리케이션 서버에서 적절한 예외로 맵핑하는 DataStoreHelper 인터페이스를 제공합니다.

오류 맵핑은 다양한 데이터베이스 벤더가 결국은 동일한 문제에 대해 다른 SQL 오류 및 코드를 제공할 수 있기 때문에 필요합니다. 예를 들어, 무효 연결 예외는 다른 데이터베이스에서 다른 코드일 수 있습니다. DB2 SQLCODE 1015, 1034, 1036 등은 연결이 임시 데이터베이스 문제로 인해 더 이상 사용할 수 없음을 나타냅니다. Oracle SQLCODE 28, 3113, 3114 등이 동일한 상황을 표시합니다.

이들 오류 코드를 표준 예외로 맵핑하면 애플리케이션 서버의 다른 설치에서도 애플리케이션이 이식 가능할 수 있도록 일관성이 제공됩니다. 다음 코드 세그먼트는 두 개의 오류 코드를 오류 맵에 추가하는 방법에 대해 설명합니다.
public class NewDSHelper extends GenericDataStoreHelper
{
  public NewDSHelper(java.util.Properties dataStoreHelperProperties)  
  {
    super(dataStoreHelperProperties);
    java.util.Hashtable myErrorMap = null;
    myErrorMap = new java.util.Hashtable();
    myErrorMap.put(new Integer(-803), myDuplicateKeyException.class);
    myErrorMap.put(new Integer(-1015), myStaleConnectionException.class);
    myErrorMap.put("S1000", MyTableNotFoundException.class);
    setUserDefinedMap(myErrorMap);
    ...
  }
}

오류 발견 모델로 표시되는 구성 옵션은 오류 맵 사용 방법을 제어합니다. V6 이하에서 예외 맵핑이 오류 발견 모델에 사용할 수 있는 유일한 옵션이었습니다. V7 이상에서 예외 검사라는 다른 옵션도 사용할 수 있습니다. 예외 맵핑 모델에서 애플리케이션 서버는 오류 맵을 참조하여 오류 맵에 나열된 해당 예외 유형으로 예외를 대체합니다. 예외 검사 모델에서 애플리케이션 서버는 해당 목적에 대해 여전히 오류 맵을 참조하지만 예외를 대체하지는 않습니다. 예외 맵핑을 계속 사용하려면 아무것도 변경할 필요가 없습니다. 예외 맵핑은 기본 오류 발견 모델입니다. 예외 검사 모델을 사용하려면 관련 링크에서 "예외 검사 모델을 사용하도록 오류 발견 모델 변경" 주제를 참조하십시오.

데이터베이스 교착 상태 및 외부 키 충돌

특정 SQL 오류 메시지가 반복되면 데이터베이스 참조 무결성 위반과 같은 문제를 표시할 수 있으며 이는 컨테이너 관리 지속성(CMP) 시퀀스 그룹화 기능을 사용하여 방지할 수 있습니다.

데이터베이스 참조 무결성 위반으로 외부 키 충돌에서 발생하는 예외

데이터베이스 referential integrity(RI) 정책은 관계형 일관성을 유지보수하기 위해 데이터가 데이터베이스 테이블에 쓰기 및 삭제되는 방법에 대한 규칙을 규정합니다. 그렇지만 Bean 지속성 관리를 위한 런타임 요구사항으로 인해 EJB(Enterprise JavaBeans) 애플리케이션이 RI 규칙을 위반하여 데이터베이스 예외를 초래할 수 있습니다.

WebSphere Application Server 추적 또는 로그 파일에서 다음 메시지와 유사한 예외 메시지가 표시되면(DB2를 실행 중인 환경에서 작성) EJB 애플리케이션이 데이터베이스 RI를 위반하는 것입니다.
FOREIGN KEY table1.name_of_foreign_key_constraint의
삽입 또는 업데이트 값이 상위 테이블의 상위 키 값과 동일하지 않습니다. 
or
상위 행은 관계 table1.name_of_foreign_key_constraint가
상위 테이블의 상위 키 값과 동일하지 않아서 삭제할 수 없습니다. 

이런 예외를 방지하려면 Bean에 대한 시퀀스 그룹을 정의하여 엔티티 Bean이 관계형 데이터베이스 테이블을 업데이트하는 순서를 지정해야 합니다.

낙관적 동시 제어 설계로 인한 교착 상태에서 초래되는 예외

또한, 시퀀스 그룹화는 낙관적 동시 제어에 대해 구성된 엔티티 Bean에 대한 트랜잭션 롤백 예외를 최소화할 수 있습니다. 낙관적 동시 제어는 최대 수의 트랜잭션이 데이터에 일관성있게 액세스할 수 있도록 데이터베이스 잠금이 최소한의 시간 동안만 잠금되도록 합니다. 이런 고가용성 데이터베이스에서 동시 트랜잭션은 동일한 테이블 행 잠금을 시도하고 교착 상태를 작성할 수 있습니다. 초래되는 예외는 다음과 유사한 메시지(DB2를 실행하는 환경에서 작성)를 생성할 수 있습니다.

교착 상태 또는 제한시간 초과로 인해 성공하지 못한 예외. 

데이터베이스 교착 상태가 자주 발생하지 않도록 시퀀스 그룹화 기능을 사용하여 Bean 지속성을 요청하십시오.


주제 유형을 표시하는 아이콘 개념 주제



시간소인 아이콘 마지막 업데이트 날짜: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=cdat_daexcp
파일 이름:cdat_daexcp.html