`

J2EE持久层会话实现(续)

阅读更多

作者:狂放不羁 
   网址: http://yuquan-nana.iteye.com

    >>>转载请注明出处!<<<
 

 

接着上篇“J2EE持久层持久化上下文传播总结”,这篇文章总结一下如何利用当今J2EE比较流行的持久层框架Hibernate和持久层标准JPA来实现会话。

 

在讨论此问题之前,首先要明确一个问题,什么是会话?会话简单的可以理解为跨多个request生命周期,就拿那个投修改简历的问题来说,第一个事务读取简历,用户修改,然后再通过另外一个事务去更新简历,那么读取和更新是在不同的事务中完成的,那么我们怎么实现这种用例呢?如果采用ORM框架,实现起来会轻松很多,下面就以hibernate和JPA来做一总结。

1. Hibernate实现会话:在hibernate中实现会话可以采用两种策略。

第一种就是采用detached object,在此种情况下,我们只需要用hibernate提供的reattach和merge操作将脱管对象重附或者是合并到当前的持久化上下文,hibernate会为我们检测更新并最后决定同步到数据库。

第二种就是通过ManagedSessionContext来扩展持久化上下文,使其跨越几个request生命周期。在使用ManagedSessionContext来实现扩展持久化上下文时,一定要记得设置session的flushmode为FlushMode.MANUAL.这样在每次事务提交的时候就不会同步持久化上下文。(不幸的是JPA规范中没有此选项,我们只能通过非事务型的操作来实现,但是如果采用EJB模型,那么我们就可以采用statefull session bean默认的扩展的持久化上下文)。

下面我主要说一下如何在JPA中来实现会话:

2. JPA中实现会话:在JPA中实现会话,我主要结合EJB的编程模型来做一总结,因为EJB编程模型为我们做了很多简化,免得我们自己动手实现,但是如果要在非J2EE托管环境下使用JPA,就要自己实现。

第一种策略:采用脱管对象来实现。在这之前首先要明确一个问题,那就是JPA只提供了对脱管对象的merge(合并)操作,没有提供reattach(重附操作),所以我们采用脱管对象实现会话时,在会话的最后一个request生命周期中,我们通过合并来将脱管对象合并到持久化上下文,当然detached object对象,我们一般是保存到httpsession里面,但是这样一个不好的地方就是将业务逻辑泄露到了表现层,不利于层的内聚性,所以我们可以采取EJB编程模型给我们带来的便利方式来实现,通过扩展的持久化上下文来实现,下面就来说说如何通过扩展的持久化上下文来实现会话。

第二种策略:采用statefull session bean扩展的持久化上下文来实现。因为在EJB3.0中,有状态会话bean默认采取扩展的持久化上下(extended persistence context),持久化上下文的生命周期与statefull session bean的生命周期是一致的,所以我们可以通过此扩展的持久化上下文来实现会话。为了更加清楚,我采用以下代码来描述:

@Statefull

@Remote(BussinessInterface.class)

public class ConversationBean implements BusinessInterface{

 

@PersistenceContext(type = PersistenceContextType.EXTENDED)

EntityManager em ;

 

public OperationResult firstOperation(...){

//此方法实现会话的第一个请求

}

 

//省略会话的中间阶段的请求方法,我只用一个来描述

public OperationResult middleOperation(..){

//此方法可以实现会话的一些中间操作,比如查询等

}

 

..........

 

//会话的最后一个请求

public OperationResult lastOperation(...){

 

 

}

 

 

}

但是此种情况下实现会话需要注意一个问题,因为EJB3.0规范没有像hibernate那样的人工刷新持久化上下文的选项,所以此时要想会话的中间阶段不刷新持久化上下文,为了让会话的中间阶段不刷新持久化上下文(同步持久化上下文到数据库),那么或者采用hibernate扩展或者采用非事务型的EJB组件方法调用(因为JPA规范只有两种持久化上下文的刷新模式,一种是AUTO,它是默认的刷新选项,第二种是commit,第一种要求在执行查询和事务提交的时候都刷新持久化上下文)。分两种情况来描述:

采用Hibernate扩展:此种情况下,我们需要增加以下注释:

........

@PersistenceContext(type=PersistenceContextType.EXTENDE,

  propertites = @PersistenceProperty(name="org.hibernate.flushMode",   

  value="MANUAL")

EntityManager em;

 

......

 

以上的注释也可以采用等价的XML部署描述来替换。

通过以上的注释,当我们的客户端调用会话中间操作时,当前与ConversationBean绑定的扩展的持久化上下文就不会刷新(因为默认会在middleOperation()方法调用的时候启动事务,结束后提交事务,而如果按照JPA标准的话,flushMode无论是AUTO,还是COMMIT,都会刷新持久化上下文,并且如果我们在中间操作进行查询操作,也会触发刷新持久化上下文的操作),当然因为当前的持久化上下文是人工刷新的,那么我们就需要在会话的最后一个操作中,本例中,也就是lastOperation中手动刷新数据库,代码如下:

 

public OperationResult lastOperation(...){

 

em.flush();

em.commit();//注意此时em是可选的,因为默认在方法调用后会自动提交事务。

}

此时我们还可以将一个会话通过面向对象的设计来进行分解,比如我们可能还需要其它的EJB来实现会话,那么我们可以将其通过@EJB注释让容器帮我们注入,这样以来不同的EJB之间的传播会通过当前的系统事务来传播持久化上下文(具体请参考上篇持久化上下文传播)

采用目前JPA规范建议方法:非事务型的EJB方法调用。我们可以修改ConversationBean的代码如下:

@Statefull

@Remote(BussinessInterface.class)

@TransactionAttribute(TransactionAttributeType.NOT_SUPPORT)

public class ConversationBean implements BusinessInterface{

 

@PersistenceContext(type = PersistenceContextType.EXTENDED)

EntityManager em ;

 

public OperationResult firstOperation(...){

//此方法实现会话的第一个请求

}

 

//省略会话的中间阶段的请求方法,我只用一个来描述

public OperationResult middleOperation(..){

//此方法可以实现会话的一些中间操作,比如查询等

}

 

..........

 

//会话的最后一个请求

@Remove

@TransactionAttribute(TransactionAttributeType,REQUIRED)

public OperationResult lastOperation(...){

 

   em.flush();

   em.commit();//注意此时em是可选的,因为默认在方法调用后会自动     提交事务。

 

}

}

以上代码改变的地方就是我们将ConversationBean的事务属性改为了not support(默认情况下是REQUIRED),这样以来我们的ConverstationBean的调用就不会在事务中进行,所有的会话操作都会放在一个队列中,当我们的扩展的持久化上下文重新与事务关联的时候,当事务提交时同步到数据库。但是有个问题,如果ConversationBean还会调用的EJB bean怎么办?因为当前的bean不支持事务,那么持久化上下文是不能通过事务来传播的,比如ConversationBean会与另外一个bean进行协作,我们定义如下:

@Stateless

@Remote(AnotherBussinessInterface.class)

public class AssistBean implements AnotherBusinessInterface{

 

.........

}

 

此时我们需要增加如下代码到ConversationBean中:

.......

//通过@EJB注释,EJB容器会将实例池里的一个实例注入到当前的 ConversationBean里。

@EJB

AnotherBusinessInterface assistBean;

........

 

这样以来,我们遇到了持久化上下文传播的问题,因为此时ConversationBean不支持事务,所以扩展的持久化上下文是传播不到没有无状态会话bean里的(这个是JPA规范规定的,不能在没有事务的情况下,传播扩展的持久化上下文到stateless session bean),那么既然持久化上下文不能得到传播,那么我们同一个会话中就会有不同的持久化上下文,这样就不能保证会话的完整性。那么我们有没有办法来采取采取措施补救呢?幸亏还有哈哈,那就是我们可以将AssistBean改为有状态的会话bean,这样以来,因为扩展的持久化上下文此时通过bean实例来传播的,所以不同的有状态会话bean里会采用同一个持久化上下文。所以我们要想通过有状态会话bean的扩展的持久化上下文来实现会话,会话设计到的所有的bean必须都要是statefull,造成这样不方便的原因也就在与当前JPA标准不支持FlushMode.MANUAL,如果JPA也支持了此选项,那么我们通过扩展的持久化上下文实现会话将变得更加容易,希望以后JPA标准能加入FlushMode.MANUAL选项。

综上所述,实现会话我们可以采取两种措施,第一种就是通过detached object,这样的不好地方就是业务状态都保存到了表现层,不利于分层架构,不利于层的内聚性,所以为了将业务状态保存到业务层,那么我们可以采取扩展的持久化上下文,虽然hibernate支持flushModel.MANUAL的选项,但是要自己动手实现扩展的持久化上下文,而EJB提供了扩展的持久化上下文,但是又没有提供FlushMode.MANUAL的选项,所以如果各有个的好处,遗憾的是不能两全其美。但是当采用EJB的扩展的持久化上下文,这样不用自己动手实现,唯一不好的地方就是要么通过hiberante的扩展来关闭事务提交自动刷新持久化上下文,要么通过非事务型的EJB方法调用来关闭事务提交自动刷新持久化上下文,所以如果我们EJB容器采用了Hiberante做为JPA标准的实现,那么我们最好借助与Hiberante的扩展,以及statefull session bean的扩展的持久化上下文来实现会话。

4
0
分享到:
评论

相关推荐

    J2EE技术及其实现

    **J2EE技术及其实现** Java企业版(Java Enterprise Edition,简称J2EE)是Oracle公司(原Sun Microsystems)推出的用于开发分布式、多层企业级应用的平台。它为构建可扩展、高可用和安全的网络应用程序提供了一个...

    使用Hibernate快速实现持久层处理的实例工程源代码

    标题"使用Hibernate快速实现持久层处理的实例工程源代码"表明,这个项目主要聚焦于展示如何高效地利用Hibernate框架来完成数据库操作。Hibernate的核心特性包括自动映射Java对象到数据库表、事务管理以及强大的查询...

    j2ee实现用户登录

    在J2EE(Java 2 Platform, ...通过实践这个"j2ee实现用户登录"的例子,你可以深入了解J2EE的各个层面,包括Web层(Servlet和JSP)、数据库交互以及会话管理等核心概念。这将为你在开发企业级Java应用时打下坚实的基础。

    J2EE 指南 J2EE中文教材

    - **EntityBean**:介绍了EntityBean的特性及其在持久化中的作用。 - **Message-DrivenBean**:讨论了消息驱动Bean的实现机制。 - **定义客户端访问接口**:讲解了如何定义客户端访问EJB的接口。 - **企业Bean的...

    基于J2EE酒店管理系统设计与实现

    4. **业务逻辑**:EJB组件是J2EE的核心,它可以是会话bean(Session Beans)处理临时状态,实体bean(Entity Beans)持久化数据,或消息驱动bean(Message-Driven Beans)响应消息事件。这些bean封装了业务逻辑,与...

    J2EE经典案例设计与实现源码

    EJB分为三种类型:Session Beans(会话bean)用于管理用户会话,Message-driven Beans(消息驱动bean)用于处理消息队列,和Entity Beans(实体bean)用于持久化数据。源码中可能包含了这些不同类型的bean实例。 4....

    j2ee实例 j2ee实例j2ee实例

    EJB有三种类型:会话bean(Session Beans)处理客户端请求,实体bean(Entity Beans)代表持久化的业务对象,消息驱动bean(Message-Driven Beans)用于处理JMS消息。在实例中,你可以学习如何创建和部署这些bean,...

    J2EE课件+j2ee课件

    3. **业务逻辑层**:通过EJB实现,包含会话Bean和实体Bean,处理业务规则和操作。 4. **数据访问层**:使用JDBC(Java Database Connectivity)或JPA(Java Persistence API)访问和操作数据库。 **第二章:Java...

    简单聊天室 J2EE课程实验 用servlet实现简单的聊天室

    【标题】: "简单聊天室 J2EE课程实验 - 使用Servlet实现" 【描述】: "在J2EE课程中,构建一个简单的聊天室是学习Web应用程序开发基础的一个常见实践项目。这个实验旨在让学生掌握Servlet技术,理解HTTP协议,并能够...

    J2EE JAR包(J2EE1.3 J2EE1.4 J2EE5.0 )

    3. **EJB 2.1**:引入了Session Bean的无状态会话和有状态会话,以及Message-Driven Bean,简化了EJB的使用。 4. **JPA(Java Persistence API)**:作为ORM(Object-Relational Mapping)的标准,替代了原先的CMP。...

    j2ee原理

    在J2EE中,会话管理是通过HttpSession对象实现的,它允许服务器跟踪用户在整个会话期间的状态。 5. **业务逻辑层(EJB层)** 企业JavaBean(Enterprise JavaBeans,EJB)是J2EE的核心,提供了服务器端的组件模型...

    J2EE完全参考手册-J2EE概述-pdf

    5. **持久层技术**:J2EE 提供了 JDBC(Java Database Connectivity)用于数据库访问,以及 JPA(Java Persistence API)和 Hibernate 这样的对象关系映射(ORM)框架,简化了数据库操作。 6. **消息传递**:JMS...

    J2EE网上购物系统

    Hibernate作为持久层,用于简化数据库操作,实现对象关系映射(ORM)。 1. **Struts2**:Struts2是一个强大的MVC框架,通过拦截器机制处理HTTP请求,提供了一系列的拦截器来实现如认证、授权、异常处理等功能。它的...

    J2EE指南(J2EE tutorial )

    3. **创建企业Bean**:根据具体的应用需求,设计并实现不同类型的企业Bean,例如会话Bean、实体Bean或消息驱动Bean。 4. **创建客户端**:为J2EE应用程序创建客户端界面,可以是基于Swing/AWT的Java应用程序客户端...

    J2EE完全参考手册-J2EE概述PDF

    5. **资源适配器层**:允许J2EE应用程序与外部系统如ERP、CRM集成。 **二、J2EE组件** 1. **Servlet**:服务器端的Java小程序,处理HTTP请求,生成响应。 2. **JSP**:结合了HTML和Java代码,用于生成动态网页。 3....

    NETBEANS7下J2EE6开发技术-英文

    4. **JAVA持久层**:Java持久层是J2EE应用中的一个关键部分,负责对象在数据库中的持久化。通过JPA,开发者可以避免直接编写SQL语句,而是通过定义实体类和元数据来实现数据存储和检索。 5. **JAVA对象映射**:对象...

    J2EE核心模式pdf

    1. **分层架构模式**:J2EE应用通常采用分层架构,包括表示层(用户界面)、业务逻辑层(服务层)和数据访问层(持久层)。这种架构有助于分离关注点,提高代码复用性和测试性。 2. **表示层**:在J2EE中,表示层...

    J2EE官网教程1

    在EJB中,有三种主要的组件类型:会话bean(Session Beans)处理业务逻辑,实体bean(Entity Beans)封装持久化数据,消息驱动bean(Message-Driven Beans)用于处理消息队列。EJB容器提供了一种环境,确保了这些...

    基于J2EE的网络商城购物系统的设计与实现.zip

    在购物系统中,可能会有Session Beans处理用户的会话状态,例如购物车信息,以及Entity Beans持久化商品和订单数据。 4. **JDBC与ORM框架**:JDBC(Java Database Connectivity)是Java与数据库交互的标准API。购物...

Global site tag (gtag.js) - Google Analytics