데이터 액세스 API에 대한 확장기능

단일 데이터 액세스 API가 사용자 애플리케이션의 전체 솔루션을 제공하지 않는 경우, WebSphere® Application Server 확장기능을 사용하여 JCA 및 JDBC API 간 상호 운용성을 얻습니다.

다양한 복합 관리 구성으로 그려진 애플리케이션은 Java™ EE(Java Platform, Enterprise Edition) Connector Architecture(JCA) API 및 JDBC(Java Database Connectivity) API 모두를 사용해야 할 수 있습니다. 그러나 일부 경우 JDBC 프로그래밍 모델은 JCA와 전체적으로 통합되지 않습니다(전체 통합이 JCA 스펙의 기반이더라도). 이 불일치는 두 API를 사용하는 애플리케이션에 대한 데이터 액세스 옵션을 제한할 수 있습니다. WebSphere Application Server는 API 확장기능을 제공하여 호환성 문제를 해결합니다.

예를 들어 다음과 같습니다.

확장기능의 장점이 없이 기타 핸들이 해당 연결에 존재하는 경우, 두 API를 사용하는 애플리케이션은 연결 요청을 작성한 후 공유 가능한 연결의 특성을 수정할 수 없습니다. (연결과 연관된 핸들이 없는 경우 연결 특성을 변경할 수 있습니다.) 이 제한사항은 API의 연결 구성 정책 간 비호환성에서 생깁니다.

커넥터 아키텍처(JCA) 스펙은 ConnectionSpec 오브젝트에서 전달하여 연결을 요청하는 경우에(getConnection() 메소드 사용) 자원 어댑터 특정 특성 설정에 전달을 지원합니다. ConnectionSpec 오브젝트는 연결하는 데 사용된 필요한 연결 특성을 포함합니다. 이 환경에서 연결을 얻은 후, 애플리케이션은 특성을 변경하지 않아도 됩니다. JDBC 프로그래밍 모델은 연결 특성을 지정하는 동일한 인터페이스가 없습니다. 대신, 먼저 연결한 다음 연결에 대한 특성을 설정합니다.

WebSphere Application Server는 JDBC 및 JCA 스펙 간의 이러한 차이를 채우도록 다음 확장기능을 제공합니다.

예: 데이터베이스 연결을 위한 IBM 확장 API 사용.

WSDataSource 확장 API를 사용하면, JDBC 애플리케이션을 코딩하여 연결을 얻기 전에 오브젝트를 통한 연결 특성을 정의할 수 있습니다. 이 동작은 애플리케이션이 CMP와 같이 다른 컴포넌트와 연결을 공유할 수 있는 가능성을 늘립니다.

사용자 애플리케이션이 트랜잭션 내 다른 CMP(Container-Managed Persistence) Bean과 공유될 수 있는 공유 가능한 연결로 실행하는 경우, WebSphere Application Server 확장 API를 사용하여 연결하는 것이 좋습니다. 이 API를 사용하면, 애플리케이션을 다른 애플리케이션 서버로 포트할 수 없습니다.

JDBC 애플리케이션에서 직접 확장 API로 코딩할 수 있습니다. 연결하기 위해 DataSource 인터페이스를 사용하는 대신 WSDataSource 인터페이스를 사용합니다. 다음 코드 세그먼트는 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 오브젝트를 통해 데이터에 액세스하는 애플리케이션 컴포넌트 내에서(BMP(Bean-Managed Persistence) Bean), WebSphere 확장 API를 사용하여 연결을 얻기 전에 오브젝트를 통해 연결 특성을 정의할 수 있습니다. 이 동작으로 BMP Bean은 CMP(Container-Managed Persistence) Bean으로 연결을 공유할 수 있는 가능성이 늘어납니다.

BMP Bean이 트랜잭션 내 다른 CMP(Container-Managed Persistence) Bean과 공유될 수 있는 공유 가능한 연결로 실행하는 경우, WebSphere Application Server 확장 API를 사용하여 연결하는 것이 좋습니다. 이 API를 사용하면, 애플리케이션을 다른 애플리케이션 서버로 포트할 수 없습니다.

이 경우, DataSource 인터페이스가 아닌 확장 API WSDataSource 인터페이스를 사용합니다. CMP 및 BMP(Bean-Managed Persistence) 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