作者:狂放不羁
网址: 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的扩展的持久化上下文来实现会话。
相关推荐
**J2EE技术及其实现** Java企业版(Java Enterprise Edition,简称J2EE)是Oracle公司(原Sun Microsystems)推出的用于开发分布式、多层企业级应用的平台。它为构建可扩展、高可用和安全的网络应用程序提供了一个...
标题"使用Hibernate快速实现持久层处理的实例工程源代码"表明,这个项目主要聚焦于展示如何高效地利用Hibernate框架来完成数据库操作。Hibernate的核心特性包括自动映射Java对象到数据库表、事务管理以及强大的查询...
在J2EE(Java 2 Platform, ...通过实践这个"j2ee实现用户登录"的例子,你可以深入了解J2EE的各个层面,包括Web层(Servlet和JSP)、数据库交互以及会话管理等核心概念。这将为你在开发企业级Java应用时打下坚实的基础。
- **EntityBean**:介绍了EntityBean的特性及其在持久化中的作用。 - **Message-DrivenBean**:讨论了消息驱动Bean的实现机制。 - **定义客户端访问接口**:讲解了如何定义客户端访问EJB的接口。 - **企业Bean的...
4. **业务逻辑**:EJB组件是J2EE的核心,它可以是会话bean(Session Beans)处理临时状态,实体bean(Entity Beans)持久化数据,或消息驱动bean(Message-Driven Beans)响应消息事件。这些bean封装了业务逻辑,与...
EJB分为三种类型:Session Beans(会话bean)用于管理用户会话,Message-driven Beans(消息驱动bean)用于处理消息队列,和Entity Beans(实体bean)用于持久化数据。源码中可能包含了这些不同类型的bean实例。 4....
EJB有三种类型:会话bean(Session Beans)处理客户端请求,实体bean(Entity Beans)代表持久化的业务对象,消息驱动bean(Message-Driven Beans)用于处理JMS消息。在实例中,你可以学习如何创建和部署这些bean,...
3. **业务逻辑层**:通过EJB实现,包含会话Bean和实体Bean,处理业务规则和操作。 4. **数据访问层**:使用JDBC(Java Database Connectivity)或JPA(Java Persistence API)访问和操作数据库。 **第二章:Java...
【标题】: "简单聊天室 J2EE课程实验 - 使用Servlet实现" 【描述】: "在J2EE课程中,构建一个简单的聊天室是学习Web应用程序开发基础的一个常见实践项目。这个实验旨在让学生掌握Servlet技术,理解HTTP协议,并能够...
3. **EJB 2.1**:引入了Session Bean的无状态会话和有状态会话,以及Message-Driven Bean,简化了EJB的使用。 4. **JPA(Java Persistence API)**:作为ORM(Object-Relational Mapping)的标准,替代了原先的CMP。...
在J2EE中,会话管理是通过HttpSession对象实现的,它允许服务器跟踪用户在整个会话期间的状态。 5. **业务逻辑层(EJB层)** 企业JavaBean(Enterprise JavaBeans,EJB)是J2EE的核心,提供了服务器端的组件模型...
5. **持久层技术**:J2EE 提供了 JDBC(Java Database Connectivity)用于数据库访问,以及 JPA(Java Persistence API)和 Hibernate 这样的对象关系映射(ORM)框架,简化了数据库操作。 6. **消息传递**:JMS...
Hibernate作为持久层,用于简化数据库操作,实现对象关系映射(ORM)。 1. **Struts2**:Struts2是一个强大的MVC框架,通过拦截器机制处理HTTP请求,提供了一系列的拦截器来实现如认证、授权、异常处理等功能。它的...
3. **创建企业Bean**:根据具体的应用需求,设计并实现不同类型的企业Bean,例如会话Bean、实体Bean或消息驱动Bean。 4. **创建客户端**:为J2EE应用程序创建客户端界面,可以是基于Swing/AWT的Java应用程序客户端...
5. **资源适配器层**:允许J2EE应用程序与外部系统如ERP、CRM集成。 **二、J2EE组件** 1. **Servlet**:服务器端的Java小程序,处理HTTP请求,生成响应。 2. **JSP**:结合了HTML和Java代码,用于生成动态网页。 3....
4. **JAVA持久层**:Java持久层是J2EE应用中的一个关键部分,负责对象在数据库中的持久化。通过JPA,开发者可以避免直接编写SQL语句,而是通过定义实体类和元数据来实现数据存储和检索。 5. **JAVA对象映射**:对象...
1. **分层架构模式**:J2EE应用通常采用分层架构,包括表示层(用户界面)、业务逻辑层(服务层)和数据访问层(持久层)。这种架构有助于分离关注点,提高代码复用性和测试性。 2. **表示层**:在J2EE中,表示层...
在EJB中,有三种主要的组件类型:会话bean(Session Beans)处理业务逻辑,实体bean(Entity Beans)封装持久化数据,消息驱动bean(Message-Driven Beans)用于处理消息队列。EJB容器提供了一种环境,确保了这些...
在购物系统中,可能会有Session Beans处理用户的会话状态,例如购物车信息,以及Entity Beans持久化商品和订单数据。 4. **JDBC与ORM框架**:JDBC(Java Database Connectivity)是Java与数据库交互的标准API。购物...