Ausnahmen beim Datenzugriff

Alle CMP-Beans (Container-managed Persistence) einer Enterprise-Bean empfangen gemäß Spezifikation Enterprise JavaBeans (EJB) 2.x beim Scheitern einer Operation eine EJB-Standardausnahme. JDBC-Anwendungen (Java™ Database Connectivity) empfangen beim Scheitern einer JDBC-Operation eine SQL-Standardausnahme. Das Programm stellt spezielle Ausnahmen für seinen relationalen Ressourcenadapter (RRA, Relational Resource Adapter) bereit, die anzeigen, dass die derzeit gehaltene Verbindung nicht mehr gültig ist.

Anmerkung: Die angepasste Eigenschaft "userDefinedErrorMap" überschreibt vorhandene Einträge in der Fehlerzuordnung, indem sie die Methode "DataStoreHelper.setUserDefinedMap" startet. Mit dieser angepassten Eigenschaft können Sie Einträge der Fehlerzuordnung hinzufügen, ändern oder entfernen.
  • Die Einträge werden durch das Zeichen ; (Semikolon) begrenzt.
  • Jeder Eintrag besteht aus einem Schlüssel und einem Wert, wobei der Schlüssel ein Fehlercode (numerischer Wert) oder SQLState ist, d. h., ein in Anführungszeichen eingeschlossener Text.
  • Schlüssel und Werte sind durch = (Gleichheitszeichen) getrennt.
Geben Sie beispielsweise den folgenden Wert für "userDefinedErrorMap" an, um die Zuordnung von SQLState S1000 zu entfernen, die Zuordnung für den Fehlercode 1062 für doppelten Schlüssel hinzuzufügen und die Zuordnung von SQLState 08004 für nicht mehr aktuelle Verbindung hinzuzufügen:
"S1000"=;1062=com.ibm.websphere.ce.cm.DuplicateKeyException;"08004"=com.ibm.websphere.ce.cm.StaleConnectionException
"userDefinedErrorMap" kann in der Administrationskonsole definiert werden, indem die Datenquelle ausgewählt und die angepassten Eigenschaften konfiguriert werden.

Veraltete Verbindungen

Das Produkt stellt die spezielle Unterklasse "java.sql.SQLException" für die Verwendung des Verbindungs-Pooling für den Zugriff auf relationale Datenbanken bereit. Die Unterklasse "com.ibm.websphere.ce.cm.StaleConnectionException" in den WebSphere-Datenquellen der Version 4.0 und in den Datenquellen der aktuellen Version, die den relationalen Ressourcenadapter verwenden, vorhanden. Diese Unterklasse zeigt an, dass die gehaltene Verbindung nicht mehr gültig ist.

Eine solche Situation kann aus verschiedenen Gründen eintreten. Einige davon sind im Folgenden beschrieben:
  • Die Anwendung fordert eine Verbindung an und schlägt fehlt, wenn die Datenbank nicht gestartet ist.
  • Die Verbindung kann aufgrund eines Datenbankfehlers nicht mehr verwendet werden. Wenn eine Anwendung versucht, eine zuvor angeforderte Verbindung zu verwenden, ist die Verbindung nicht mehr gültig. In diesem Fall kann in allen Verbindungen, die derzeit von der Verbindung verwendet werden, dieser Fehler auftreten.
  • Die Verbindung ist verwaist (weil die Anwendung die Verbindung in dem Zeitlimit, das mit der Einstellung "Zeitlimit für nicht verwendete Verbindungen" mindestens zwei Mal nicht verwendet hat), und die Anwendung versucht, die verwaiste Verbindung zu verwenden. Dies gilt nur für Datenquellen der Version 4.0.
  • Die Anwendung versucht, eine JDBC-Ressource zu verwenden, z. B. eine Anweisung, die in einer nicht aktuellen Verbindung angefordert wurde.
  • Eine Verbindung wird von der Datenquelle der Version 4.0 geschlossen (Funktion für automatische Bereinigung von Verbindungen) und ist nicht mehr verwendbar. Die automatische Verbindungsbereinigung ist der Standardmodus, in dem die Verbindungsverwaltung arbeitet. In diesem Modus schließt der Transaktionsmanager am Ende einer Transaktion alle Verbindungen, die für diese Transaktion registriert sind. Auf diese Weise kann der Transaktionsmanager sicherstellen, dass Verbindungen nicht über einen längeren Zeitraum aufrechterhalten werden, und dass der Pool nicht vorzeitig die maximale Anzahl von Verbindungen erreicht.

    Wenn der Transaktionsmanager die Verbindungen schließt und nach dem Ende einer Transaktion an den Pool freier Verbindungen zurückgibt, hat dies zur Folge, dass eine Anwendung nicht in einer Transaktion eine Verbindung anfordern und diese in einer anderen Transaktion verwenden kann. Wenn die Anwendung dies versucht, wird eine Ausnahme des Typs ObjectClosedException ausgelöst, die wiederum eine StaleConnectionException-Ausnahme auslöst, weil die Verbindung bereits geschlossen ist.

Mit Hilfe der folgenden Konfigurationsangaben oder Einstellungen können Sie verhindern, dass StaleConnectionExceptions ausgelöst werden:
  • Wenn Sie die Mindestgröße des Verbindungspools auf 0 setzen, bleibt der Verbindungspool leer, wenn der Anwendungsserver während eines längeren Zeitraums inaktiv ist. Dadurch können Sie vermeiden, dass Verbindungen aufgrund der Verwaltungsaktivität auf der Datenbankseite als nicht aktuell eingestuft werden.
  • Setzen Sie das Zeitlimit für nicht verwendete Verbindungen für den Verbindungspool auf einen Wert, der kleiner ist als der für das Zeitlimit der Firewall konfigurierte Wert. Dadurch wird sichergestellt, dass die Verbindung bis zum Ablauf des Zeitlimits für nicht verwendete Verbindungen nicht als abgelaufen markiert wird und ermöglicht, dass die Verbindung zwecks Wiederverwendung im freien Pool verbleibt.
  • Setzen sie die Bereinigungszeit für den Verbindungspool auf einen Wert, der kleiner ist als das Zeitlimit für nicht verwendete Verbindungen. Je kleiner der Wert, desto häufiger prüft der Poolverwaltungsthread und desto genauer wird der Zeitgeber für nicht verwaltete Verbindungen eingestellt. Allerdings können häufig ausgeführte Poolverwaltungsthreads zu einer Leistungsverschlechterung führen.

Wenn versucht wird, eine verwaiste Verbindung oder eine durch die automatische Bereinigung geschlossene Verbindung zu verwenden, weist eine Ausnahme wegen einer veralteten Verbindung darauf hin, dass die Anwendung versucht hat, eine bereits an den Verbindungspool zurückgegebene Verbindung zu verwenden. Diese Ausnahme weist jedoch nicht auf ein tatsächliches Problem mit der Verbindung hin. In anderen Fällen kann die Ausnahme wegen einer nicht aktuellen Verbindung anzeigen, dass die Verbindung zur Datenbank ungültig oder nicht aktuell ist. Wenn eine Verbindung nicht aktuell ist, kann sie nicht wiederhergestellt werden. Sie müssen die Verbindung vollständig schließen, anstatt sie an den Pool zurückzugeben.

Veraltete Verbindungen erkennen

Wenn eine Verbindung zur Datenbank veraltet, löst der JDBC-Treiber beim Ausführen von Operationen in dieser Verbindung eine SQL-Ausnahme aus. Weil eine SQL-Ausnahme eine eher generische Ausnahme ist, enthält sie Status- und Fehlercodes, die Sie verwenden können, um die Bedeutung der Ausnahme zu bestimmen. Allerdings unterscheiden sich die Bedeutungen dieser Status- und Fehlercodes je nach Datenbankhersteller. Die Laufzeit des Verbindungs-Pooling verwaltet für jeden unterstützten Datenbankhersteller eine Aufstellung darüber, welche SQL-Status- und Fehlercodes eine Ausnahme wegen einer nicht aktuellen Verbindung anzeigen. Wenn die Laufzeitumgebung für das Verbindungs-Pooling eine SQL-Ausnahme abfängt, prüft sie, ob diese SQL-Ausnahme eine Ausnahme wegen einer nicht aktuellen Verbindung für den verwendeten Datenbankserver ist.

Wiederherstellung im Falle von veralteten Verbindungen
Wie eine Anwendung eine Ausnahme aufgrund einer nicht aktuellen Verbindung abfängt, ist abhängig vom Typ des Fehlererkennungsmodells, das in der Datenquelle konfiguriert ist:
  • Wenn das Fehlererkennungsmodell für die Ausnahmezuordnung konfiguriert ist, ersetzt der Anwendungsserver die vom JDBC-Treiber ausgelöste Ausnahme durch die Ausnahme "StaleConnectionException". In diesem Fall kann die Anwendung eine Ausnahme aufgrund einer nicht aktuellen Verbindung abfangen.
  • Wenn das Fehlererkennungsmodell für die Ausnahmeprüfung konfiguriert ist, prüft der Anwendungsserver weiterhin die Fehlerzuordnungstabelle, um den Verbindungspool zu verwalten, aber die Ausnahme wird nicht ersetzt. In diesem Fall sollte die Anwendung eine Ausnahme aufgrund einer nicht aktuellen Verbindung nicht abfangen.

Aufgrund der Unterschiede zwischen den Fehlererkennungsmodellen stellt der Anwendungsserver eine API bereit, die die Anwendungen in beiden Fällen verwenden können, um nicht aktuelle Verbindungen zu identifizieren. Hierbei handelt es sich um die API "com.ibm.websphere.rsadapter.WSCallHelper.getDataStoreHelper(datasource).isConnectionError(sqlexception)".

Anwendungen müssen eine Ausnahme aufgrund einer nicht aktuellen Verbindung nicht explizit identifizieren. Die Anwendungen müssen bereits Ausnahmen des Typs "java.sql.SQLException" abfangen, und die Ausnahmen über nicht aktuelle Verbindung oder die vom JDBC-Treiber ausgelöste Ausnahme übernimmt immer die Daten aus der Ausnahme "java.sql.SQLException". Die Ausnahme wegen einer nicht aktuellen Verbindung, die von jeder Methode ausgelöst werden kann, die für das Erstellen von "SQLException" deklariert wurde, wird automatisch im allgemeinen Abfangblock (catch-block) abgefangen. Wenn die Ausnahme wegen einer nicht aktuellen Verbindung jedoch explizit identifiziert werden kann, ist eine Wiederherstellung der Anwendung nach dem Erkennung ungültiger Verbindungen möglich. Wenn der Anwendungscode eine Ausnahme wegen einer nicht aktuellen Verbindung identifiziert, sollte er explizit Schritte zur Wiederherstellung ausführen, z. B. die Operation unter einer neuen Transaktion und einer neuen Verbindung wiederholen.

Beispiel: Behandlung von Ausnahmen beim Datenzugriff - Veraltete Verbindung

Diese Codebeispiele zeigen, wie Ausnahmen wegen veralteter Verbindungen für unterschiedliche Arten von Datenzugriffsclients in unterschiedlichen Transaktionszenarien über das Programm behandelt werden.

Wenn eine Anwendung eine Ausnahme wegen einer veralteten Verbindung für eine Datenbankoperation empfängt, zeigt sie an, dass die gegenwärtig gespeicherte Verbindung nicht mehr gültig ist. Obwohl eine Ausnahme vom Typ "Veraltete Verbindung" für jede Datenbankoperation zurückgegeben werden kann, wird eine solche Ausnahme am häufigsten zurückgegeben, wenn die Verbindung zum ersten Mal abgerufen wird. Da Verbindungen in Pools gestellt werden, wird ein Datenbankfehler erst ermittelt, wenn die Operation, die unmittelbar auf den Abruf aus dem Pool folgt, ausgeführt wird, d. h., wenn zum ersten Mal versucht wird, mit der Datenbank zu kommunizieren. Die Verbindung wird erst bei ihrer Ermittlung als alt markiert. Die Ausnahme wegen einer veralteten Verbindung tritt seltener auf, wenn alle Methoden, die auf die Datenbank zugreifen, eine neue Verbindung aus dem Pool abrufen.

Viele Ausnahmen wegen veralteten Verbindungen werden durch sporadisch auftretende Fehler im Netz des Datenbankservers ausgelöst. Wenn Sie dann eine neue Verbindung abrufen und die Operation wiederholen, kann die Operation ohne Ausnahmen ausgeführt werden. In manchen Fällen ist von Vorteil, eine kurze Wartezeit zwischen Versuchen verstreichen zu lassen, um dem Datenbankserver mehr Zeit für die Wiederherstellung zu lassen. Die Anwendungen dürfen die Operationen jedoch nicht unendlich lange wiederholen, falls die Datenbank über einen langen Zeitraum inaktiv ist.
Fehler vermeiden Fehler vermeiden: Wenn Sie Anwendungen für WebSphere Application Server mit einer integrierten Entwicklungsumgebung (IDE, Integrated Development Environment) wie Eclipse entwickeln, müssen Sie möglicherweise die Datei Stammverzeichnis_des_Anwendungsservers/plugins/com.ibm.ws.runtime.jar in die Entwicklungsumgebung importieren, um den bereitgestellten Code nutzen zu können.gotcha

Bevor die Anwendung eine neue Verbindung abrufen kann, um die Operation zu wiederholen, müssen Sie die Transaktion, an der die ursprüngliche Verbindung beteiligt war, zurücksetzen und eine neue Transaktion starten. Sie können die Informationen zu dieser Aktion in die folgenden beiden Kategorien unterteilen:

Objekte, die in einem Bean-gesteuerten globalen Transaktionskontext (der in derselben Methode gestartet wurde wie der Datenbankzugriff) ausgeführt werden
Eine Servlet- oder Session-Bean mit Bean-gesteuerten Transaktionen (BMT) kann eine Transaktion explizit starten, indem sie begin() für ein javax.transaction.UserTransaction-Objekt aufruft. Dieses Objekt kann vom Namensservice oder vom EJBContext-Objekt der Bean abgerufen werden. Zum Festschreiben einer Bean-gesteuerten Transaktion ruft die Anwendung commit() für das UserTransaction-Objekt auf. Zum Zurücksetzen der Transaktion ruft die Anwendung rollback() auf. Entity-Beans und Nicht-BMT-Session-Beans können globale Transaktionen nicht starten.

Wenn ein Objekt, das explizit eine Bean-gesteuerte Transaktion gestartet hat, eine Ausnahme wegen einer veralteten Verbindung für eine Datenbankoperation empfängt, müssen Sie die Verbindung schließen und die Transaktion zurücksetzen. An diesem Punkt kann der Entwickler entscheiden, ob er eine neue Transaktion beginnen, eine neue Verbindung abrufen und die Operation wiederholen soll.

Das folgende Codefragment ist ein Beispiel für die Behandlung von Ausnahmen wegen veralteten Verbindungen in diesem Szenario:
// userTransaction abrufen
javax.transaction.UserTransaction tran = getSessionContext().getUserTransaction();
//retry zeigt an, ob Wiederholungen durchgeführt werden sollen
//numOfRetries zeigt an, wie viele Wiederholungen versucht wurden
boolean retry = false;
int numOfRetries = 0;
java.sql.Connection conn = null;
java.sql.Statement stmt = null;
do {
  try  {    
    //Transaktion starten
    tran.begin();
    //Es wird vorausgesetzt, dass bereits eine Datenquelle
    //von JNDI abgerufen wurde
    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)
  {
    // Wenn der Fehler darauf hinweist, dass die Verbindung veraltet ist,
    // eine ROLLBACK-Operation ausführen und die Aktion wiederholen
    if (com.ibm.websphere.rsadapter.WSCallHelper
        .getDataStoreHelper(ds)
        .isConnectionError(sqlX))
    {
      try  {    
        tran.rollback();
      } catch (java.lang.Exception e) {
        //Ausnahme prüfen
        //Kann normalerweise ignoriert werden
      }
      if (numOfRetries < 2) {
        retry = true;
        numOfRetries++;
      } else {
        retry = false;
      }
    }
    else
    {
      //Ausnahme für andere Datenbank prüfen
      retry = false
    }
  } finally {
    //JDBC-Ressourcen immer löschen
    try  {    
      if(stmt != null) stmt.close();
    } catch (java.sql.SQLException sqle) {
      //Kann normalerweise ignoriert werden
    }
    try  {    
      if(conn != null) conn.close();
    } catch (java.sql.SQLException sqle) {
      //Kann normalerweise ignoriert werden
    }
  }
} while (retry) ;
Objekte, die in einem Bean-gesteuerten globalen Transaktionskontext ausgeführt werden, und eine Transaktion, die nicht in derselben Methode gestartet wurde wie der Datenbankzugriff.
Wenn das Objekt, das die Ausnahme wegen einer veralteten Verbindung empfängt, die Transaktion nicht direkt steuern kann, wie z. B. im Falle einer containergesteuerten Transaktion, muss es die Transaktion für das Zurücksetzen markieren und seinem aufrufenden Prozess (Caller) mitteilen, dass es die Transaktion wiederholen soll. In den meisten Fällen können Sie zu diesem Zweck für die Anwendung eine Ausnahme auslösen, die angibt, dass die Operation wiederholt werden soll. Diese Aktion ist jedoch nicht immer zulässig, und oft ist eine Methode so definiert, dass sie nur eine bestimmte Ausnahme auslöst. Dies trifft auf die Methoden ejbLoad() und ejbStore() in einer Enterprise-Bean zu. Die nächsten beiden Beispiele veranschaulichen diese Szenarien.
Beispiel 1: Methode für Datenbankzugriff löst eine Anwendungsausnahme aus
Wenn die Methode, die auf die Datenbank zugreift, jede erforderliche Ausnahme auslösen kann, empfiehlt es sich die Ausnahme wegen veralteter Verbindung abzufangen und eine Anwendungsausnahme zu erstellen, die Sie interpretieren können, um die Methode zu wiederholen. Das folgende Beispiel zeigt einen EJB-Client, der eine Methode mit der Transaktionsabgrenzung TX_REQUIRED für eine Entity-Bean aufruft, d. h., dass der Container eine globale Transaktion startet, wenn die Methode insertValue() aufgerufen wird:
public class MyEJBClient
{
  //... andere Methoden hier ...

  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);
  }  
}  //MyEJBClient beenden

public class MyEJB implements javax.ejb.EntityBean
{
  //... andere Methoden hier ...
  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)
    {
      // Herausfinden, ob der Fehler darauf hinweist, dass die Verbindung veraltet ist
      if (com.ibm.websphere.rsadapter.WSCallHelper
          .getDataStoreHelper(ds)
          .isConnectionError(sqlX))
      {
        getSessionContext().setRollbackOnly();
        throw new RetryableConnectionException();
      }
      else
      {
        //Fehler in anderer Datenbank beheben
      }
    }
    finally
    {
      //JDBC-Ressourcen immer löschen
      try 
      {
        if(stmt != null) stmt.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //Kann normalerweise ignoriert werden
      }
      try 
      {
        if(conn != null) conn.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //Kann normalerweise ignoriert werden
      }
    }
  }
}  //MyEJB beenden

MyEJBClient ruft zuerst eine MyEJB-Bean von der Home-Schnittstelle ab, von dem angenommen wird, dass es zuvor über JNDI (Java Naming and Directory Interface) abgerufen wurde. Dann ruft der Client insertValue() für die Bean ab. Die Methode für die Bean ruft eine Verbindung ab und versucht, einen Wert in eine Tabelle einzufügen. Wenn eine der Methode mit einer Ausnahme wegen veralteter Verbindung fehlschlägt, wird die Transaktion als rollbackOnly gekennzeichnet (was den Caller (Aufrufender) dazu veranlasst, die Transaktion rückgängig zu machen) und eine neue Ausnahme vom Typ wiederholbare Verbindung erstellt, die die Ressourcen bereinigt, bevor die Ausnahme ausgelöst wird. Die Ausnahme für wiederholbare Verbindung ist lediglich eine anwendungsdefinierte Ausnahme, die dem Caller mitteilt, die Methode zu wiederholen. Der aufrufende Prozess überwacht diese Ausnahme und wiederholt die Methode, wenn die Ausnahme abgefangen wird. In diesem Beispiel ist keine Transaktionsverwaltung auf dem Client oder dem Server erforderlich; da der Container in der Transaktion beginnt und endet. Der Client kann natürlich eine Bean-gesteuerte Transaktion starten, und das Verhalten ist dann, vorausgesetzt, der Client hat die Transaktion festgeschrieben oder zurückgesetzt.

Beispiel 2: Die Methode für Datenbankzugriff erstellt eine Ausnahme onlyRemote oder eine EJB-Ausnahme
Nicht alle Methoden haben die Berechtigung, von der Anwendung definierte Ausnahmen auszulösen. Wenn Sie mit BMP (Bean-Managed Persistence, über JavaBeans realisierte Transaktionspersistenz oder einfach Bean-gesteuerte Persistenz) arbeiten, werden die Methoden ejbLoad() und ejbStore() zum Speichern des Bean-Status verwendet. Die einzigen Ausnahmen, die von diesen Methoden ausgelöst werden, sind java.rmi.Remote und javax.ejb.EJB. Daher können Sie nicht wie im vorigen Beispiel beschrieben vorgehen.
Wenn Sie mit containergesteuerter Persistenz (CMP) arbeiten, verwaltet der Container die Bean-Persistenz, und es ist auch der Container, der die Ausnahme wegen veralteter Verbindung erkennt. Wenn eine veraltete Verbindung erkannt wird, ist die Ausnahme zu dem Zeitpunkt, zu dem sie an den Client zurückgegeben wird, lediglich eine ferne Ausnahme. Deshalb ist ein einfacher Abfangblock (Catch-Block) nicht ausreichend. Es besteht jedoch die Möglichkeit festzustellen, ob die ursprüngliche Ursache einer fernen Ausnahme eine Ausnahme wegen veralteter Verbindung ist. Wenn die ferne Methode eine andere Ausnahme einschließt, wird die ursprüngliche Ausnahme in der Regel beibehalten. Alle fernen Ausnahmeinstanzen haben eine Detaileigenschaft des Typs java.lang.Throwable. Mit dieser Detaileigenschaft können Sie die ursprüngliche Ausnahme ermitteln. Falls es sich dabei um eine Ausnahme wegen veralteter Verbindung handelt, können Sie die Transaktion wiederholen. Tatsächlich geht die Detaileigenschaft verloren, wenn eine dieser fernen Ausnahmen von einer JVM-API an die nächste übergeben wird, daher empfiehlt es sich, eine Transaktion auf demselben Server zu starten, auf dem der Datenbankzugriff erfolgt. Aus diesem Grund zeigt das folgende Beispiel eine Entity-Bean, auf die eine Session-Bean mit Bean-gesteuerter Transaktionsabgrenzung zugreift.
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();
        // Bewirkt, dass ejbLoad() gestartet wird
        myBMPBean.myMethod();
        // Bewirkt, dass ejbStore() gestartet wird
        tran.commit();
      }
      catch(java.rmi.EJBException re)
      {
        try 
        {
          tran.rollback();
        }
        catch (Exception e)
        {
          //Kann ignoriert werden
        }
        if (causedByStaleConnection(re))
          retry = true;
        else
          throw re;
      }
      catch (Exception e)
      {
        // Andere Fehler beheben
      }
      finally
      {
        //JDBC-Ressourcen immer löschen
        try 
        {
          if(stmt != null) stmt.close();
        }
        catch (java.sql.SQLException sqle)
        {
          //Kann normalerweise ignoriert werden
        }
        try 
        {
          if(conn != null) conn.close();
        }
        catch (java.sql.SQLException sqle)
        {
          //Kann normalerweise ignoriert werden
        }
      }
    }
    while (retry);
  }

  public boolean causedByStaleConnection(java.rmi.EJBException re)
  {
    // In der Ausnahmekette nach Fehlern suchen, die auf eine
    // veraltete Verbindung hinweist
    for (Throwable t = re; t != null; t = t.getCause())
      if (t instanceof RetryableConnectionException)
        return true;

    // Verbindung nicht veraltet
    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)
    {
      // Herausfinden, ob der Fehler darauf hinweist, dass die Verbindung veraltet ist
      if (com.ibm.websphere.rsadapter.WSCallHelper
          .getDataStoreHelper(ds)
          .isConnectionError(sqlX))
      {
        // Transaktion bei Rückgabe der Methode zurücksetzen
        getEntityContext().setRollbackOnly();
        throw new java.rmi.EJBException(
          "Exception occurred in ejbStore",
          new RetryableConnectionException(sqlX));
      }
      else
      {
        // Andere Fehler beheben
      }
    }
    finally
    {
      //JDBC-Ressourcen immer löschen
      try 
      {
        if(stmt != null) stmt.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //Kann normalerweise ignoriert werden
      }
      try 
      {
        if(conn != null) conn.close();
      }
      catch (java.sql.SQLException sqle)
      {
        //Kann normalerweise ignoriert werden
      }
    }
  }
}
In mySessionBMTMethod() des vorherigen Beispiels:
  • Die Session-Bean zuerst ein UserTransaction-Objekt vom Sitzungskontext ab und startet dann eine globale Transaktion.
  • Dann ruft sie eine Methode für die Entity-Bean auf, die die Methode ejbLoad() aufruft. Wenn ejbLoad() ausgeführt wird, schreibt der Client die Transaktion anschließend fest und bewirkt, dass die Methode ejbStore() aufgerufen wird.
  • In ejbStore() ruft die Entity-Bean eine Verbindung ab und schreibt deren Status in die Datenbank. Wenn die abgerufene Verbindung alt ist, wird sie als rollbackOnly markiert, und eine neue EJBException, die auf die RetryableConnectionException folgt, wird ausgelöst. Diese Ausnahme wird vom Client abgefangen, der die JDBC-Ressourcen bereinigt, die Transaktion rückgängig macht und die Methode causedByStaleConnection() aufruft, die feststellt, ob eine Ausnahme wegen veralteter Verbindung irgendwo in der Ausnahme verborgen ist.
  • Wenn die Methode den Wert "true" zurückgibt, wird das retry-Flag gesetzt, die Transaktion wird wiederholt. Andernfalls wird die Ausnahme für den aufrufenden Prozess erneut ausgelöst.
  • Die Methode causedByStaleConnection() durchsucht die Kette von Detailattributen, um die Originalausnahme zu ermitteln. Bis die Ausnahme den Client endgültig wieder erreicht, können mehrere Ausnahmen in der ausgelösten Ausnahme verborgen sein. Deshalb sucht die Methode weiter, bis sie eine Ausnahme vom Typ "Veraltete Verbindung" findet und true zurückgegeben wird. Wenn keine Ausnahme dieses Typs in der Liste gefunden wird, wird false zurückgegeben.
  • Wenn die Kommunikation mit einer CMP-Bean anstatt mit einer BMP-Bean erfolgt, ist die Session-Bean gleich. Die Methode ejbStore() der CMP-Bean ist dann höchstwahrscheinlich leer, und der Container speichert die Bean mit generiertem Code persistent, nachdem er die Methode aufgerufen hat.
  • Wenn während der Persistenz eine Ausnahme wegen einer veralteten Verbindung auftritt, wird sie in einer fernen Ausnahme verborgen, die an den aufrufenden Prozess zurückgegeben wird. Die Methode causedByStaleConnection() durchsucht die Ausnahmekette dann erneut nach der eigentlichen Ausnahme, der Ausnahme wegen veralteter Verbindung.
Objekte, die in einem lokalen Transaktionskontext ausgeführt werden
Wenn eine Datenbankoperation außerhalb des globalen Transaktionskontextes ausgeführt wird, wird eine lokale Transaktion vom Container implizit gestartet. Dies umfasst Servlets oder JSPs, die Transaktionen nicht mit der Schnittstelle UserTransaction starten, sowie Enterprise-Beans, die in nicht angegebenen Transaktionskontexten ausgeführt werden. Wie bei globalen Transaktionen müssen Sie die lokale Transaktion zurücksetzen, bevor die Operation wiederholt wird. In diesen Fällen endet das LTC (Local Transaction Containment), wenn die Geschäftsmethode endet. Dies gilt nur in den Fällen, in denen Sie Activity-Sessions verwenden, nicht. In diesem Fall muss die Activity-Session beendet werden, bevor versucht wird, eine neue Verbindung abzurufen.

Wenn die lokale Transaktion in einer Enterprise-Bean ausgeführt wird, die in einem nicht angegebenen Transaktionskontext aktiv ist, kann das Clientobjekt der Enterprise-Bean außerhalb des LTC (Local Transaction Containment) die unter dem vorangegangenen Punkt beschriebene Methode verwenden, um die Transaktion zu wiederholen. Wenn das LTC jedoch als Teil eines Servlet oder einer JSP-Datei verwendet wird, ist kein Clientobjekt verfügbar, um die Operation zu wiederholen. Aus diesem Grund wird empfohlen, Datenbankoperationen in Servlets und in der JSP-Datei zu vermeiden, es sei denn, sie sind Bestandteil einer Benutzertransaktion.

Veraltete Verbindung auf Linux-Systemen

Damit Sie über den Anwendungsserver auf DB2-Datenbanken auf einer Linux-Plattform zugreifen können, müssen Sie möglicherweise ein Loopback festlegen.

In den folgenden Konfigurationen kann ein Linux-Semaphor beim JDBC-Zugriff auf Ihre DB2-Datenbank Probleme verursachen:
  • Wenn Sie mit dem DB2 Universal JDBC Driver Type 2 auf eine lokale DB2-Datenbank zugreifen
  • Wenn Sie mit dem DB2 Universal JDBC Driver Type 2 auf DB2 for z/OS zugreifen und dazu eine Installation von DB2 Connect verwenden, die sich auf derselben Maschine befindet wie der Anwendungsserver. Das Problem tritt nur dann auf, wenn DB2 Connect die Ausführung von lokalen Clients innerhalb eines Agenten ausschließt, (d. h., wenn DB2_IN_APP_PROCESS nicht auf den Standardwert oder aber auf Yes gesetzt ist. Geben Sie No als Wert an, um das Problem zu beheben, und vermeiden Sie die Ausführung der folgenden Prozedur.)
Dieses Problem bewirkt häufig, dass JVM-Protokolle die DB2-Ausnahme wegen veralteter Verbindung SQL1224 anzeigt. Weil jedoch verschiedene SQL-Ausnahmecodes angezeigt werden können, sollten Sie im Fall einer veralteten Verbindung das DB2-Traceprotokoll prüfen. Wenn Sie die folgenden Fehlerdaten finden, dann ist das Verhalten des Linux-Semaphor der Auslöser für das Problem:
'71' -SQLCC_ERR_CONN_CLOSED_BY_PARTNER and SQLCODE -XXXX
Sie können dieses Problem umgehen, indem Sie ein Loopback für die Datenbank definieren. Wenn z. B. Ihre Datenbank WAS, der Hostname LHOST und die Portnummer des Datenbankservice 50000 lauten, geben Sie die folgenden Befehle über das DB2-Befehlszeilenfenster ein:
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

Beispiel: Behandlung von Ausnahmen der Servlet-JDBC-Verbindung.

Das folgende Codebeispiel zeigt, wie die Eigenschaften für die Transaktionsverwaltung und die Verbindungsverwaltung festgelegt werden, z. B. die Anzahl der Operationswiederholungen, um auf Ausnahmen wegen veralteter Verbindungen innerhalb einer Servlet-JDBC-Transaktion zu reagieren.

Dieser Beispielcode führt die folgenden Aktionen aus:
  • Er initialisiert ein Servlet.
  • Er ermittelt eine Datenquelle.
  • Er legt die Fehlernachrichten, die Zahl der Verbindungswiederholungen und die Voraussetzungen für ein Rollback der Transaktion fest.
//===================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.*;
// JDBC-Pakete und Namensservicepaket importieren.
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    = "Mitarbeiterliste";    

// ****************************************************************
// * Servlet beim ersten Laden initialisieren. *
// * Daten von properties-Datei abrufen und DataSource-Objekt     *
// * über JNDI prüfen, um die Leistung der Servicemethoden        *
// * des Servlet zu verbessern. *
// ****************************************************************
    public void init(ServletConfig config)
    throws ServletException
    {
        super.init(config);
        getDS();
    }

// ****************************************************************
// * JNDI-Lookup für das DataSource-Objekt und das UserTransaction-Objekt *
// * durchführen. *
// * Diese Methode wird von init() und vom Service aufgerufen             *
// * Methode der Datenquelle ist 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);
            		 		 // Namensservice-Lookup zum Abrufen des DataSource-Objekts durchführen.
            		 		 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();
        }
    }

// ****************************************************************
// * Antwort auf GET-Anforderung des Benutzers                    *
// ****************************************************************
    public void doGet(HttpServletRequest req, HttpServletResponse res) throws ServletException, IOException
    {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        Vector employeeList = new Vector();
        // retryCount auf die gewünschte Anzahl der Wiederholungen nach
        // Ausnahme aufgrund einer veralteten Verbindung setzen
        int retryCount = 5;  
        // Wenn der Datenbankcode erfolgreich ausgeführt wird, wird error = false eingestellt.
        boolean error = true;
        do
        {
            try 
            {          
                //Eine neue Transaktion starten
                ut.begin();
                  // Verbindungsobjekt conn wird mit der DataSource-Factory abrufen.
                conn = ds.getConnection();
                // DB-Abfrage mit JDBC-Standardcodierung durchführen.
                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));
                }                           
                        //error=false einstellen, um Fertigstellung der Datenbankoperationen anzuzeigen.
                error=false;                    
            }
            catch (SQLException sqlX)
            {
              // Feststellen, ob das zulässige Zeitlimit für Verbindungsanforderungen
    // überschritten ist.
              // Dieser Code funktioniert mit jedem Fehlerkennungsmodell.
              // Wenn die Ausnahmezuordnung aktiviert ist, muss nach einer
              // ConnectionWaitTimeoutException gesucht werden.
              // Wenn die Ausnahmeprüfung aktiviert ist, nach einer
              // SQLTransientConnectionException mit einer verketteten
              // ConnectionWaitTimeoutException suchen.

              if ( sqlX instanceof ConnectionWaitTimeoutException
                || sqlX instanceof SQLTransientConnectionException
                   && sqlX.getCause() instanceof ConnectionWaitTimeoutException)
              {
                // Diese Ausnahme wird ausgelöst, wenn eine Verbindung nicht
                // innerhalb eines konfigurierbaren Zeitraum aus einem Pool abgerufen
// werden kann.  Ein häufiges Auftreten dieser Ausnahme ist
                // ein Hinweis auf einen falsch optimierten Verbindungspool.

                System.out.println("Connection Wait Timeout Exception during get connection or 
process SQL: " + c.getMessage());  
     
                // Im Allgemeinen sollen nach dieser Ausnahme keine Wiederholungen
                // durchgeführt werden, daher den Wiederholungszähler auf 0 setzen und
                // die Transaktion zurücksetzen.
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se) {
                    //Wird ausgelöst, um anzuzeigen, dass der Thread die Transaktion nicht zurücksetzen darf.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise) {
                    //Wird ausgelöst, wenn der aktuelle Thread keiner Transaktion zugeordnet ist.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye) {
                    //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                retryCount=0;
              }
              else if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(sqlX))
              {
                // Diese Ausnahme zeigt an, dass die Verbindung zur Datenbank nicht mehr gültig ist.
                // Die Transaktion zurücksetzen, dann mehrmals versuchen, eine gültige Verbindung herzustellen
                // und, falls das nicht möglich ist, eine Fehlernachricht anzeigen.

                System.out.println("Connection is stale: " + sc.getMessage());
                
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se) {
                    //Wird ausgelöst, um anzuzeigen, dass der Thread die Transaktion nicht zurücksetzen darf.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise) {
                    //Wird ausgelöst, wenn der aktuelle Thread keiner Transaktion zugeordnet ist.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye) {
                    //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
                    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());

                // Im Allgemeinen sollen nach dieser Ausnahme keine Wiederholungen
// durchgeführt werden, daher den Wiederholungszähler auf 0 setzen und
// die Transaktion zurücksetzen.
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se) {
                    //Wird ausgelöst, um anzuzeigen, dass der Thread die Transaktion nicht zurücksetzen darf.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise) {
                    //Wird ausgelöst, wenn der aktuelle Thread keiner Transaktion zugeordnet ist.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye) {
                    //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                retryCount=0;
              } 
            }
            catch (NotSupportedException nse) {
                //Wird von UserTransaction-Startmethode ausgelöst, wenn der Thread bereits einer 
                //Transaktion zugeordnet wurde und die Implementierung des Transaktionsmanagers
//keine verschachtelten Transaktionen unterstützt.
                System.out.println("NotSupportedException on User Transaction begin: "                                     + nse.getMessage());
            } 
            catch (SystemException se) {
                //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
                System.out.println("SystemException in User Transaction:" + se.getMessage());
            } 
            catch (Exception e) 
            {
                System.out.println("Exception in get connection or process SQL: " + e.getMessage());
                // Im Allgemeinen sollen nach dieser Ausnahme keine Wiederholungen
                // durchgeführt werden, daher den Wiederholungszähler auf 5 setzen und
                // die Transaktion zurücksetzen.
                try 
                {
                    ut.setRollbackOnly();
                } 
                catch (SecurityException se) {
                    //Wird ausgelöst, um anzuzeigen, dass der Thread die Transaktion nicht zurücksetzen darf.
                    System.out.println("Security Exception setting rollback only!" + se.getMessage());
                } 
                catch (IllegalStateException ise) {
                    //Wird ausgelöst, wenn der aktuelle Thread keiner Transaktion zugeordnet ist.
                    System.out.println("Illegal State Exception setting rollback only!" + ise.getMessage());
                } 
                catch (SystemException sye) {
                    //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
                    System.out.println("System Exception setting rollback only!" + sye.getMessage());
                }
                retryCount=0;
            } 
            finally
            {
                // Die Verbindung in einer finally-Anweisung immer schließen, um 
                // in allen Fällen ein ordnungsgemäßes Schließen zu gewährleisten. // Durch das Schließen der Verbindung wird die aktuelle Verbindung 
                // nicht tatsächlich geschlossen, sondern zur Wiederverwendung in
     // Pool zurückgegeben.

                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) {
                    //Wird ausgelöst, um anzuzeigen, dass die Transaktion zurückgesetzt und nicht
//festgeschrieben wurde.
                    System.out.println("User Transaction Rolled back!" + re.getMessage());
                } 
                catch (SecurityException se) {
                    //Wird ausgelöst, um anzuzeigen, dass der Thread die Transaktion nicht zurücksetzen darf.
                    System.out.println("Security Exception thrown on transaction commit: "                                     + se.getMessage());
                } 
                catch (IllegalStateException ise) {
                    //Wird ausgelöst, wenn der aktuelle Thread keiner Transaktion zugeordnet ist.
                    System.out.println("Illegal State Exception thrown on transaction commit: " + ise.getMessage());
                } 
                catch (SystemException sye) {
                    //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
                    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 );

        // HTML-Antwort vorbereiten und zurückgeben, das Zwischenspeichern
        // von dynamischem Inhalt auf Browsern verhindern.
        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());
        }
    }
}

Beispiel: Behandlung von Verbindungsausnahmen für Session-Beans in containergesteuerten Datenbanktransaktionen

Das folgende Codebeispiel zeigt, wie im Fall von Ausnahmen wegen veralteter Verbindungen Transaktionen rückgängig gemacht und Ausnahmen an den Bean-Client ausgegeben werden.

//===================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;

/*************************************************************************************
* Diese Bean wurde konzipiert, um Datenbankverbindungen in einer containergesteuerten *                      
* Transaktions-Session-Bean zu veranschaulichen.  Das Transaktionsattribut der Bean    *
* muss auf TX_REQUIRED oder TX_REQUIRES_NEW gesetzt werden. *
**************************************************************************************
*/
public class ShowEmployeesCMTBean implements SessionBean {
		 		 private javax.ejb.SessionContext mySessionCtx = null;
		    final static long serialVersionUID = 3206093459760846163L;
		 
		 	private javax.sql.DataSource ds;

//************************************************************************************
//* ejbActivate ruft die Methode getDS auf, die den JNDI-Lookup für die DataSource durchführt.
//* Da der Lookup für die DataSource sich in einer separaten Methode befindet, kann er
//* auch über die Methode getEmployees aufgerufen werden, wenn das DataSource-Feld leer ist. 		
//************************************************************************************
public void ejbActivate() throws java.rmi.EJBException {
		 getDS();
}
/**
 * Methode ejbCreate 
 * @exception javax.ejb.CreateException
 * @exception java.rmi.EJBException
 */
public void ejbCreate() throws javax.ejb.CreateException, java.rmi.EJBException {}
/**
 * Methode ejbPassivate
 * @exception java.rmi.EJBException
 */
public void ejbPassivate() throws java.rmi.EJBException {}
/**
 * ejbRemove method
 * @exception java.rmi.EJBException 
 */
public void ejbRemove() throws java.rmi.EJBException {}

//************************************************************************************
//* Die Methode getEmployees führt die Datenbankabfrage durch und ruft die Angestelltendaten ab.		//* Die Methode getDS wird nur aufgerufen, wenn keine DataSource-Variable angegeben ist.			//* Da diese Session-Bean containergesteuerte Transaktion verwendet, kann sie die Transaktion	
//* nicht nach einer StaleConnectionException ausführen.  Sie kann jedoch eine Ausnahme
//* für ihren Client auslösen, die angibt, dass die Operation wiederholt werden kann.				
//************************************************************************************

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 
   {
        // Verbindungsobjekt conn wird mit der DataSource-Factory abrufen.
      conn = ds.getConnection();
      // DB-Abfrage mit JDBC-Standardcodierung durchführen.
      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)
   {
     // Feststellen, ob die Verbindung veraltet ist.
     if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(sqlX))
     {
       // Diese Ausnahme zeigt an, dass die Verbindung zur Datenbank nicht mehr gültig ist.
       // Die Transaktion zurücksetzen und eine Ausnahme an den Client absetzen, die anzeigt,
       // dass die Transaktion gegebenenfalls wiederholt werden kann.

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

       mySessionCtx.setRollbackOnly();
       throw new RetryableConnectionException(sqlX.toString());
     }
     // Feststellen, ob das zulässige Zeitlimit für Verbindungsanforderungen
    // überschritten ist.
     else if ( sqlX instanceof ConnectionWaitTimeoutException
            || sqlX instanceof SQLTransientConnectionException
               && sqlX.getCause() instanceof ConnectionWaitTimeoutException)
     {
       // Diese Ausnahme wird ausgelöst, wenn eine Verbindung nicht
       // innerhalb eines konfigurierbaren Zeitraum aus einem Pool abgerufen
// werden kann.  Ein häufiges Auftreten dieser Ausnahme ist
       // ein Hinweis auf einen falsch optimierten Verbindungspool.

       System.out.println("Connection Wait Timeout Exception during get connection or process SQL: " +
       sqlX.getMessage());
       throw sqlX instanceof ConnectionWaitTimeoutException ?
             sqlX :
             (ConnectionWaitTimeoutException) sqlX.getCause();
     } 
     else
     {
       //Durch das Auslösen einer fernen Ausnahme wird die containergesteuerte
       //Transaktion automatisch zurückgesetzt

       System.out.println("SQL Exception during get connection or process SQL: " +
		 		 		 		 sqlX.getMessage());
       throw sqlX;
     } 
   }
   finally
   {
     // Die Verbindung in einer finally-Anweisung immer schließen, um 
     // in allen Fällen ein ordnungsgemäßes Schließen zu gewährleisten. // Durch das Schließen der Verbindung wird die aktuelle Verbindung 
     // nicht tatsächlich geschlossen, sondern zur Wiederverwendung in
     // Pool zurückgegeben.

     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;
}

/**
 * Methode getSessionContext
 * @return javax.ejb.SessionContext
 */
public javax.ejb.SessionContext getSessionContext() {
		 		 return mySessionCtx;
}
//************************************************************************************
//* Die Methode "getDS" für die JNDI-Lookup-Operation für die Datenquelle aus.
//* Diese Methode wird über ejbActivate und getEmployees aufgerufen, wenn     *
//* kein DataSource-Objekt angegeben ist.              								               *//************************************************************************************

private void getDS() {
		 try  {    
		 		 Hashtable parms = new Hashtable();
		 		 parms.put(Context.INITIAL_CONTEXT_FACTORY, 
		 		 		 		 com.ibm.websphere.naming.WsnInitialContextFactory);
		 		 InitialContext ctx = new InitialContext(parms);
		 		 		 		 // Namensservice-Lookup zum Abrufen des DataSource-Objekts durchführen.
		 		 		 		 ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
		 } 
       catch (Exception e) {
		 		 System.out.println("Naming service exception: " + e.getMessage());
		 		 e.printStackTrace();
		 }
}
/**
 * Methode setSessionContext
 * @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;

/**
 * Dies ist eine Home-Schnittstelle für die Session-Bean
 */
public interface ShowEmployeesCMTHome extends javax.ejb.EJBHome {

/**
 * Methode create für eine 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;

/**
 * Dies ist ein ferne EJB-Schnittstelle
 */
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;

/**
 * Ausnahme, die anzeigt, dass die Operation wiederholt werden kann
 * Build-Datum: (02.04.2001 10:48:08)
 * @author: Administrator
 */
public class RetryableConnectionException extends Exception {
/**
 * Konstruktor RetryableConnectionException.
 */
public RetryableConnectionException() {
		 		 super();
}
/**
 * Konstruktor RetryableConnectionException.
 * @param s java.lang.String
 */
public RetryableConnectionException(String s) {
		 		 super(s);
}
}

Beispiel: Behandlung von Verbindungsausnahmen für Session-Beans in Bean-gesteuerten Datenbanktransaktionen

Das folgende Codebeispiel zeigt Optionen zur Behandlung von Ausnahmen wegen veralteter Verbindungen. Sie können verschiedene Parameter für die Transaktionsverwaltung und Verbindungsverwaltung festlegen, z. B. die Anzahl der Operationswiederholungen und das Zeitlimit für Verbindungen.

//===================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;

/**********************************************************************************
* Diese Bean wurde konzipiert, um Datenbankverbindungen in einer Bean-gesteuerten
* Transaktions-Session-Bean zu veranschaulichen. Das Transaktionsattribut der Bean    *
* muss auf TX_BEANMANAGED gesetzt werden. **********************************************************************************/
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 ruft die Methode getDS auf, die den JNDI-Lookup für die DataSource durchführt.
//* Da der Lookup für die DataSource sich in einer separaten Methode befindet, kann er
//* auch über die Methode getEmployees aufgerufen werden, wenn das DataSource-Feld leer ist. 		
//************************************************************************************
public void ejbActivate() throws java.rmi.EJBException {
		 getDS();
}
/**
 * Methode ejbCreate 
 * @exception javax.ejb.CreateException
 * @exception java.rmi.EJBException
 */
public void ejbCreate() throws javax.ejb.CreateException, java.rmi.EJBException {}
/**
 * Methode ejbPassivate
 * @exception java.rmi.EJBException
 */
public void ejbPassivate() throws java.rmi.EJBException {}
/**
 * ejbRemove method
 * @exception java.rmi.EJBException
 */
public void ejbRemove() throws java.rmi.EJBException {}

//************************************************************************************
//* Die Methode getEmployees führt die Datenbankabfrage durch und ruft die Angestelltendaten ab.		//* Die Methode getDS wird nur aufgerufen, wenn keine DataSource- bzw. userTran-Variable angegeben ist.			
//* Wenn eine veraltete Verbindung gefunden wird, versucht die Bean, die Transaktion fünf Mal zu
//* wiederholen, und löst dann eine Ausnahme vom Typ "EJBException" aus.
//************************************************************************************

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

   // retryCount auf die gewünschte Anzahl der Wiederholungen nach
   // Erkennung einer veralteten Verbindung setzen

   int retryCount = 5;  
    
   // Wenn der Datenbankcode erfolgreich ausgeführt wird, wird error = false eingestellt.
   boolean error = true;
   
   if (ds == null || userTran == null) getDS();
   do
   {		 		 
         try 
         { 
            //try/catch-Block für UserTransaction-Vorgänge
            //Die Transaktion beginnen
            userTran.begin ();
            try 
            { 
               //try/catch-Block für Datenbankoperation
               // Verbindungsobjekt conn wird mit der DataSource-Factory abrufen.
               conn = ds.getConnection();
               // DB-Abfrage mit JDBC-Standardcodierung durchführen.
               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));
               }
               //Da alle Datenbankoperationen erfolgreich ausgeführt werden, error = false setzen.
               error = false;
            } 
            catch (SQLException sqlX)
            {
              if (WSCallHelper.getDataStoreHelper(ds).isConnectionError(sqlX))
              {
                // Diese Ausnahme zeigt an, dass die Verbindung zur Datenbank nicht mehr gültig ist.
                // Die Transaktion zurücksetzen und eine Ausnahme an den Client absetzen, die anzeigt,
// dass die Transaktion gegebenenfalls wiederholt werden kann.

                System.out.println("Stale connection: " +
                se.getMessage());
                userTran.rollback();
                if (--retryCount == 0)
                {
                  //Die Transaktion wurde bereits so häufig wie angefordert wiederholt, eine EJBException auslösen.
                  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)
              {
                // Diese Ausnahme wird ausgelöst, wenn eine Verbindung nicht
                // innerhalb eines konfigurierbaren Zeitraum aus einem Pool abgerufen
// werden kann.  Ein häufiges Auftreten dieser Ausnahme ist
                // ein Hinweis auf einen falsch optimierten Verbindungspool.

                System.out.println("Connection request timed out: " + 
                sqlX.getMessage());
                userTran.rollback();
                throw new EJBException("Transaction failure: " + sqlX.getMessage());
              } 
              else
              {                   
		  	  // catch bearbeitet alle anderen SQL-Ausnahmen
                System.out.println("SQL Exception during get connection or process SQL: " +
		 		 		 		 sqlX.getMessage());
                userTran.rollback();
                throw new EJBException("Transaction failure: " + sqlX.getMessage());
              } 
            finally
            {
              // Die Verbindung in einer finally-Anweisung immer schließen, um 
              // in allen Fällen ein ordnungsgemäßes Schließen zu gewährleisten. // Durch das Schließen der Verbindung wird die aktuelle Verbindung 
              // nicht tatsächlich geschlossen, sondern zur Wiederverwendung in
     // Pool zurückgegeben.

              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) {
         //Datenbankvorgänge erfolgreich abgeschlossen, die Transaktion festschreiben
         userTran.commit ();
      }
      //Ausnahmen für UserTransaction abfangen
      } 
      catch (NotSupportedException nse) {

//Wird von UserTransaction-Startmethode ausgelöst, wenn der Thread bereits einer 
//Transaktion zugeordnet wurde und die Implementierung des Transaktionsmanagers
//keine verschachtelten Transaktionen unterstützt.
 System.out.println("NotSupportedException on User Transaction begin: " +
                                 nse.getMessage());
         throw new EJBException("Transaction failure: " + nse.getMessage());
      } 
      catch (RollbackException re) {
//Wird ausgelöst, um anzuzeigen, dass die Transaktion zurückgesetzt und nicht
//festgeschrieben wurde.
         System.out.println("User Transaction Rolled back!" + re.getMessage());
         throw new EJBException("Transaction failure: " + re.getMessage());
      } 
      catch (SystemException se) {
		   //Wird ausgelöst, wenn der Transaktionsmanager eine unerwartete Fehlerbedingung ermittelt.
         System.out.println("SystemException in User Transaction:" + se.getMessage());
         throw new EJBException("Transaction failure: " + se.getMessage());
      } 
      catch (Exception e) {
         //Alle generischen oder unerwarteten Ausnahmen bearbeiten
         System.out.println("Exception in User Transaction: " + e.getMessage());
         throw new EJBException("Transaction failure: " + e.getMessage());		 		 
      }
   } 
   while (error);
   return employeeList;
}
/**
 * Kommentar zur Methode getSessionContext
 * @return javax.ejb.SessionContext
 */
public javax.ejb.SessionContext getSessionContext() {
		 		 return mySessionCtx;
}

//************************************************************************************
//* Die Methode getDS führt den JNDI-Lookup für die DataSource durch.         *
//* Diese Methode wird über ejbActivate und getEmployees aufgerufen, wenn     *
//* kein DataSource-Objekt angegeben ist.		 		 		 		 		 		 		 		 		
//************************************************************************************
private void getDS() {
   try  {    
      Hashtable parms = new Hashtable();
parms.put(Context.INITIAL_CONTEXT_FACTORY, 
         com.ibm.websphere.naming.WsnInitialContextFactory);
      InitialContext ctx = new InitialContext(parms);

      		 		 // Namensservice-Lookup zum Abrufen des DataSource-Objekts durchführen.
      		 		 ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
      //UserTransaction-Objekt erstellen
      userTran = mySessionCtx.getUserTransaction();
   } 
   catch (Exception e) {
      System.out.println("Naming service exception: " + e.getMessage());
      e.printStackTrace();
}
}
/**
 * Methode setSessionContext
 * @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;

/**
 * Dies ist eine Home-Schnittstelle für die Session-Bean
 */
public interface ShowEmployeesBMTHome extends javax.ejb.EJBHome {

/**
 * Methode create für eine 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;

/**
 * Dies ist ein ferne EJB-Schnittstelle
 */
public interface ShowEmployeesBMT extends javax.ejb.EJBObject {

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

Beispiel: Behandlung von Verbindungsausnahmen für BMP-Beans in containergesteuerten Datenbanktransaktionen

Das folgende Codebeispiel zeigt, wie im Fall von Ausnahmen wegen veralteter Verbindungen Transaktionen rückgängig gemacht und Ausnahmen an den Bean-Client ausgegeben werden.

//===================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;

/**
 * Dies ist eine Entity-Bean-Klasse mit BMP-Feldern
 * 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;
/**
 * Methode ejbActivate 
 * ejbActivate ruft die Methode getDS() auf, die das
 * JNDI-Lookup für die Datenquelle durchführt.
 */
public void ejbActivate() {
       getDS();
}
/**
 * Methode ejbCreate für eine 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))
      {
         // Diese Ausnahme zeigt an, dass die Verbindung zur Datenbank nicht mehr gültig ist.
         // Die Transaktion zurücksetzen und eine Ausnahme an den Client absetzen, die anzeigt,
// dass die Transaktion gegebenenfalls wiederholt werden kann.

         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
   {
      // Die Verbindung in einer finally-Anweisung immer schließen, um 
      // in allen Fällen ein ordnungsgemäßes Schließen zu gewährleisten. 
      // Durch das Schließen der Verbindung wird die aktuelle Verbindung
      // nicht tatsächlich geschlossen, sondern zur Wiederverwendung in
     // Pool zurückgegeben.
      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);
}
/**
 * Methode ejbFindByPrimaryKey
 * @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;
}
/**
 * Methode ejbLoad
 */
public void ejbLoad() {
       try  {    
              EmployeeBMPKey pk = (EmployeeBMPKey) entityContext.getPrimaryKey();
              loadByEmpNo(pk.empNo);
       } catch (FinderException fe) {
              throw new EJBException("Cannot load Employee state from database.");
       }       
}
/**
 * Methode ejbPassivate
 */
public void ejbPassivate() {}
/**
 * Methode ejbPostCreate für eine 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))
      {
         // Diese Ausnahme zeigt an, dass die Verbindung zur Datenbank nicht mehr gültig ist.
         // Die Transaktion zurücksetzen und eine Ausnahme an den Client absetzen, die anzeigt,
// dass die Transaktion gegebenenfalls wiederholt werden kann.

         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
   {
      // Die Verbindung in einer finally-Anweisung immer schließen, um 
      // in allen Fällen ein ordnungsgemäßes Schließen zu gewährleisten. 
      // Durch das Schließen der Verbindung wird die aktuelle Verbindung
      // nicht tatsächlich geschlossen, sondern zur Wiederverwendung in
     // Pool zurückgegeben.
      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());
         }
      }
   }
}
/**
 * edLevel des Angestellten abrufen
 * Build-Datum: (20.04.2001 15:46:22)
 * @return int
 */
public int getEdLevel() {
       	return edLevel;
}
/**
 * Methode getEntityContext
 * @return javax.ejb.EntityContext
 */
public javax.ejb.EntityContext getEntityContext() {
       return entityContext;
}
/**
 * Vornamen des Angestellten abrufen
 * Build-Datum: (19.04.2001 13:34:47)
 * @return java.lang.String
 */
public java.lang.String getFirstName() {
       return firstName;
}
/**
 * Familiennamen des Angestellten abrufen
 * Build-Datum: (19.04.2001 13:35:41)
 * @return java.lang.String
 */
public java.lang.String getLastName() {
       return lastName;
}
/**
 * Zweiten Vornamen des Angestellten abrufen
 * Build-Datum: (19.04.2001 13:36:15)
 * @return char
 */
public String getMiddleInit() {
       return middleInit;
}
/**
 * JNDI-Lookup für DataSource durchführen
 * Build-Datum: (19.04.2001 15:28:15)
 */
private void getDS() {
       try  {    
              Hashtable parms = new Hashtable();
              parms.put(Context.INITIAL_CONTEXT_FACTORY, 
                            com.ibm.websphere.naming.WsnInitialContextFactory);
              InitialContext ctx = new InitialContext(parms);
              		 		 // Namensservice-Lookup zum Abrufen des DataSource-Objekts durchführen.
              		 		 ds = (DataSource)ctx.lookup("java:comp/env/jdbc/SampleDB");
       } 
       catch (Exception e) {
              System.out.println("Naming service exception: " + e.getMessage());
              e.printStackTrace();
       }
}
/**
 * Daten zum Angestellten aus der Datenbank laden
 * Build-Datum: (19.04.2001 15:44:07)
 * @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 
       {
                // Verbindungsobjekt conn wird mit der DataSource-Factory abrufen.
              conn = ds.getConnection();
              // DB-Abfrage mit JDBC-Standardcodierung durchführen.
              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))
         {
           // Diese Ausnahme zeigt an, dass die Verbindung zur Datenbank nicht mehr gültig ist.
           // Die Transaktion zurücksetzen und eine Ausnahme an den Client absetzen, die anzeigt,
       // dass die Transaktion gegebenenfalls wiederholt werden kann.

           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
       {
         // Die Verbindung immer in einer finally-Anweisung schließen, um
              // sicherzustellen, dass sie in allen Fällen ordnungsgemäß
              // geschlossen wird. Durch das Schließen der Verbindung wird die
              // Verbindung nicht tatsächlich geschlossen, sondern zur
              // Wiederverwendung an den Pool zurückgegeben.
         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());
            }
         }
       }      
}
/**
 * Schulabschluss des Angestellten angeben
 * Build-Datum: (20.04.2001 15:46:22)
 * @param newEdLevel int
 */
public void setEdLevel(int newEdLevel) {
       	edLevel = newEdLevel;
}
/**
 * Methode setEntityContext
 * @param ctx javax.ejb.EntityContext
 */
public void setEntityContext(javax.ejb.EntityContext ctx) {
       entityContext = ctx;
}
/**
 * Vornamen des Angestellten angeben
 * Build-Datum: (19.04.2001 13:34:47)
 * @param newFirstName java.lang.String
 */
public void setFirstName(java.lang.String newFirstName) {
       	firstName = newFirstName;
}
/**
 * Familiennamen des Angestellten angeben
 * Build-Datum: (19.04.2001 13:35:41)
 * @param newLastName java.lang.String
 */
public void setLastName(java.lang.String newLastName) {
       	lastName = newLastName;
}
/**
 * Zweiten Vornamen des Angestellten angeben
 * Build-Datum: (19.04.2001 13:36:15)
 * @param newMiddleInit char
 */
public void setMiddleInit(String newMiddleInit) {
       	middleInit = newMiddleInit;
}
/**
 * Methode unsetEntityContext
 */
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;

/**
 * Dies ist ein ferne EJB-Schnittstelle
 */
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;

/**
 * Dies ist ein ferne EJB-Schnittstelle
 */
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;

/**
* Dies ist eine Primärschlüsselklasse für die Entity-Bean
**/
public class EmployeeBMPKey implements java.io.Serializable { 
		 	public String empNo;
		    final static long serialVersionUID = 3206093459760846163L;

/**
* Konstruktor EmployeeBMPKey() 
*/
public EmployeeBMPKey()  {
}
/**
* Konstruktor EmployeeBMPKey(String key) 
*/
public EmployeeBMPKey(String key)  {
		 	empNo = key;
}
/**
* Methode equals
*   Benutzer muss eine passende Implementierung für die Methode equal bereitstellen. Die 
*   generierte Methode geht davon aus, dass der Schlüssel ein Zeichenfolgeobjekt ist.
*/
public boolean equals (Object o)  {
		 	if (o instanceof EmployeeBMPKey) 
		 		 		return empNo.equals(((EmployeeBMPKey)o).empNo);
		 else
		 		 return false;
}
/**
* Methode hashCode
*   Benutzer muss eine passende Implementierung für die Methode hashCode bereitstellen. Die
*   generierte Methode geht davon aus, dass der Schlüssel ein Zeichenfolgeobjekt ist.
*/
public int hashCode ()  {
		 		 return empNo.hashCode();

Beispiel: Behandlung von Ausnahmen beim Datenzugriff - ConnectionWaitTimeoutException (für die JDBC-API)

Dieses Codebeispiel zeigt, wie die Bedingungen festgelegt werden, unter denen der Anwendungsserver die Ausnahme ConnectionWaitTimeoutException für eine JDBC-Anwendung auslöst.

Wenn die Ausnahme "ConnectionWaitTimeoutException" abgefangen wird, gibt es wenig Chancen für eine Wiederherstellung.

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

		 		 try  {    
		 		 		 			// Datenquelle suchen
		 		 		 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);

		 		 		 			// Verbindung abrufen.
		 		 		 		 		 		 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)
					{
		 		 		 			//Den Benutzer benachrichtigen, dass das System keine Verbindung 
		 		 		 		 		 		 //zur Datenbank hertellen konnte.  Dies ist meist der Fall, wenn der 
		 		 		 			//Verbindungspool voll ist und keine Verbindung für gemeinsame 
		 		 		 		 		 		 //Benutzung vorhanden ist.
		 			}
					else
					{
		 		 		 // Andere Datenbankfehler beheben.
					}
		 		 }
		 		 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) {
}
		 		 }
		 }

Beispiel: Behandlung von Ausnahmen beim Datenzugriff - ConnectionWaitTimeoutException für Java EE Connector Architecture

Dieses Codebeispiel zeigt, wie die Bedingungen festgelegt werden, unter denen WebSphere Application die Ausnahme ConnectionWaitTimeout für eine JCA-Anwendung auslöst.

In allen Fällen, in denen die Ausnahme ConnectionWaitTimeout abgefangen wird, gibt es praktisch keine Möglichkeit der Fehlerbehebung.

Das folgende Codefragment veranschaulicht, wie diese Ausnahme in Java Platform, Enterprise Edition (Java EE) Connector Architecture (JCA) verwendet wird:

/**
 * Diese Methode führt einen einfachen Verbindungstest durch. 
 */
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  {    
      // Die Verbindungsfactory abrufen
      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) {
      // Die Verbindungsfactory kann nicht abgerufen werden.
      throw ne;
   }
    // Verbindung abrufen
      if (verbose) System.out.println("Get the connection...");
      conn = factory.getConnection();
      // Verbindungsdaten der Verbindung abrufen
      metaData = conn.getMetaData();
      // Informationen zu Metadaten ausgeben.
      System.out.println("EISProductName" is + metaData.getEISProductName());
   }
   catch (com.ibm.websphere.ce.j2c.ConnectionWaitTimeoutException cwtoe) {
      // Wartezeit für Verbindung
      throw cwtoe;
   }
   catch (javax.resource.ResourceException re) {
      // Fehler in Verbindungen.
      throw re;
   }
   finally {
      if (conn != null) {
         try  {    
            conn.close();          }
         catch (javax.resource.ResourceException re) {
         }
      }
   }
}

Beispiel: Behandlung von Ausnahmen beim Datenzugriff - Fehlerzuordnung in DataStoreHelper

Der Anwendungsserver stellt eine DataStoreHelper-Schnittstelle für die Zuordnung unterschiedlicher SQL-Datenbankfehlercodes zu den entsprechenden Ausnahmen im Anwendungsserver bereit.

Die Fehlerzuordnung ist erforderlich, weil unterschiedliche Datenbankanbieter unterschiedliche SQL-Fehler und -Codes verwenden können, um dasselbe Problem darzustellen. Beispielsweise hat die Ausnahme wegen veralteter Verbindung in den verschiedenen Datenbanken unterschiedliche Codes. Die DB2-SQL-Codes 1015, 1034, 1036 usw. zeigen an, dass die Verbindung aufgrund eines temporären Datenbankproblems nicht mehr verfügbar ist. Die Oracle-SQL-Codes 28, 3113, 3114 usw. zeigen dieselbe Situation an.

Durch Zuordnung dieser Fehlercodes zu Standardausnahmen wird die Konsistenz erreicht, die erforderlich ist, damit Anwendungen in den unterschiedlichen Installationen des Anwendungsservers portierbar sind. Das folgende Codesegment veranschaulicht, wie zwei Fehlercodes der Fehlermaske zugeordnet werden:
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);
    ...
  }
}

Eine Konfigurationsoption mit dem Namen "Fehlererkennungsmodell" steuert, wie die Fehlerzuordnung eingesetzt wird. Bis zur Version 6 war die Ausnahmezuordnung die einzige verfügbare Option für das Fehlererkennungsmodell. Ab Version 7 wird eine weitere Option mit dem Namen "Ausnahmeprüfung" bereitgestellt. Unter dem Modell "Ausnahmezuordnung" verwendet der Anwendungsserver die Fehlerzuordnung und ersetzt Ausnahmen durch den entsprechenden, in der Fehlerzuordnung aufgelisteten Ausnahmetyp. Unter dem Modell "Ausnahmeprüfung" verwendet der Anwendungsserver weiterhin die Fehlerzuordnung für seine eigenen Zwecke, ersetzt aber keine Ausnahmen. Wenn Sie das Modell "Ausnahmezuordnung" weiterhin verwenden möchten, müssen Sie nichts ändern. Die Ausnahmezuordnung ist das Standardfehlererkennungsmodell. Wenn Sie das Modell "Ausnahmeprüfung" verwenden möchten, lesen Sie den Artikel "Fehlererkennungsmodell auf das Modell "Ausnahmeprüfung" umstellen" unter "Zugehörige Links".

Datenbank-Deadlocks und Konflikte bei Fremdschlüsseln

Die Wiederholung bestimmter SQL-Fehlernachrichten zeigen Probleme an, z. B. Verletzungen der referenziellen Integrität der Datenbank, die Sie vermeiden können, indem Sie das Feature für CMP-Sequenzgruppierung verwenden.

Ausnahmen durch Fremdschlüsselkonflikte, die aufgrund von Verletzungen der referenziellen Integrität der Datenbank auftreten

Eine Datenbankrichtlinie für referenzielle Integrität (RI) gibt Regeln für das Schreiben von Daten in die Datenbanktabellen und das Löschen von Daten aus den Datenbanktabellen vor, um die relationale Konsistenz zu gewährleisten. Die Laufzeitanforderungen für die Verwaltung der Bean-Persistenz können jedoch dazu führen, dass eine EJB-Anwendung gegen RI-Regeln verstößt, woraufhin möglicherweise Datenbankausnahmen ausgelöst werden.

Ihre EJB-Anwendung verletzt die referenzielle Integrität der Datenbank, wenn in Ihrer Tracedatei oder Protokolldatei von WebSphere Application Server eine Ausnahme erscheint, die mit den folgenden (in einer Umgebung mit DB2 erzeugten) Nachrichten vergleichbar sind:
The insert or update value of the FOREIGN KEY table1.name_of_foreign_key_constraint
is not equal to any value of the parent key of the parent table.
oder
A parent row cannot be deleted because the relationship table1.name_of_foreign_key_constraint
is not equal to any value of the parent key of the parent table.

Wenn Sie die Reihenfolge festlegen, in der Entity-Beans relationale Datenbanktabellen aktualisieren, indem Sie Bean-Sequenzen definieren, können Sie derartige Ausnahmen vermeiden.

Ausnahmen durch gegenseitige Sperren bei optimistischer Parallelitätssteuerung

Auch hier können Sequenzen Ausnahmen für Entity-Beans mit optimistischer Parallelitätssteuerung, die mit einer Zurücksetzung von Transaktionen verbunden sind, auf ein Minimum reduziert werden. Die optimistische Parallelitätssteuerung gibt vor, dass Datenbanksperren nur für eine Mindestzeit gehalten werden, damit eine möglichst große Anzahl von Transaktionen kontinuierlich Zugriff auf die Daten haben. Bei einer Datenbank mit so hoher Verfügbarkeit können parallele Transaktionen versuchen, dieselbe Tabellenzeile zu sperren, und so eine gegenseitige Sperre bewirken. Die dadurch ausgelösten Ausnahmen können Nachrichten wie die folgende generieren (die in einer Umgebung mit DB2 erzeugt wurde):

Unsuccessful execution caused by deadlock or timeout.

Nutzen Sie das Sequenzfeature, um die Bean-Persistenz so zu organisieren, dass die Wahrscheinlichkeit von gegenseitigen Datenbanksperren sinkt.


Symbol, das den Typ des Artikels anzeigt. Konzeptartikel



Symbol für Zeitmarke Letzte Aktualisierung: 25.05.2016
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=cdat_daexcp
Dateiname:cdat_daexcp.html