JDBC オブジェクト (Bean 管理パーシスタンス (BMP) Bean) を 介してデータにアクセスするアプリケーション・コンポーネント内で、接続を取得する前に、WebSphere 拡張 API を使用し、オブジ ェクトを介して接続プロパティーを定義することができます。この性質により、BMP Bean が コンテナー 管理パーシスタンス (CMP) Bean と接続を共用する可能性が高まります。
トランザクション内の他のコンテナー管理パーシスタンス (CMP) Bean と 共用できる共用可能接続を用いて、BMP Bean を実行する場合、WebSphere Application Server 拡張 API を使用して接続を取得するように お勧めします。 この API を使用すると、 アプリケーションを他のアプリケーション・サーバーに移植できません。
この場合、DataSource インターフェースではなく、拡張 API WSDataSource インターフェースを使用してください。CMP Bean と Bean 管理パーシスタンス (BMP) Bean の両方が同じ物理接続を必ず共用するために、両者において 同じアクセス・インテント・プロファイルを定義してください。BMP メソッド内部で、 リレーショナル・リソース・アダプターの helper クラスから、適切な分離レベルを取得できます。
package fvt.example; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javax.ejb.CreateException; import javax.ejb.DuplicateKeyException; import javax.ejb.EJBException; import javax.ejb.ObjectNotFoundException; import javax.sql.DataSource; // following imports are used by the IBM extended API import com.ibm.websphere.appprofile.accessintent.AccessIntent; import com.ibm.websphere.appprofile.accessintent.AccessIntentService; import com.ibm.websphere.rsadapter.JDBCConnectionSpec; import com.ibm.websphere.rsadapter.WSCallHelper; import com.ibm.websphere.rsadapter.WSDataSource; import com.ibm.websphere.rsadapter.WSRRAFactory; /** * Bean implementation class for Enterprise Bean: Simple */ public class SimpleBean implements javax.ejb.EntityBean { private javax.ejb.EntityContext myEntityCtx; // Initial context used for lookup. private javax.naming.InitialContext ic = null; // define a JDBCConnectionSpec as instance variable private JDBCConnectionSpec connSpec; // define an AccessIntentService which is used to get // an AccessIntent object. private AccessIntentService aiService; // AccessIntent object used to get Isolation level private AccessIntent intent = null; // Persitence table name private String tableName = "cmtest"; // DataSource JNDI name private String dsName = "java:comp/env/jdbc/SimpleDS"; // DataSource private DataSource ds = null; // bean instance variables. private int id; private String name; /** * In setEntityContext method, you need to get the AccessIntentService * object in order for the subsequent methods to get the AccessIntent * object. * Other ejb methods will call the private getConnection() to get the * connection which has all specific connection properties */ public void setEntityContext(javax.ejb.EntityContext ctx) { myEntityCtx = ctx; try { aiService = (AccessIntentService) getInitialContext().lookup( "java:comp/websphere/AppProfile/AccessIntentService"); ds = (DataSource) getInitialContext().lookup(dsName); } catch (javax.naming.NamingException ne) { throw new javax.ejb.EJBException( "Naming exception: " + ne.getMessage()); } } /** * ejbCreate */ public fvt.example.SimpleKey ejbCreate(int newID) throws javax.ejb.CreateException, javax.ejb.EJBException { Connection conn = null; PreparedStatement ps = null; // Insert SQL String String sql = "INSERT INTO " + tableName + " (id, name) VALUES (?, ?)"; id = newID; name = ""; try { // call the common method to get the specific connection conn = getConnection(); } catch (java.sql.SQLException sqle) { throw new EJBException("SQLException caught: " + sqle.getMessage()); } catch (javax.resource.ResourceException re) { throw new EJBException( "ResourceException caught: " + re.getMessage()); } try { ps = conn.prepareStatement(sql); ps.setInt(1, id); ps.setString(2, name); if (ps.executeUpdate() != 1){ throw new CreateException("Failed to add a row to the DB"); } } catch (DuplicateKeyException dke) { throw new javax.ejb.DuplicateKeyException( id + "has already existed"); } catch (SQLException sqle) { throw new javax.ejb.CreateException(sqle.getMessage()); } catch (CreateException ce) { throw ce; } finally { if (ps != null) { try { ps.close(); } catch (Exception e) { } } } return new SimpleKey(id); } /** * ejbLoad */ public void ejbLoad() throws javax.ejb.EJBException { Connection conn = null; PreparedStatement ps = null; ResultSet rs = null; String loadSQL = null; try { // call the common method to get the specific connection conn = getConnection(); } catch (java.sql.SQLException sqle) { throw new EJBException("SQLException caught: " + sqle.getMessage()); } catch (javax.resource.ResourceException re) { throw new EJBException( "ResourceException caught: " + re.getMessage()); } // You need to determine which select statement to be used based on the // AccessIntent type: // If READ, then uses a normal SELECT statement. Otherwise uses a // SELECT...FORUPDATE statement // If your backend is SQLServer, then you can use different syntax for // the FOR UPDATE clause. if (intent.getAccessType() == AccessIntent.ACCESS_TYPE_READ) { loadSQL = "SELECT * FROM " + tableName + " WHERE id = ?"; } else { loadSQL = "SELECT * FROM " + tableName + " WHERE id = ? FOR UPDATE"; } SimpleKey key = (SimpleKey) getEntityContext().getPrimaryKey(); try { ps = conn.prepareStatement(loadSQL); ps.setInt(1, key.id); rs = ps.executeQuery(); if (rs.next()) { id = rs.getInt(1); name = rs.getString(2); } else { throw new EJBException("Cannot load id = " + key.id); } } catch (SQLException sqle) { throw new EJBException(sqle.getMessage()); } finally { try { if (rs != null) rs.close(); } catch (Exception e) { } try { if (ps != null) ps.close(); } catch (Exception e) { } try { if (conn != null) conn.close(); } catch (Exception e) { } } } /** * This method will use the AccessIntentService to get the access intent; * then gets the isolation level from the DataStoreHelper * and sets it in the connection spec; then uses this connection * spec to get a connection which has the specific connection * properties. **/ private Connection getConnection() throws java.sql.SQLException, javax.resource.ResourceException, EJBException { // get current access intent object using EJB context intent = aiService.getAccessIntent(myEntityCtx); // Assume this bean only supports the pessimistic concurrency if (intent.getConcurrencyControl() != AccessIntent.CONCURRENCY_CONTROL_PESSIMISTIC) { throw new EJBException("Bean supports only pessimistic concurrency"); } // determine correct isolation level for currently configured database // using DataStoreHelper int isoLevel = WSCallHelper.getDataStoreHelper(ds).getIsolationLevel(intent); connSpec = WSRRAFactory.createJDBCConnectionSpec(); connSpec.setTransactionIsolation(isoLevel); // Get connection using connection spec Connection conn = ((WSDataSource) ds).getConnection(connSpec); return conn; }