`
yingfang05
  • 浏览: 122980 次
  • 性别: Icon_minigender_1
  • 来自: 重庆
社区版块
存档分类
最新评论

EJB3中会话的持久上下文

    博客分类:
  • ejb3
阅读更多
参与到事务中的实体管理就像其它资源一样.我们在这本书中可以看到例子.扩展的持久化上下文有很多有趣的事务行为你可以使用.允许你调用EntityManager的操作,像persist( ), merge( ), 和remove( )在一个事务外当你与一个扩展的持久化上下文交互时.那些插入,更新,和删除排队直到扩展持久化上下文支持一个活动的事务和提交.换句话来讲,数据库不被涉及直到持久化上下文变成关联一个事务时.同时,任何被运行的查询不被保存到数据库中连接在他们完成之后.让我们看这样的一个例子.
1 EntityManager manager =           entityManagerFactory.createEntityManager(EXTENDED);
2 manager.persist(newCabin);
3 manager.merge(someCustomer);
4 manager.remove(someReservation);
5
6 userTransaction.begin( );
7 manager.flush( );
8 userTransaction.commit( );
第一行创建一个扩展的持久化上下文.第2-4行创建,更新,和删除一些实体.这些动作排队直到持久化上下文变成支持一个事务在第6行.调用一个EntityManager方法的行为在一个事务的持久化上下文内.批量动作的提交在第7行.

你可以真正的开发这种行为通过使用有状态会话Bean.前面,我们显示的创建两个reservations 通过TRavelAgentBean的例子:
TravelAgent tr1 = (TravelAgent)getInitialContext( ).lookup("TravelAgentRemote");
tr1.setCruiseID(cruiseID);
tr1.setCabinID(cabin_1);
tr1.setCustomer(customer0);
TravelAgent tr2 = (TravelAgent)getInitialContext( ).lookup("TravelAgentRemote");;
tr2.setCruiseID(cruiseID);
tr2.setCabinID(cabin_2);
tr2.setCustomer(customer);

javax.transaction.UserTransaction tran = ...; // Get the UserTransaction.
tran.begin( );
tr1.bookPassage(visaCard,price);
tr2.bookPassage(visaCard,price);
tran.commit( );
这个想法是我们有一个客户想要创建多个预定为他的家人.这些多个预定将会参加到一个事务中,由客户端初始化.这实际上是一个非常差的系统设计,因为你有一个事务跨路多个远程调用.远程客户,通常,不可靠的实体,尤其是被人操作的客户端.数据库更新锁保持远程 bookPassage( ) 调用和数据库的连接是打开的.如果是人工的旅行代理决定去吃午餐在事务执行期间,这些资源和连接将会被保持直到事务超时.为了解决这个问题,我们可以使用查询非事务行为的实体管理操作.让我们编写TravelAgentBean 的例子:
import javax.ejb.*;
import javax.persistence.*;
import static javax.persistence.PersistenceContextType.*;
import static javax.ejb.TransactionAttributeType.*;

@Stateful
@TransactionAttribute(NOT_SUPPORTED)
public class TravelAgentBean implements TravelAgentRemote {

   @PersistenceContext(unitName="titan", EXTENDED)
   private EntityManager entityManager;

   @EJB ProcessPaymentLocal processPayment;

   private Customer customer;
   private Cruise cruise;
   private Cabin cabin;

   public Customer findOrCreateCustomer(String first, String last) {
     ...
   }

   public void setCabinID(int id) {
     ...
   }

   public void setCruiseID(int id) {
     ...
   }

   public TicketDO bookPassage(CreditCardDO card, double price)
      throws IncompleteConversationalState {

     if (customer == null || cruise == null || cabin == null) {
        throw new IncompleteConversationalState( );
     }
      try {
          Query getCruiseCabin = entityManager.createQuery(
                "SELECT cc FROM CruiseCabin cc WHERE" +
                "cc.cabin = :cabin AND cc.cruise = :cruise");
          getCruiseCabin.setParameter("cabin", cabin);
          getCruiseCabin.setParameter("cruise", cruise);
          CruiseCabin cc = (CruiseCabin)getCruiseCabin.getSingleResult( );

          if (cc.getIsReserved( ))
              throw new EJBException ("Cabin is already reserved");
          cc.setIsReserved(true);

          Reservation reservation = new Reservation(
              customer, cruise, cabin, price);
          entityManager.persist(reservation);

          this.process.byCredit(customer, card, price);

          TicketDO ticket = new TicketDO(customer,cruise,cabin,price);

          return ticket;
      } catch(Exception e) {
          throw new EJBException(e);
      }
   }

>   @TransactionAttribute
(REQUIRED)
>   @Remove

   public void checkout( ) {
      entityManager.flush( ); // really not necessary
   }
}
我们首先要做的是使每个非事务的业务方法通过 @TRansactionAttribute(NOT_SUPPORTED)注释在组件类上.下一步是,一个扩展的持久化上下文被注入到entityManager字段,所以我们可以同一个外在的事务交互.@Remove注释被移动从bookPassage()到一个新的checkout()方法,所以多个bookPassage()方法调用可以在相同的TravelAgent会话.因为bookPassage( )方法现在是非事务的,任何预定可以被这个方法创建,现在查询和无数据库资源被保存在它们的调用之间.预定被提交到数据库,当扩展的持久化上下文支持一个事务在checkout()方法内.

checkout( ) 方法的EntityManager.flush( )操作不是必需的;扩展的持久化上下文自动被支持当方法开始时.它是一个好的习惯,无论如何都要调用flush()方法,因为,它提醒开发者读取实际发生的代码.
最后的事情是修改ProcessPayment EJB.因为,ProcessPaymentBean使用原一的JDBC记录付款,这些付款没有向实体管理操作排队.为了促进这个,我们需要写另外一个实体组件代表一个付款和改变ProcessPayment EJB 使用一个实体管理,并非JDBC:
@Entity
public class Payment implements java.io.Serializable
{
   private int id;
   private Customer customer;
   private double amount;
   private String type;
   private String checkBarCode;
   private int checkNumber;
   private String creditCard;
   private Date creditCardExpiration;

   @Id @GeneratedValue
   public int getId( ) { return id; }
   public void setId(int id) { this.id = id; }

   @ManyToOne
   public Customer getCustomer( ) { return customer; }
   public void setCustomer(Customer cust) { this.customer = cust; }

   public double getAmount( ) { return amount; }
   public void setAmount(double amount) { this.amount = amount; }

   public String getType( ) { return type; }
   public void setType(String type) { this.type = type; }

   public String getCheckBarCode( ) { return checkBarCode; }
   public void setCheckBarCode(String checkBarCode)
{ this.checkBarCode = checkBarCode; }

   public int getCheckNumber( ) { return checkNumber; }
   public void setCheckNumber(int checkNumber) { this.checkNumber = checkNumber; }

   public String getCreditCard( ) { return creditCard; }
   public void setCreditCard(String creditCard) { this.creditCard = creditCard; }

   public Date getCreditCardExpiration( ) { return creditCardExpiration; }
   public void setCreditCardExpiration(Date creditCardExpiration) {
       this.creditCardExpiration = creditCardExpiration; }
}
这个实体代表在前面ProcessPayment EJB例子中使用的PAYMENT表.下一步,让我们编写ProcessPaymentBean 使用这个新实体:
package com.titan.processpayment;
import com.titan.domain.*;

import javax.ejb.*;
import javax.annotation.Resource;
import javax.persistence.*;
import static javax.ejb.TransactionAttributeType.*;
import static javax.persistence.PersistenceContextType.*;

@Stateful
@TransactionAttribute(SUPPORTS)
public class ProcessPaymentBean implements ProcessPaymentLocal
{
   final public static String CASH = "CASH";
   final public static String CREDIT = "CREDIT";
   final public static String CHECK = "CHECK";

   @PersistenceContext(unitName="titan", type=EXTENDED)
   private EntityManager entityManager;
   @Resource(name="min") int minCheckNumber = 100;

   public boolean byCash(Customer customer, double amount)
      throws PaymentException
   {
      return process(customer, amount, CASH, null, -1, null, null);
   }

   public boolean byCheck(Customer customer, CheckDO check, double amount)
      throws PaymentException
   {
      if (check.checkNumber > minCheckNumber)
      {
         return process(customer, amount, CHECK,
                        check.checkBarCode, check.checkNumber, null, null);
      }
      else
      {
         throw new PaymentException("Check number is too low. Must be at
least "+minCheckNumber);
      }
   }
   public boolean byCredit(Customer customer, CreditCardDO card,
                           double amount) throws PaymentException
{
      if (card.expiration.before(new java.util.Date( )))
      {
         throw new PaymentException("Expiration date has passed");
      }
     else
      {
         return process(customer, amount, CREDIT, null,
                        -1, card.number,
new java.sql.Date(card.expiration.getTime( )));
      }
   }
   private boolean process(Customer cust, double amount, String type,
                           String checkBarCode, int checkNumber, String creditNumber,
                           java.sql.Date creditExpDate) throws PaymentException
   {
      Payment payment = new Payment( );
      payment.setCustomer(cust);
      payment.setAmount(amount);
      payment.setType(type);
      payment.setCheckBarCode(checkBarCode);
      payment.setCheckNumber(checkNumber);
      payment.setCreditCard(creditNumber);
      payment.setCreditCardExpiration(creditExpDate);
      entityManager.persist(payment);
      return true;
   }
}
ProcessPaymentBean 类使用@transactionAttribute (SUPPORTS)注释,因为它可能或不执行在一个事务中.很容易改变process( ) 方法并且移除很多冗余的JDBC语法从原始的版本.我们必需有一些作做的事情,不合实际的事情在ProcessPayment EJB中强制这个例子工作.JAVA持久化规范不允许你传递一个扩展的持久化上下文到一个无状态会话Bean,当没有事务时.因此,ProcessPayment变成一个有状态会话Bean,有一个扩展的持久化上下文注入到其中.因为ProcessPayment是一个EJB被嵌入到travelAgentBean,他们共享相同的扩展持久化上下文.我们可以使用这一点绕开传递问题.

提供不理想的变化来使ProcessPayment 例子工作,我不建议使用扩展持久化上下文的查询特性如果你需要交互同其它的EJB.它是不幸的 EJB 3.0 专家的组无法修复明显的可用性问题,暴露在这一段中.因为专家组的一两个顽固成员无法决定解决这一问题,两个厂商决定修复这些问题在它们的实现中.
同travelAgentBean 和 ProcessPaymentBean 改变的完成,我们现在焦点放在重新实现的客户端:
TravelAgent tr1 = (TravelAgent)getInitialContext( ).lookup("TravelAgentRemote");
tr1.setCruiseID(cruiseID);
tr1.setCabinID(cabin_1);
tr1.setCustomer(customer0);
tr1.bookPassage(visaCard,price);

tr1.setCruiseID(cruiseID);
tr1.setCabinID(cabin_2);
tr1.setCustomer(customer);
tr1.bookPassage(visaCard,price);

tr1.checkout( );
比较客户端的代码从原始的例子中,这个代码已经变得非常单一化了.如你所看到的,我们管理很少的travelAgentBean中的因数和简单的客户端逻辑.我们解决了我们原始的使用多个bookPassage( )调用的情况.同时,我们管理使用数据库资源更有效并且仍代表一个工作单元.
分享到:
评论

相关推荐

    Jboss下开发ejb应用之一会话bean的应用

    会话Bean可以是无状态的或有状态的,无状态会话Bean通常用于处理一次性请求,而有状态会话Bean则保存了与客户端交互的上下文信息。 1. **无状态会话Bean**: - 无状态会话Bean不维护与客户端的特定关系,每次调用...

    EJB3 实例练习(一)

    在EJB3中,我们可以创建一个无状态会话bean,比如`SmsServiceBean`,用于处理短信发送的逻辑。这个bean可能包含一个`sendSms`方法,接收电话号码和短信内容作为参数。在实际应用中,`SmsServiceBean`会与数据库或...

    ejb3实例源代码

    无状态会话Bean适用于简单、无上下文的操作,而有状态会话Bean能维护客户端的会话状态。 3. **消息驱动Bean(Message-Driven Beans)**:处理JMS(Java Message Service)消息,常用于异步处理。 4. **注解驱动...

    EJB 会话BEAN PPT

    【EJB会话BEAN PPT】概览 EJB,全称Enterprise JavaBeans,是Sun Microsystems(现Oracle)提出的一种服务器端组件模型,主要用于构建分布式应用程序。它在Java平台上扮演着重要角色,类似于微软的.NET技术,但具有...

    实战EJB 实战EJB 实战EJB

    BMP (Bean Managed Persistence) 是另一种实体Bean的持久化方式,在EJB1.1规范中,BMP要求开发者自行管理实体Bean的持久化逻辑,而不是依赖容器。 **编写一个EJB1.1的BMP程序** 1. **定义接口**:包括`remote`和`...

    EJB3开发第一个无状态会话bean

    无状态会话 Bean 是 EJB 的一种类型,它为每个请求创建一个新的实例,不保留任何客户端的上下文信息。这使得它们非常适合执行计算密集型任务或事务操作,而不涉及持久化状态。 3. **EJB3 的简化** EJB3 相比于...

    EJB_JPA数据库持久层开发详解

    5. **持久化上下文(Persistence Context)**:管理实体的状态,保证了在一段时间内的对象一致性。 6. **JPQL(Java Persistence Query Language)**:面向对象的查询语言,类似于SQL,用于从数据库中检索和操作实体...

    ejb3 经典教程 中文 加 光盘 源代码 工程

    在学习EJB3的过程中,理解其核心概念如容器管理的持久性(CMP)、实体Bean的生命周期、会话Bean的上下文管理、以及JMS与EJB的结合使用至关重要。同时,掌握Java EE的其他组件,如Servlet、JSP、JSF等,也是提升EJB3...

    EJB3实例教程

    有状态会话Bean可以存储客户端状态,适用于需要维护会话上下文的情况。 ### 4. 注解驱动开发 EJB3的一大亮点是广泛使用注解,比如`@EJB`用于注入其他Bean,`@PersistenceContext`和`@PersistenceUnit`用于管理数据...

    ejb 3 官方 API

    9. **持久化**:`@PersistenceContext`和`@PersistenceUnit`注解用于管理和访问持久化上下文,与JPA配合,方便地进行对象的保存、查询和删除。 10. **查询语言**:JPA引入了JPQL(Java Persistence Query Language...

    JSF-EJB3.rar_EJB3.rar_base.util.EJBUtil_ejb jsf_jsf ejb3_jsf mys

    1. **实体Bean(Entity Beans)**:EJB3引入了注解驱动的实体管理,允许开发者直接在类上使用注解(如@Entity和@Id)来声明一个对象为数据库中的持久化实体。 2. **会话Bean(Session Beans)**:用于封装业务逻辑...

    EJB3.pdf EJB3 文档 资料

    而有状态会话Bean则维护着与特定客户端的交互状态,适用于需要跨多个方法调用维持上下文的应用场景。理解两者之间的区别,并掌握如何改变会话Bean的JNDI名称、如何管理会话Bean的生命周期,以及如何使用拦截器和依赖...

    EJB3 in Action

    - **Stateful Session Beans**:可以跨多次调用保持客户端状态,适用于需要跟踪客户端上下文的场景。 **4. 消息驱动Bean (MDB) 的开发** 第四章“消息和开发MDB”重点介绍了如何利用消息驱动Bean (MDB) 来处理异步...

    EJB 3.0规范官方文档

    1. **持久化上下文(Persistence Context)**:持久化上下文是管理实体Bean实例的容器,它负责跟踪Bean的状态变化并确保这些变化被正确地同步到数据库。 2. **生命周期回调(Lifecycle Callbacks)**:开发者可以...

    EJB3.pdf

    3. **实体 Bean(Entity Beans)的简化**:EJB3中的实体Bean使用JPA(Java Persistence API)进行持久化操作,取代了EJB2中的CMP(Container-Managed Persistence)。JPA允许开发者使用ORM(Object-Relational ...

    EJB学习PPT(上)

    有状态会话bean保持与特定客户端的上下文,而无状态会话bean不保存任何客户端状态。 - **实体bean(Entity Beans)**:这些bean持久化数据,通常映射到数据库中的表。有两种主要的实体bean类型:Bean管理的持久性...

    EJB2.0

    无状态会话Bean通常用于执行独立的操作,而有状态会话Bean则保存了客户端的上下文信息,可以处理多个请求序列。 2. 消息驱动Bean(Message-Driven Beans,MDB):这是EJB2.0引入的新特性,主要用于处理JMS(Java ...

    Ejb开发实体bean

    实体Bean(Entity Beans)是EJB的一种类型,它代表了业务逻辑中的持久数据,通常对应数据库中的记录。在这个"购物车"案例中,我们将会探讨如何使用EJB来开发一个简单的实体Bean,以及与之交互的Web前端。 1. **EJB...

    EJB3_study

    无状态Bean适用于一次性的、不依赖上下文的请求,而有状态Bean可以维护客户端的会话状态。 - **消息驱动Bean(Message-Driven Bean, MDB)**:用于处理JMS(Java Message Service)消息,是异步处理的典型代表。 #...

Global site tag (gtag.js) - Google Analytics