使用Seam的替代JPA提供程序

发布者:    |       JPA Seam

你以为这是不可能的吗?当然可以!虽然Seam开发团队鼓励你使用Hibernate作为JPA提供程序,但Seam能够与任何JPA提供程序协同工作。本文将向您展示如何操作。

为什么选择Hibernate?还是不选择?

Hibernate被推荐是有原因的。它提供了一些Seam可以利用的供应商扩展,这可以为您带来优势。如果您愿意放弃这些增强(尤其是手动刷新、高级映射和Hibernate Search),那么您应该没有问题更换Hibernate为其他提供程序。事实上,我鼓励您尝试替代提供程序,这样您就能体会到Hibernate所增加的价值 ;)

建议就到这里,让我们开始吧。

更改JPA持久化提供程序

更改Seam应用程序中的JPA持久化提供程序有三个步骤

  1. 确保JPA提供程序已部署到应用程序服务器(JAR文件可在类路径上找到)
  2. 在persistence.xml中声明SPI类
  3. 告诉Seam使用通用的JPA持久化提供程序管理组件(而不是Hibernate)

配置好JPA提供程序后,您应该检查您的代码中是否有使用Hibernate特定扩展的情况。这将防止您遇到异常。

步骤1:准备替代提供程序

第一步通常是决定使用应用程序服务器提供的JPA提供程序。例如,如果您正在使用GlassFish V2,TopLink Essentials是捆绑的提供程序。否则,您必须将JAR文件添加到应用程序服务器的扩展目录中。如果您曾经在GlassFish上使用过Hibernate,就必须执行此步骤。

步骤2:将持久化单元附加到提供程序

第二步是告诉JPA您想要使用哪个提供程序。您需要在元素下的元素中输入扩展javax.persistence.spi.PersistenceProvider接口的SPI类。javax.persistence.spi.PersistenceProvider接口<provider>元素下<persistence-unit>在持久化单元描述符(persistence.xml)中。

<persistence xmlns="http://java.sun.com/xml/ns/persistence" 
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" 
   version="1.0">
   <persistence-unit name="pu">
      <provider>oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider</provider>
      ...
   </persistence-unit>
</persistence>

如果类路径上只有一个提供者,JPA会自动检测并使用它。只有当你有多个JPA提供者在类路径上时,你才必须明确指定。

你可能需要指定persistence.xml中的一些其他设置,这些设置特定于提供者,就像Hibernate有其自己的属性集一样。例如,使用TopLink时,你需要添加一个设置目标数据库的属性

<property name="toplink.target-database" value="MySQL4"/>

我还发现,当我在使用展开的存档时,我必须告诉TopLink不要排除未列出的类。这是通过在上面的<properties>元素之前添加以下元素来完成的

<exclude-unlisted-classes>false</exclude-unlisted-classes>

效果因人而异。我必须承认,根据你的打包方式,正确设置持久化单元可能很复杂。这与Seam无关。

步骤3:向Seam透露你将不会使用Hibernate

配置应用程序的第三步和最后一步是向Seam提供有关要使用的持久化提供者管理组件的提示。这就是Seam如何确定哪些JPA提供者支持哪些功能。对于任何非Hibernate JPA提供者,你可以在Seam组件描述符(components.xml)中定义通用的JPA持久化提供者。

<components xmlns="http://jboss.com/products/seam/components"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   ...
   xsi:schemaLocation="
      ...
      http://jboss.com/products/seam/components http://jboss.com/products/seam/components-2.1.xsd">

   ...
   <component name="org.jboss.seam.persistence.persistenceProvider"
      class="org.jboss.seam.persistence.PersistenceProvider"/>
</components>

这仅在你将Hibernate放在类路径上时才是必要的,因为Seam假定在这种情况下你想要使用Hibernate(请参阅JBSEAM-2785以了解修复此“功能”的计划)。

然而,如果你使用Seam < 2.1.2,你会遇到问题。在旧版本中,Seam会在渲染之前尝试将持久化上下文切换到手动刷新模式时抛出异常(请参阅JBSEAM-3030),而此刷新模式仅在Hibernate中可用。现在已经修复了这个问题。在你有机会升级之前,你需要添加以下组件到你的应用程序中来抑制此异常

package com.domain.app.persistence;

import javax.persistence.EntityManager;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.persistence.PersistenceProvider;

@Name("org.jboss.seam.persistence.persistenceProvider")
public class NoManualFlushPersistenceProvider extends PersistenceProvider {

   @Override
   public void setFlushModeManual(EntityManager entityManager) {
      // no-op
   }
}

现在,你应该能够使用备选的JPA提供者启动你的Seam应用程序!现在,是时候调整你的期望了。

影响

首先,没有Hibernate,将无法使用手动刷新。因此,当使用长时间运行会话时,你很可能会在每个请求之后刷新持久化上下文。原因是Seam在每个非faces请求周围使用一个包装器(全局)事务,并在每个faces请求中使用两个事务。由于JPA提供者在事务提交之前刷新,因此可以保证在每次请求上都会刷新。你可以选择通过配置Seam组件描述符中的<core:init>组件来禁用Seam的包装器事务

<core:init transaction-management-enabled="false"/>

现在你可以通过避免调用事务方法直到你准备好将脏更改发送到数据库来控制刷新。这就是所说的JPA方式。

此外,请注意,你不能将EntityManager转换为FullTextEntityManager(Hibernate Search)。另外,当你从EntityManager检索代理时,它将是提供者的代理,例如在TopLink中将是oracle.toplink.essentials.ejb.cmp3.EntityManager

请随意

这就是拥有备用JPA提供者的Seam!这是利用Java EE标准的好处。实际上,你甚至可以使用seam-gen创建一个可以部署到GlassFish的Seam项目,这是Seam是Java EE框架的最终证明。虽然你可能享受你的自由,但你也会错过Hibernate添加的某些良好功能。然而,了解你有选择总是好的。

官方说明以常见问题解答(FAQ)的形式保存在Seam维基百科上。


返回顶部