與資料存取相關的異常狀況

當作業失敗時,遵循 Enterprise JavaBeans (EJB) 2.x 規格的所有 Enterprise Bean 儲存器管理持續性 (CMP) Bean 會收到標準 EJB 異常狀況。 如果有任何 JDBC 作業失敗,Java™ 資料庫連線功能 (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 版資料來源自動清理連線功能關閉,已不再堪用。自動清理連線是連線管理的標準運作模式。此模式指出在交易結束時,交易管理程式會關閉該交易中列入的所有連線。 這可讓交易管理程式確保不會保留連線太久,而且儲存區不會過早達到連線數上限。

    然而,如果交易管理程式在交易結束之後關閉連線並將連線歸還到可用儲存區,則會導致不良後果。 應用程式無法在一個交易中取得連線,又試圖在另一個交易中使用此連線。如果應用程式試圖這樣做,因為連線已關閉,將會發生 ObjectClosedException,進而發生 StaleConnectionException。

下列配置或設定有助於避免發生 StaleConnectionException:
  • 只要將連線儲存區大小下限設定為 0,當應用程式伺服器長時間處於非作用中時,連線儲存區會保持淨空。這有助於避免因為資料庫端進行維護活動而導致連線過時。
  • 將連線儲存區「未用逾時值」設定為小於防火牆逾時所配置的值。這可以確保連線在達到「未用逾時值」之前不會過時,而且可讓連線保留在可用儲存區中供重複使用。
  • 將連線儲存區執行間隔時間值設定為小於未用逾時值。該值越小,儲存區維護執行緒檢查就越頻繁,而且未用的計時器就越準確。但是,頻繁執行儲存區維護執行緒可能會降低效能。

如果您試圖使用孤立連線,或經過自動連線清理而無法使用的連線,則過時連線異常狀況會指出應用程式試圖使用的連線,已回到連線儲存區。 它不會指出連線的實際問題。但是,過時連線異常狀況的其他情形則表示資料庫的連線已損壞或過時。一旦連線過時,就無法回復,您必須完全關閉該連線,而不是將它歸還給儲存區。

偵測過時連線

當資料庫的連線過時,該連線上的作業會導致 JDBC 驅動程式傳回 SQL 異常狀況。因為 SQL 異常狀況是很常見的異常狀況,它包含可用來判斷異常狀況意義的狀態和錯誤碼值。 然而,這些狀態和錯誤碼的意義根據資料庫供應商而有所不同。針對每一個支援的資料庫供應商,連線儲存區執行時期會維護一份對映,指出哪些 SQL 狀態和錯誤碼表示過時連線異常狀況。 當連線儲存區執行時期捕捉到 SQL 異常狀況時,它會檢查此 SQL 異常狀況是否可視為使用中資料庫伺服器的過時連線異常狀況。

從過時連線回復
根據資料來源上配置的錯誤偵測模型的類型而定,應用程式可以捕捉過時連線異常狀況:
  • 當錯誤偵測模型配置為異常狀況對映時,應用程式伺服器會以 StaleConnectionException 取代 JDBC 驅動程式引發的異常狀況。 在此情況下,應用程式可能捕捉過時連線異常狀況。
  • 當錯誤偵測模型配置為異常狀況檢查時,應用程式伺服器仍會查閱錯誤對映來管理連線儲存區,但不會取代異常狀況。 在此情況下,應用程式不應捕捉過時連線異常狀況。

由於錯誤偵測模型之間的差異,應用程式伺服器提供一個 API,供應用程式在任一情況下用來識別過時連線。 此 API 是 com.ibm.websphere.rsadapter.WSCallHelper.getDataStoreHelper(datasource).isConnectionError(sqlexception)。

應用程式不需要明確識別過時連線異常狀況。 應用程式已需要捕捉 java.sql.SQLException,而且過時連線異常狀況或由 JDBC 驅動程式引發的異常狀況,一律會從 java.sql.SQLException 繼承資料。 一般 catch 區塊中會自動捕捉過時連線異常狀況(可能由任何已宣告為引發 SQLException 的方法造成)。不過,明確識別過時連線異常狀況,有可能讓應用程式從不正確的連線中回復。 當應用程式碼識別過時連線異常狀況時,應該採取明確步驟來回復,例如在新的交易和新的連線下重試作業。

範例:處理資料存取異常狀況 - 過時連線

這些程式碼範例示範在不同的交易實務範例中,針對不同類型的資料存取用戶端,如何以程式設計方式解決過時連線異常狀況。

當應用程式收到關於資料庫作業的過時連線異常狀況時,就表示目前保留的連線不再有效。雖然在進行任何資料庫作業時都可能收到過時連線異常狀況,但最常是在第一次收到連線之後,才會看到發出過時連線異常狀況。 因為連線是放在儲存區,所以要直到作業緊接於從儲存區擷取之後(也就是第一次試圖與資料庫通訊),才會偵測到資料庫失敗。 只有在偵測到失敗時,連線才會標示為過時。如果每一個存取資料庫的方法都從儲存區取得新的連線,則不會太常發生過時連線異常狀況。

許多過時連線異常狀況都是由資料庫伺服器的網路間歇性問題所引起。取得新連線並重試作業可以成功完成,而不會發生異常狀況。 在某些情況下,最好在重試之間增加些微等待時間,讓資料庫伺服器有更多時間可回復。但是,應用程式不應無限期重試作業,以防資料庫停止運作太久。
避免困難 避免困難: 如果您正在使用 Eclipse 之類的整合開發環境 (IDE) 來開發 WebSphere Application Server 的應用程式,您可能必須將 app_server_root/plugins/com.ibm.ws.runtime.jar 檔匯入到該開發環境中,才能使用所提供的程式碼。gotcha

請先回復原始連線所涉及的交易並起始新的交易,應用程式才能取得新的連線來重試作業。您可以將此動作的詳細資料分成下列兩個種類:

在與資料庫存取相同的方法中起始的 Bean 管理廣域交易環境定義中運作的物件
使用 Bean 管理的交易 (BMT) 的 Servlet 或階段作業 Bean,可以在 javax.transaction.UserTransaction 物件(您可以從 naming 或從 Bean EJBContext 物件中擷取)上呼叫 begin(),以明確啟動廣域交易。 如果要確定 Bean 管理的交易,應用程式可在 UserTransaction 物件上呼叫 commit()。 如果要回復交易,應用程式可呼叫 rollback()。Entity 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) ;
不在與資料庫存取相同的方法中啟動的廣域交易環境定義和交易中運作的物件。
當收到過時連線異常狀況的物件無法直接控制交易時(例如在儲存器管理交易的案例中),該物件必須將交易標示為回復,然後指示呼叫端重試交易。 在大多數情況下,如果要這麼做的話,您可以建立應用程式異常狀況來指示要重試該作業。然而,並非一定都容許執行此動作,而且方法通常只定義來建立特定的異常狀況。 Enterprise Bean 上的 ejbLoad() 和 ejbStore() 方法就是如此。下面兩個範例說明每一種情況。
範例 1:資料庫存取方法建立應用程式異常狀況
當存取資料庫的方法可任意建立任何需要的異常狀況時,最佳作法是捕捉過時連線異常狀況,並建立某種應用程式異常狀況供您解譯來重試方法。 下列範例顯示一個使用交易區分 TX_REQUIRED 在 Entity 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 先從 Home 介面取得 MyEJB Bean,並假定先前已從 Java 命名和目錄介面 (JNDI) 擷取。 然後對 Bean 呼叫 insertValue()。Bean 的這個方法會取得連線,並嘗試在表格中插入值。 如果其中一個方法失敗並引發過時連線異常狀況,則會將交易標示為 rollbackOnly(強制呼叫端回復該交易),並建立新的可重試的連線異常狀況,而且在擲出異常狀況之前會清除資源。 可重試的連線異常狀況只是應用程式定義的異常狀況,用於告知呼叫端重試方法。呼叫端會監視可重試的連線異常狀況,如果捕捉到該異常狀況,則重試方法。 在此範例中,因為儲存器會起始和結束交易,所以用戶端或伺服器中不需要交易管理。當然,用戶端可以啟動 Bean 管理的交易,只要用戶端也已確定或回復該交易,則行為仍然相同。

範例 2:資料庫存取方法建立 onlyRemote 異常狀況或 EJB 異常狀況
並不是所有的方法都能夠擲出應用程式所定義的異常狀況。如果您使用 Bean 管理的持續性 (BMP),請使用 ejbLoad()ejbStore() 方法來儲存 Bean 狀態。 從這些方法發出的異常狀況只有 java.rmi.Remote 異常狀況或 javax.ejb.EJB 異常狀況,因此您無法使用類似先前的範例。
如果您使用儲存器管理的持續性 (CMP),則儲存器會管理 Bean 持續性,而且是由該儲存器發現過時連線異常狀況。 如果偵測到過時連線,等到異常狀況傳回給用戶端時,就只是遠端異常狀況,因此簡單的 catch 區塊並不足夠。 有方法可判斷遠端異常狀況的主要原因是否為過時連線異常狀況。當建立遠端異常狀況來包裝另一個異常狀況時,通常會保留原始異常狀況。 所有遠端異常狀況實例都有一個詳細內容,類型為 java.lang.Throwable。利用此詳細資料,您可以往回追蹤到原始異常狀況,如果是過時連線異常狀況,則重試交易。 實際上,當其中一個遠端異常狀況在 Java 虛擬機器 API 之間流動時,詳細資料會遺失,所以最好是在進行資料庫存取時的同一伺服器中啟動交易。 因此,下列範例顯示由階段作業 Bean 使用 Bean 管理交易區分來存取的 Entity 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 物件,然後起始廣域交易。
  • 接下來,它呼叫 Entity Bean 的方法,這方法轉而呼叫 ejbLoad() 方法。如果 ejbLoad() 執行成功,則用戶端會確定交易,導致呼叫 ejbStore() 方法。
  • ejbStore() 中,Entity Bean 會取得連線並將其狀態寫入到資料庫;如果擷取的連線已過時,則將交易標示為 rollbackOnly,並擲出包裝 RetryableConnectionException 的新 EJBException。 然後,用戶端捕捉到該異常狀況,並且清除 JDBC 資源、回復交易,然後呼叫 causedByStaleConnection(),以判斷該異常狀況中的某處是否隱藏著過時連線異常狀況。
  • 如果此方法傳回 true,則設定重試旗標並重試交易;否則重新發出異常狀況給呼叫端。
  • causedByStaleConnection() 方法會瀏覽詳細屬性鏈,以尋找原始異常狀況。 等到異常狀況最終回到用戶端時,可能已包裝多個異常狀況,所以方法會持續搜尋,直到發現過時連線異常狀況為止,然後傳回 true;否則,就代表清單中沒有過時連線異常狀況,然後傳回 false
  • 如果是呼叫 CMP Bean 而不是 BMP Bean,則階段作業 Bean 相同。CMP Bean ejbStore() 方法很可能是空的,而儲存器在呼叫此方法之後,將持續保存 Bean 及產生的程式碼。
  • 如果持續保存期間發生過時連線異常狀況,則會包裝在遠端異常狀況中,並傳回給呼叫端。causedByStaleConnection() 方法將再次瀏覽異常狀況鏈,尋找根異常狀況,也就是過時連線異常狀況。
在區域交易環境定義中運作的物件
當資料庫作業發生在廣域交易環境定義之外時,儲存器會隱含地起始區域交易。這包括未以 UserTransaction 介面起始交易的 Servlet 或 JSP,以及在未指定的交易環境定義中執行的 Enterprise Bean。 如同廣域交易一樣,您必須在重試作業之前回復區域交易。在這些情況下,當商業方法結束時,區域交易限制通常也就結束。但使用活動階段作業時是唯一的例外。在此情況下,在試圖取得新連線之前,活動階段作業必須結束。

當區域交易發生在未指定的交易環境定義中執行的 Enterprise Bean 中時,區域交易限制外的 Enterprise Bean 用戶端物件可以使用前一個項目符號所述的方法來重試交易。 然而,當區域交易限制發生在 Servlet 或 JSP 檔之內時,就沒有用戶端物件可用於重試作業。因此,除非資料庫作業是使用者交易的一部分,建議避免在 Servlet 和 JSP 檔中執行資料庫作業。

Linux 系統上的過時連線

您可能必須設定迴圈,才能從 Linux 平台上的應用程式伺服器存取 DB2® 資料庫。

在以下任一種配置中,Linux 信號問題可能會干擾 JDBC 存取 DB2 資料庫:
  • 使用 DB2 Universal JDBC Type 2 驅動程式來連接到本端 DB2 資料庫
  • 使用 DB2 Universal JDBC Type 2 驅動程式,透過應用程式伺服器的同一台機器上安裝的 DB2 Connect™ 來存取 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

範例:處理 Servlet JDBC 連線異常狀況

下列程式碼範例示範如何設定交易管理和連線管理內容(例如作業重試次數),以解決 Servlet JDBC 交易內的過時連線異常狀況。

此程式碼範例執行下列動作:
  • 起始設定 Servlet
  • 查閱資料來源
  • 指定錯誤訊息、連線重試次數和交易回復需求
//===================START_PROLOG======================================
//
//   5630-A23, 5630-A22,
//   (C) COPYRIGHT International Business Machines Corp. 2002,2008
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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
//   All Rights Reserved
//   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
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   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) {
		 		 		 		 }
		 		 }
		 }

範例:處理資料存取異常狀況 - ConnectionWaitTimeoutException(適用於 Java EE 連接器架構)

下列程式碼範例示範如何指定條件,讓 WebSphere Application Server 據以針對 JCA 應用程式發出 ConnectionWaitTimeout 異常狀況。

在捕捉到 ConnectionWaitTimeout 異常狀況的所有情況下,幾乎無計可施,難以回復。

下列程式碼片段說明如何在 Java Platform Enterprise Edition (Java EE) 連接器架構 (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 中的錯誤對映

應用程式伺服器提供 DataStoreHelper 介面,可將不同的資料庫 SQL 錯誤碼對映至應用程式伺服器中的適當異常狀況。

由於各個資料庫供應商可能提供不同的 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) 順序分組功能來防止這些問題。

由於違反資料庫參照完整性,外部索引鍵衝突導致的異常狀況

資料庫參照完整性 (RI) 原則規定在資料庫表格中寫入和刪除資料的規則,以維護關聯式一致性。 但是,用於管理 Bean 持續性的執行時期需求,可能導致 Enterprise JavaBeans (EJB) 應用程式違反 RI 規則,進而造成資料庫異常狀況。

如果您在 WebSphere Application Server 追蹤檔或日誌檔中看到類似下列其中一個訊息(在執行 DB2 的環境中產生)的異常狀況訊息,則表示您的 EJB 應用程式違反資料庫 RI:
FOREIGN KEY table1.name_of_foreign_key_constraint 的插入或更新值
不等於母表格的母索引鍵的任何值。
無法刪除母列,因為關係 table1.name_of_foreign_key_constraint
不等於母表格的母索引鍵的任何值。

為了防止這些異常狀況,您必須為 Bean 定義序列群組,以指定 Entity Bean 更新關聯式資料庫表格的順序。

樂觀併行控制模式造成的死鎖所導致的異常狀況

另外,對於配置給樂觀併行控制的 Entity 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