数据访问 API 的扩展

如果单个数据访问 API 未提供应用程序的完整解决方案,那么使用 WebSphere® Application Server 扩展来实现 JCA 与 JDBC API 之间的互操作性。

这些应用程序提取自多种复合的资源管理配置,它们可能需要使用 Java™ 平台企业修订版 (Java EE) 连接器体系结构 (JCA) API 和 Java 数据库连接 (JDBC) API。但是,在某些情况下,JDBC 编程模型不会与 JCA 完全集成(即使完全集成是 JCA 规范的基础)。这些矛盾可以限制使用这两个 API 的应用程序的数据访问选项。WebSphere Application Server 提供 API 扩展来解决兼容性问题。

例如:

如果对于可共享连接有其他句柄存在,那么在没有扩展的优势的情况下使用这两个 API 的应用程序,在进行连接请求后无法修改此连接的属性。(如果没有与此连接相关的其他句柄,那么可以更改连接属性。)此限制是由 API 的连接配置策略间的不兼容性引起的。

在您通过传递 ConnectionSpec 对象(使用 getConnection() 方法)请求连接时,连接器体系结构 (JCA) 规范支持为资源适配器重新进行特定属性设置。ConnectionSpec 对象包含用于获取连接所必需的连接属性。 在您从此环境中获取连接后,您的应用程序无需更改这些属性。然而,JDBC 编程模型没有用于指定连接属性的同一接口。而是它首先获取连接,然后设置连接的属性。

WebSphere Application Server 提供以下扩展来弥补 JDBC 和 JCA 规范间的此类差异:

示例:将 IBM 扩展 API 用于数据库连接

在获取连接之前,可以使用 WSDataSource 扩展 API 来编码 JDBC 应用程序,以通过对象定义连接属性。此行为增加了应用程序可以与另一个组件(如 CMP)共享连接的机会。

如果应用程序与可共享连接(可能与事务中其他容器管理的持久性 (CMP) bean 共享)一起运行,那么建议您使用 WebSphere Application Server 扩展 API 来获取连接。 当使用这些 API 时,您无法将您的应用程序迁移至其他应用程序服务器。

可以使用扩展 API 直接在 JDBC 应用程序中进行编码;请使用 WSDataSource 接口来获取连接,而不是使用 DataSource 接口。以下代码段说明了 WSDataSource:

import com.ibm.websphere.rsadapter.*;
... 
// Create a JDBCConnectionSpec and set connection properties. If this connection
// is shared with the CMP bean, make sure that the isolation level is the same as
// the isolation level that is mapped by the Access Intent defined on the CMP bean. 

JDBCConnectionSpec connSpec = WSRRAFactory.createJDBCConnectionSpec(); 
connSpec.setTransactionIsolation(CONNECTION.TRANSACTION_REPEATABLE_READ); 
connSpec.setCatalog("DEPT407");

// Use WSDataSource to get the connection 
Connection conn = ((WSDataSource)datasource).getConnection(connSpec);

示例:使用 IBM 扩展 API 在 CMP bean 与 BMP bean 之间共享连接

获取连接之前,在通过 JDBC 对象(如 bean 管理的持久性 (BMP) Bean)访问数据的应用程序组件中,可以使用 WebSphere 扩展 API 来通过对象定义连接属性。此行为增加了 BMP bean 可以与容器管理的持久性 (CMP) bean 共享连接的机会。

如果 BMP bean 与可共享连接(可能与事务中其他容器管理的持久性 (CMP) bean 共享)一起运行,那么建议您使用 WebSphere Application Server 扩展 API 来获取连接。 当使用这些 API 时,您无法将您的应用程序迁移至其他应用程序服务器。

在这种情况下,请使用扩展的 API WSDataSource 接口,而不是 DataSource 接口。要确保 CMP 和 bean 管理的持久性 (BMP) bean 共享同一物理连接,请在 CMP 和 BMP bean 上定义相同的访问意向概要文件。在 BMP 方法中,您可以从关系资源适配器辅助类中获取正确的隔离级别。

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

指示主题类型的图标 参考主题



时间戳记图标 最近一次更新时间: last_date
http://www14.software.ibm.com/webapp/wsbroker/redirect?version=cord&product=was-nd-mp&topic=rdat_cextiapi
文件名:rdat_cextiapi.html