SEAM IN ACTION 第9章

斜瑞
2023-12-01

9、Seam-managed persistence and transactions


This chapter covers
■ Handling the persistence context properly
■ Bootstrapping Java persistence in Seam
■ Applying a multifaceted transaction strategy
■ Implementing an application transaction

SEAM管理的存储和事务

本章包括
恰当处理存储上下文
在SEAM中启动JAVA存储
应用多层面的事务策略
实现一个应用事务

Most web frameworks remain agnostic of persistence rather than recognize it as
vital to the overall state of the application. Stateless architectures, especially, have
depleted the persistence manager of its true value—to monitor a set of managed
entities and transparently migrate changes made to them to the database. Seam
seeks to restore Java persistence (i.e., ORM) to its full potential by recognizing it as
a core part of the application. In addition to adeptly managing the persistence
context, Seam ensures that a transaction is always active, commits the transaction
when appropriate, and broadcasts transaction synchronization events to improve
transparency of persistence operations. In the previous chapter, you learned the fundamentals
of Java persistence and how persistence is used both inside and out of a
Java EE container. In this chapter, you’ll discover how Seam’s involvement with transactions
and persistence helps make these services truly manageable.

多数WEB框架保持对存储的不可知,而不是认为应用的整体状态很重要。无状态结构,尤其是删去了的存储管理器的真正价格,监视一套被管理的实体,透明地迁移其变化到数据库。SEAM将其认作应用的核心部分,借用存储Java persistence(ORM)并作同最大努力。除了熟练地管理存储上下文,SEAM确保事务总是活动的,适当的时候提交事务,广播事务的同步事件以加强存储操作的透明度。在前一章,你学习了Java 存储的基础,存储如何应用在Java EE容器的内部和外部。本章介绍SEAM如何包含事务及存储来使这些服务真正可管理。

The conversation is also revisited in this chapter, which combines with persistence
to form the core of Seam’s state-management architecture. Seam hosts the persistence
manager in the conversion context, giving it refuge from the confines of a stateless
design. The true benefit of this union is realized at the end of the chapter when you
learn about an application transaction, a special type of transaction that allows modifications
made to managed entities to be queued across requests until the end of
the use case, at which time the changes are committed to the database within a database
transaction.

本章还会重访会话,其与存储结合,构成了SEAM有状态管理架构的核心。SEAM在会话上下文主持存储管理,突破了无状态设计的限制。真正的结合的益处是建立应用级的事务,一个特殊类型的事务,让被管理的实体可以被修改,可以穿越请求,直到用例结束。这时改变在一个数据库事务中提交到数据库。

This chapter also prepares you to use the Seam Application Framework, covered in
the next chapter, which enables rapid development of create, read, update, delete
(CRUD)-based applications and embodies the design goal of properly handling the
persistence context, a theme that continues through this chapter. Let’s pick up with
this theme where the previous chapter left off.

本章也为你下一章使用SEAM应用框架做好准备。那种快速开发基于CRUD的应用。提供恰当的存储上下文。让我们先捡起前一章遗留的这一主题。

9.1 Getting persistence context management right
To realize the true value of Java persistence, the persistence manager—a general
term for a JPA EntityManager or Hibernate Session—must be scoped properly. In
chapter 8, you learned that if you treat the persistence manager as a stateful component,
it can do a lot for you; if you don’t, it can lead to a lot of pain. The transactionscoped
persistence context inhibits the capabilities of Java persistence and is generally
discouraged in Seam.

摆正存储上下文管理
为实现Java persistence的真正价值,存储管理器,一个JPA EntityManager or Hibernate Session的通用词汇,范围必须设定正确。第8章已介绍如果你将存储管理器看作有状态部件,它可以为你做很多。

The challenge of using an extended persistence context is deciding how long to
extend it without overdoing it. If it’s not held open long enough, your entities become
detached prematurely. If it’s held open for too long, it can result in an overzealous
cache and memory leaks. As it turns out, the persistence manager was intended to
serve a use case, making the conversation context the ideal host for an extended persistence
context. In this section, I explain how a conversation-scoped persistence manager
gets to the heart of the problems that many developers encounter using ORM.
I then show you two ways to bind the persistence manager to a conversation in a
Seam application.

使用扩展的存储上下文的挑战在于决定扩展多长而不会过度。如果打开的时间不够长,你的实体会永久脱管。如果打开过长,会导致缓冲过热和内存泄漏。结果是存储管理器试图服务一个用例,使会话上下文成为理想的扩展的存储上下文的宿主。本节,我解释一个会话范围存储管理器解决很多开发者使用ORM遇到的问题。随后我给出两种方式在SEAM应用中绑定存储管理器到会话。

9.1.1 Respecting the persistence manager
It’s true that using Java persistence in a web application can be a challenge. Unfortunately,
some developers have made it harder than it has to be. I want to educate you
about the shortcomings of the so-called “patterns” that have been developed to solve
Hibernate lazy-loading exceptions. The purpose in raising this issue is to emphasize
that this exception is really a symptom of incorrect usage, which these shortsighted
fixes fail to address.

在WEB应用中使用Java persistence的确是个挑战。不幸的是一些开发者用得更糟糕了。我想告诉你一个缺点,就是所谓的“patterns”,是用来解决Hibernate延迟加载异常的。这个讨论的目的在于强调异常出自不正确的使用。which these shortsighted
fixes fail to address.

THE OPEN SESSION IN VIEW REMEDY
Recognizing that Hibernate wasn’t going to allow lazy loading in the view unless the
Session remained open, developers created the Open Session in View pattern,1 which
controls the Session from the outer rim of the application using a servlet filter. It
works by preventing the data layer from closing the Session and instead the filter
closes it at the end of the request. (There is a parallel implementation for JPA that also
applies here.)

OPEN SESSION IN VIEW修复法
认识到Hibernate不允许在view中延迟加载,除非Session还开着,开发者建立了Open Session in View模式,从外部使用servlet filter控制Session。通过不关Session来保护数据层,只在请求的末尾让过滤器去关闭。(JPA中也有这样的实现)

The problem with this fix is that a filter is too far removed from the application
to know what it’s doing. It blindly tries to determine whether it should open one
Session or whether several are needed. Complications also arise because now the
Session has two masters, the application framework and the filter, which may not
always be in agreement.

这种补救的问题在地应用不会知道过滤器在干什么。另外的复杂性在于Session现在有两个主人了,它们不可能总是互相认同。

The filter may make a mess of things, but at least it allows lazy loading in the
view, right? Sure, but the benefits end there. By waiting until the end of the request
to flush and close the persistence context, the application doesn’t know if the database
writes succeeded or failed until after the view is rendered, a problem addressed
in section 9.4.1. Once the page is rendered, all of the entity instances stored in stateful
scopes become detached. Thus, the lazy-loading problems are merely deferred
until postback, where you no longer benefit from the persistence cache or automatic
dirty checking of entities. In addition, having detached entities around during
a postback can introduce the NonUniqueObjectException. A far better solution is to
respect the persistence manager by scoping it to the conversation.

过滤器可能会弄乱事情。直到请求结束再做清理(flush),并关闭存储上下文。应用在生成view前并不知道数据是否写成功,这个问题见9.4.1。一旦页面生成,所有保存在有状态范围的实体实例脱管。因此延持加载总是只推迟到postback,那时你已不再从存储缓冲或自动脏数据检查中受益,另外,在postback时有太多的脱管实体会导致NonUniqueObjectException。一个更好的办法是使用存储管理器扩展
其范围到会话。

THE OPEN SESSION IN CONVERSATION SOLUTION
As you learned in chapter 7, conversations last for at least the entire request, including
redirects. By associating the persistence manager with the conversation, you get
the Open Session in View pattern for free. But now, you aren’t allowing a filter to
make arbitrary decisions about how the persistence manager should be managed. If
the conversation is long-running, then the persistence manager stretches to match it,
termed the Open Session in Conversation pattern. As a result, entities aren’t detached
prematurely, which means you can avoid merging and instead benefit from automatic
dirty checking. In fact, to propagate an entity instance between requests, you only
have to keep track of the entity’s identifier since the same instance can be retrieved
again out of the persistence context.

OPEN SESSION IN CONVERSATION方案
如第7章所学,会话至少持续一整个请求,即使有重定向。通过关联存储管理器到会话,你可以免费得到Open Session in View模式。但现在你不能让过滤器对存储管理器如何管理任意作决定。如果会话是长期运行的,则存储管理器会扩展以匹配它,这就叫Open Session in Conversation模式。结果,实体不会永久脱管,这意味你可以避免合并,并有脏数据检查。事实上,在请求间传播一个实体实例,你只需要跟踪实体的ID,因为同一个实例可从存储上下文中再次得到。

Placing the persistence manager directly into the conversation introduces the
problem that no one tends to it. Who will close it? How will it be enlisted in transactions?
I present two options for tying the persistence manager to a conversation in a
way that it is still managed.

将存储管理器直接放入会话引入了一个问题,也就是没有会管理它。谁来关闭它?怎样被加入事务?我给出两个方式使其仍被管理。

9.1.2 Managing an extended persistence context
Seam has two strategies for managing an extended persistence context, contrasted in
figure 9.1. In chapter 8, you learned that a container-managed persistence manager

管理一个扩展的存储上下文
SEAM有两个策略来管理存储上下文,对比见图9.1,在第8章,你知道一个容器管理的存储管理器在生命周期中可以加载到有状态session bean (SFSB)。通过指定SFSB到会话,SEAM就可以直接管理扩展的存储上下文。另外,SEAM可以通过建立自己的存储管理器并直接保管在会话中来完全控制扩展的存储上下文。


can latch onto a stateful session bean (SFSB) for the duration of its lifetime. By scoping
the SFSB to the conversation, Seam can indirectly manage the extended persistence
context. Alternatively, Seam can take full control of the extended persistence
context by creating its own persistence manager and storing it directly in the conversation.
The benefit of the Seam-managed persistence manager is that it can be injected
into any Seam component.

Picking up from the previous chapter, I reiterate the inherent limitations of using
an SFSB to host the extended persistence context and segue into Seam’s more flexible
solution.

回顾前一章,我反复地说,使用SFSB来管理扩展存储上下文有其固有的限制。SEAM有更灵活的方案。

SCOPING THE PERSISTENCE CONTEXT INDIRECTLY
When an SFSB becomes a Seam component, Seam doesn’t control how a containermanaged
persistence manager is bound to the SFSB. Thus, Seam can only tune the
lifetime of the extended persistence context by managing the lifetime of the SFSB.
(Keep in mind that this has no effect on a transaction-scope persistence context on
the SFSB.) However, there are several problems with this solution:

间接扩展存储上下文的范围
当SFSB成为SEAM部件,SEAM不控制绑定到SFSB的容器管理的存储管理器。因此SEAM只能通过管理SFSB的生命周期调整扩展存储上下文的生命周期。(记住这对SFSB上的事务范围的存储上下文没有影响)不管怎样,这一方案还是有几个问题:

■ It can only be used in an EJB environment (EJB session bean and JPA).
■ There are complex propagation rules2 for sharing the extended persistence
context across loosely coupled Java EE components.
■ The extended persistence context on an SFSB cannot be accessed easily from
JavaBean components.
■ Seam can’t control the flush mode of the persistence context on an SFSB (no
manual flushing).

只可用在EJB环境(EJB session bean and JPA)
复杂的传播规则来在松耦合的Java EE部件间共享扩展的存储上下文
SFSB上的扩展的存储上下文不能轻松地从JavaBean部件访问
SEAM不能控制SFSB上的存储上下文的清理模式(没有手动清理)

I’m not saying that you can’t make the conversation-scoped SFSB work. It may sufficiently
suit your needs. But if any one of these issues gets in your way, it calls for a
more flexible solution. Seam can assume the task of managing the persistence manager,
a feature known in Seam as a Seam-managed persistence context. Seam can even
go a step further by managing Java persistence end to end.

我不是说你不可以让会话范围的SFSB工作,这可能已满足你的需求。但是任何一个问题的出现会导致更复杂的方案。SEAM可以承担管理存储管理器的任务,这个特性叫做SEAM管理的存储上下文。SEAM甚至可以更进一步,端点到端点地管理Java persistence。

LETTING SEAM MANAGE THE PERSISTENCE CONTEXT
A Seam-managed persistence context is a Hibernate or JPA extended persistence manager
operating in isolation of Java EE. It’s application managed, which means that
Seam is responsible for instantiating it. After that, you use it just as you would a container-
managed persistence context in a Java EE component, except that it’s injected
using @In rather than @PersistenceContext. To give Seam control of creating the
persistence manager, you have to feed it a persistence unit, which you’ll learn to do in
section 9.3.

让SEAM管理存储上下文
SEAM管理的存储上下文是Java EE中的Hibernate or JPA扩展存储管理器。是应用管理的,这意味着SEAM有责任来初始化它。此后,使用起来就像Java EE部件中容器管理的存储上下文,除了它是用@In注入而不是@PersistenceContext。让SEAM控制来建立存储管理器,我必须给它一个存储单元,你会在9.3节中学到。

The Seam-managed persistence context is scoped to the conversation, which
means you tune its lifetime using the conversation propagation controls you learned
about in chapter 7. What sets the Seam-managed persistence context apart from its
container-managed counterpart is that it’s stored directly in the conversation, making
it a first-class citizen of the application, rather than being bound to the lifetime of a
single component. Consider that if an SFSB hosting an extended persistence context is
removed, the persistence context goes along with it. In contrast, a Seam-managed persistence
context remains available as long as the conversation is active, regardless of
which components come and go. The best part is that you can share the persistence
context between Java EE and non–Java EE components alike without having to worry
about complex (and tricky) propagation rules. Although the extended persistence
context in EJB 3 is a good start, Seam is better at handling this task.

SEAM管理的存储上下文设定为会话范围,这意味你要通过第7章学的会话传播控制调整其生命周期。使SEAM管理的存储上下文特别的地方是它直接保存在会话中。是应用中的一等公民,而不是绑定在单个部件的生命周期。考虑到如果主管着一个扩展存储上下文的SFSB被删除,存储上下文也一同去了。相比之下,一个SEAM管理的存储上下文保存可用,只是会话处理活动,而不在乎部件怎样。最棒的是你可以在Java EE和非Java EE部件间共享而不用关心复杂的传播规则。虽然EJB 3中扩展存储上下文是个好起点,SEAM是个更好的选择来完成这一任务。

Another nice feature of the Seam persistence infrastructure is that the support for
JPA and native Hibernate is parallel. The classes and configurations differ, of course,
but the overall architecture is the same, making it easy to switch between the two APIs
across different projects. This parallel support extends into the Seam Application
Framework, covered in the next chapter, which wraps the persistence manager and
provides additional built-in functionality to support persistence tasks.

SEAM存储框架的另一个好处是支持同时支持JPA and native Hibernate。当然,类和配置文件不同,但总的架构一样。这样很容易从两个不同项目的API间切换。这种平行支持扩展到了SEAM应用框架,下章介绍。其封装了存储管理器,提供了附加的内建功能来支持存储任务。

Regardless of who controls the persistence manager, the conversation is the key to
giving the persistence manager the respect it deserves. It’s really a perfect marriage.
Seam’s persistence strategy goes beyond just scoping the persistence manager. When
used in a Seam application, your persistence manager gets some upgrades. If you’re
using native Hibernate or Hibernate as the JPA provider, you get yet another set
of enhancements.

不管谁来控制存储管理器,会话是存储管理器的关键。这是一个完美的婚姻,SEAM的存储策略超越了存储管理器的范畴。当在SEAM应用中使用,你的存储管理器得到更多的更新。如果你在使用native Hibernate or Hibernate作为JPA的提供者,你会得到另一系列强化。

9.2 Enhancing the capabilities of the persistence manager
Seam proxies the persistence manager when it’s injected into a Seam component and
decorates it with extra functionality (i.e., the Decorator pattern). This section presents
these upgrades, starting with standard enhancements and then those specific
to Hibernate.

强化存储管理器的能力
当被注入到SEAM部件并添加额外功能(如Decorator 模式)时,SEAM可代理存储管理器。本节展现这些更新,从标准增强开始,然后是Hibernate专有的指定。

9.2.1 Seam’s standard enhancements
Given that Seam and Hibernate are both JBoss-supported frameworks, it should come
as no surprise that Hibernate gets special treatment in Seam. If you’re already using
Hibernate, this is good news. But Seam also offers some standard enhancements that
are available to any persistence provider:

SEAM标准增强
假如Seam and Hibernate都是JBoss支持的框架,不会奇怪Hibernate在SEAM中有一些特殊处理。如果你已使用Hibernate,这是个好消息。但SEAM也提供了一些标准的增强,对任何存储提供者都可用。

■ EL notation in persistence queries
■ Entity converter that allows entities to be used in UI select menus
■ Managed entity identity across session passivation

存储请求中的EL标识
实体转换器,允许实体用于UI选择菜单
管理实体标识across session passivation

Only the first two items will be covered in detail. The last item is a low-level feature
and it’s not necessary to concern yourself with the details. Let’s start with the crowd
favorite: the EL.

只 有前两条会细述。最后面的是底层特性,你不用关心其细节。来看看大众最爱:EL。

EL IN THE QL
As you have come to expect by now, Seam lets you use the EL all over a Seam application.
With persistence, the EL is back again. Seam supports the use of EL value expressions
within a JPQL or HQL query just as it does in JSF messages and log messages. This
holds true regardless of which persistence provider or API you’re using.

QL中的EL
如你所料,SEAM让你在应用中到处可以使用EL。在存储这里,EL又来了。SEAM支持在JPQL or HQL中使用EL值表达式,就像JSF消息及日志消息一样。而不管你用的是哪个存储管理器或API。

The value expressions provide an alternative to supplying positional or named
parameters in your queries and are evaluated when the query is executed. Let’s say
that in the registration process, you want to check to make sure that a username
isn’t taken:

值表达式提供另一个方法,允许在你的查询中使用定位或命名参数,当查询执行时被估值。就如在注册过程,你想检查以确认有没有用户名:

assert entityManager.createQuery(
"select m from Member m where m.username = #{newGolfer.username}")
.list() == 0;


Using the EL in a query provides a number of benefits. First, it serves as shorthand for
creating a named query parameter and assigning it a value. Also, since the value of the
expression is assigned using a query parameter (i.e., setParameter()), it’s properly
escaped, protecting the query from SQL injection. And any value that can be resolved
via the EL can be used as a parameter. That includes contextual variables as well as factory
and manager components. You see this combination used in the restriction
clauses of the Query component, covered in chapter 10. Finally, the inline EL syntax
moves all parameters into a string, making it possible to define the query in a string
constant or externalize it to a configuration file, where it can be assigned using component
configuration.

在查询中使用EL带来了一些好处。首先,可作为建立一个命名查询参数的简写,可指定给它一个值。同时,既然值表达式被用一个查询参数指定,(i.e., setParameter()),也可不用,以防止从SQL注入的查询。可以通过EL解析的值可用作参数。这包括上下文变量及工厂和管理部件。这种结合用在Query部件的查询分句。见第10章。最终,行内EL语法将所有参数移至一个串,使之可能在一个串常量中定义查询或具体到一个配置文件,其可由部件配置指定。

PICK ME OUT AN ENTITY
I bet that at one point or another, you’ve needed to present a list of entities in a form
field and let the user select one or more of them. This is one of those tasks JSF doesn’t
support out of the box (or most frameworks for that matter). It’s your job to convert
the instances into a string representation and then reinterpret the selections when the
form is submitted. Well, guess what? Seam offers to take care of it for you! The only
catch is that you must be using a Seam-managed persistence context and, ideally, a
long-running conversation.

将我从实体中取出
我确信你会在一个实体列表中显示一个列表而让用户选择其中之一。这是JSF不支持的。改换一个实例成一个串表示,然后当表单提交时,再翻译选项,这是你的工作。你猜怎样?SEAM可帮你处理,唯一要求是你必须使用SEAM管理的存储上下文,理想的是一个长期运行的会话。

Let’s assume that you need to assign a member a list of roles and you’ve prepared a
factory named availableRoles that returns a list of Role entity instances. (You cannot
use a Set with a UISelectMany component, only a parameterized List or an
array.) You can assign roles to a member as follows, nesting the UI
component tag to let Seam know to handle the conversion:

假定你需要指定一些角色列表,你已准备了一个工厂名为availableRoles,返回一个Role实体实例列表。(你不可以使用Set于UISelectMany部件,只能用参数化的List or an array)。你可以指定角色到一个成员如嵌套UI部件标签,让SEAM知道如何处理会话:




That’s all there is to it! When the view is rendered, the id of each entity (as defined by
its @Id property) is used in the value of a select option. On postback, the entity
instance is restored by passing the id to the persistence manager. For the selection to
be valid, its object identity must be equivalent to an instance in the collection. The
best way to guarantee this condition is to use a conversation-scoped collection and a
long-running conversation.

当view生成时,每个实体的ID(由@Id属性定义),被用在选项的值。对于postback,实体实例通过传送ID到存储管理器来保存。对于有效的选择,它的对象标识必须等同于集合中的实例。最好的保证这一条件的方式是使用一个会话范围的集合及一个长期运行的会话。

The component that handles the conversion for is named
org.jboss.seam.ui.EntityConverter. This component looks for a JPA persistence
manager according to a standard naming convention, described at the end of section
9.3.2. It’s possible to override the JPA persistence manager that the converter
uses, or configure the converter to use a Hibernate persistence manager. However,
the configuration changed between Seam 2.0 and 2.1. Let’s start with Seam 2.0.

处理会话的部件名为org.jboss.seam.ui.EntityConverter。这个部件根据标准的命名惯例找到JPA存储管理器,将在9.3.2描述。其可能超越转换器使用的JPA存储管理器,或配置转换器以使用Hibernate存储管理器。不管怎样,配置在Seam 2.0 and 2.1间有所变化。来从SEAM2.0开始。

In Seam 2.0, you can establish the persistence manager that the converter uses by
setting its entityManager property (for JPA) or session property (for Hibernate).
Here’s an example of an override when using JPA:

Seam 2.0,你可以通过设置entityManager属性(for JPA)或session属性(for Hibernate)建立转换器使用的存储管理器。下面是一个用JPA时的一个重载的例子:


#{em}


If you only want to override the persistence manager for a single conversion, you first
define a new component for the converter class in the component descriptor:

如果你只想为单个会话重载存储管理器,你首先为转换器类在部件描述文件中定义一个新的部件;

class="org.jboss.seam.ui.converter.EntityConverter">
#{em}

The name of this component is a valid JSF converter id, which you then supply to a JSF
converter tag that takes the place of within the select component:

这个部件的名字是一个有效的JSF转换器ID,随后你会提供给一个JSF转换器标签来换掉选择部件中的:

In Seam 2.1, a layer of indirection was introduced. Instead of the entity converter using
a persistence manager directly, it uses an entity loader component. In addition, two configuration
elements in the component namespace http://jboss.com/products/
seam/ui, prefixed as ui, were introduced to simplify the configuration. The entity
loader elements are and
for JPA and Hibernate, respectively. Here’s the same global override for JPA in Seam 2.1:

在Seam 2.1,引入了一个间接层,不再是直接使用存储管理器的实体转换器,它使用一个实体加载部件。另外,两个配置元素也被引入以简化配置。实体加载元素为 and 分别对应JPA和Hibernate。下面是一些Seam 2.1对JPAR 全局超载。

To define a custom entity converter, you must also define a custom entity loader:

要定义一个自定义实体转换器,你必须也定义一个自定义的实体加载器:


entity-loader="#{customEntityLoader}"/>

If all of this configuration is stressing you out, just remember that you can be configuration
free if you stick to the defaults. These overrides are just there if you need
them.

如果这些配置让你不自在,只要记住你是可以不用配置的,只用默认就可以。超载只中需要时才会用到。

NO THANKS, HIBERNATE
Before moving on to the Hibernate extensions that Seam exposes, I want to discuss
Seam’s JPA extension manager and how it affects using alternate JPA providers. Seam
uses a built-in component named persistenceProvider to transparently tap into vendor-
specific JPA extensions, such as Hibernate’s manual flushing, allowing Seam to
leverage the strengths of the persistence provider while respecting your choice to use
JPA. As its JavaDoc states, “The methods on this class are the TODO list for the next
revision of the JPA specification.”

不客气
在转向Hibernate扩展前,我想先谈谈SEAM的JPA扩展管理器,及它怎样影响使用其它JPA提供者。SEAM使用一个名为persistenceProvider的内建部件来透明地引入到供应商指定的JPA扩展。如Hibernate的手动清理。JavaDoc声称:“本类中的方法是下一版的JPA规范的TODO”

The only trouble with this component is that in Seam 2.0, it has a strong affinity for
Hibernate. If the Hibernate JARs are present on the classpath, Seam automatically
assumes that Hibernate is the JPA provider. To reverse this assumption and prevent
Seam from trying to use Hibernate extensions, add the following configuration to the
component descriptor:

这个部件的唯一麻烦是在SEAM2.0中,与Hibernate有强关联。如果Hibernate JARs出现在类路径,SEAM自动将Hibernate当作JPA提供者。要改变这个假定防止SEAM使用Hibernate扩展,增加如下配置到部件描述文件:

class="org.jboss.seam.persistence.PersistenceProvider"/>

Seam 2.1 switched to using runtime detection of the JPA provider by consulting the
persistence manager, thus making this override unnecessary. Let’s check out what
extensions are used if it is Hibernate.

Seam 2.1转变为使用运行时向存储管理器查询来检测,因此让重载不再必要。让我们来看看如果是Hibernate,会用什么扩展。

9.2.2 Letting Hibernate shine through
As I mentioned in chapter 8, Hibernate has several nice extensions that Seam can elegantly
expose to your application even if you’re using JPA. Here are the most notable
extensions:
■ Postquery filters
■ Hibernate Search
■ Manual flushing of the persistence context

正如第8章提到的,Hibernate有几个很好的扩展,如果你用的是JPA,SEAM可以暴露给你的应用程序。下面是最值得关注的:
后请求过滤器
Hibernate Search
存储上下文的手动清理

This section focuses on the first two features, as well as how to elegantly expose the
Hibernate Session. An entire section, section 9.4, is dedicated to the last feature and
how it relates to application transactions.

本节关注于前两个特性,及如何巧妙地暴露Hibernate Session。9.4节,描述最后一个特性及其如何关联到应用事务。

FILTERING THE QUERY RESULTS
Although it’s perhaps not the first feature you’ll use in Hibernate, if the need arises, it’s
nice to know that Hibernate supports filtering of the query results for a given Session.
This feature is useful for regional filtering and redacting sensitive data. Best of all, you
can apply it without touching Java code. Instead, you define filters using XML in the
component descriptor. This feature is only available if you’re using a Seam-managed
persistence context. Consult the Hibernate reference documentation for details on
how to define filters.

过滤请求结果
虽然可能不是你使用Hibernate中的第一个属性,如果产生了需求,Hibernate支持过滤针对给定Session的查询结果。这一特性对于分区过滤器和修订敏感数据很有用。最好的一点是你可以不用碰Java代码。而是在部件描述文件中使用XML。这一特性只在你使用SEAM的存储上下文时才可用。如何定义过滤器的更多细节,参阅Hibernate参考文档。

But why filter when you can search? That’s what Hibernate Search is all about.

关于为什么过滤及什么时候查询,是Hibernate Search要管的事。

CALLING ON HIBERNATE SEARCH
For more sophisticated searching, and to take load off the database, you can use
Hibernate Search, a Hibernate extension that can perform Lucene-based full text
search queries against the domain model. When the Hibernate Search libraries are
present on the classpath (consisting of hibernate-search.jar, hibernate-commonsannotations.
jar, and lucene-core.jar), Seam proxies the persisten1ce manager, wrapping
it with Hibernate Search capabilities. If you’re using Hibernate, the Session is
wrapped in a FullTextSession; if you’re using JPA, the EntityManager is wrapped in
a FullTextEntityManager. Hibernate Search is available even when you’re using a
Java EE container-managed EntityManager (i.e., @PersistenceContext).

调用HIBERNATE SEARCH
为了做更复杂的搜索,并降低数据库的压力,可以使用Hibernate Search,一个Hibernate扩展,针对域模型的基于Lucene的全文搜索。当Hibernate Search库出现在类路径,(consisting of hibernate-search.jar, hibernate-commonsannotations.jar, and lucene-core.jar),SEAM代理存储管理器,封装了Hibernate Search能力。如果你使用Hibernate,Session会包含进FullTextSession,如果使用JPA,EntityManager被包含进FullTextEntityManager.当你使用Java EE容器管理的EntityManager时(i.e., @PersistenceContext),Hibernate Search可用,

To use Hibernate Search, you either downcast to the full-text variant when you
need its features or, if you’re using a Seam-managed persistence context, just inject it
directly using the appropriate property type. Here, we search for golf courses using a
Lucene query:

要使用Hibernate Search,当你需要它的特性,你或者应顺从其全文变体。如果你使用SEAM管理的存储上下文,直接使用适应的属性类型注入它。这里,我们用Lucene查询来查找高尔夫课程:

@Name("courseSearch")
public class CourseSearchAction {
@In private FullTextEntityManager entityManager;
@Out private List searchResults;
public void search(String searchString) {
org.apache.lucene.query.Query luceneQuery =
new MultiFieldQueryParser(new String[] {"name", "description"},
new StandardAnalyzer()).parse(searchString);
javax.persistence.Query query = entityManager
.createFullTextQuery(luceneQuery, Course.class);
searchResults = (List) query.getResultList();
}
}

Of course, to query entities with Hibernate Search, you need to apply the Hibernate
Search annotations to your entity classes and add the indexer settings to the persistence
unit descriptor. A minimal configuration consists of an index storage provider
and index location, shown here for JPA (/META-INF/persistence.xml):

当然,用Hibernate Search查询实体,需要应用Hibernate Search annotations到你的实体类并增加索引设定器到存储单元描述文件。一个索引存储提供者和索引定位的最小的配置(for JPA)(/META-INF/persistence.xml):


...
value="org.hibernate.search.store.FSDirectoryProvider"/>
value="/home/twoputt/indexes/open18-index"/>

There’s no way to do Hibernate Search justice in this small amount of space. Besides,
Seam simply handles the task of wrapping the full-text search persistence manager
around the native one. From there, it’s out of Seam’s hands. I encourage you to grab a
copy of Hibernate Search in Action (Manning, 2008) to learn how to use this extremely
powerful feature of Hibernate.

这个小空间里没法判断Hibernate Search。SEAM简单地在原生存储管理器外面包装了一个全文查找存储管理器。从那起,SEAM不再经办。我建议弄一个Hibernate Search in Action (Manning, 2008)来学习Hibernate的这一超强特性。

While Seam’s role as liaison between JPA and the underlying Hibernate API is a
desirable abstraction and usually fishes what you need out of Hibernate, there may be
times when you have to work directly with the Hibernate Session. Fortunately, Seam
offers a neat trick.

SEAM的角色是JPA and the underlying Hibernate API之间的联络抽象,经常从Hibernate中抓取出你需要的实现。现在可以直接进入Hibernate Session,SEAM也提供了一个很好的路径。

GETTING DOWN TO HIBERNATE
When you’re using JPA, you can always get down to the provider interface by calling
the getDelegate() method on the EntityManager instance. But you have to perform
a cast that makes an assumption about the underlying JPA provider:

亲临HIBERNATE
当你使用JPA,你总是可以在EntityManager实例调用getDelegate()方法来使用提供商的接口。但还是要做一个cast。

Session session = (Session) entityManager.getDelegate();

You can define a factory in Seam to hide the cast:

你可以在SEAM中定义一个工厂来在隐藏CAST:

auto-create="true"/>

You then use the @In annotation to inject the value of this factory into your component:

随后可以使用@In在你的部件中注入这一工厂:

@In private Session hibernateSession;

One reason you might need the Hibernate Session is to check if there are modified
entities in the persistence context:

需要使用Hibernate Session的一个原因是去在存储上下文中检查是否有修改了的实体:

boolean dirty = hibernateSession.isDirty();

Hopefully these upgrades motivate you to use the Seam-managed persistence components.
In the next section, you’ll learn to set up a persistence unit and persistence manager
in Seam. I present the JPA configuration followed by Hibernate configuration. If
you’re only interested in one of the frameworks, you can skip over its complement.

这种升级动机促使你使用SEAM管理的存储部件,在下一节,你会学到在SEAM中设置存储单元和存储管理器。我在Hibernate配置后给出JPA配置。如果你人关心一个,可跳到对应位置。

9.3 Setting up a persistence unit in Seam
In the previous chapter, you learned how to prepare a persistence unit descriptor for
JPA (META-INF/persistence.xml) and one for Hibernate (hibernate.cfg.xml), which
you’ll use in this section to load JPA and Hibernate, respectively. While the Java EE
container can find the JPA persistence unit descriptor on its own, Seam requires some
direction in locating a persistence unit. Seam’s persistence management is capable of
bootstrapping the persistence unit, but it’s not required. You can also configure Seam
to use the persistence unit runtime managed by the Java EE container, which only
applies to JPA, or, as you’ll learn in chapter 15 (online), Seam can retrieve a persistence
unit runtime that’s managed by the Spring container.

在SEAM中设置存储单元
前一章,你已学到了如何为JPA准备存储单元描述文件(META-INF/persistence.xml),(对应Hibernate的是hibernate.cfg.xml)。用它们来加载JPA and Hibernate。Java EE容器可以自行发现JPA存储描述文件,SEAM需要一些指导来定位存储单元。SEAM的存储管理器可以开启一个存储单元,但这不是必须的。你也可以配置SEAM使用存储单元在运行时被Java EE容器管理。这只应用于JPA,见第15章(online)。SEAM也可以运行时检索由Spring容器管理的存储单元。

I start by introducing you to Seam’s built-in components that load and manage
either a JPA or Hibernate persistence unit, then move on to configuring them.

我会你介绍SEAM内建的部件,可加载和管理JPA or Hibernate存储单元,然后是如何配置它们。

9.3.1 Seam’s persistence manager factories
Seam provides manager components for bootstrapping JPA and Hibernate persistence
units. I refer to these components, which wrap the runtime configuration
object of the persistence unit, as Seam-managed persistence units. Table 9.1 shows the
mapping between each Seam-managed persistence unit and the persistence manager
factory it manages.

SEAM存储管理工厂
SEAM提供管理部件来启动JPA and Hibernate存储单元。我倾向使用这些部件,封装了存储单元的运行时配置对象。如SEAM管理的存储单元。见表9.1。列出了SEAM管理的存储单元和其管理的存储单元工厂。

The Manager design pattern allows Seam to tie the life cycle of the underlying persistence
manager factory to that of an application-scoped Seam component. Each of the
two components listed in table 9.1 has a @Create method, which starts the persistence
manager factory, and a @Destroy method, which closes it. The components initialize
on application startup as directed by the @Startup annotation.

管理者设计模式让SEAM绑定底层存储管理器工厂的生命周期到应用范围的SEAM部件。这两个部件(列于表9.1)都有@Create方法,用于启动存储管理工厂,@Destroy用于关闭。部件的初始化使用@Startup。

Since the Seam-managed persistence units are manager components, they resolve
to the value they manage, which is the persistence manager factory. Thus, when a
Seam-managed persistence unit is injected into a property of a Seam component, the
property’s type must be that of the persistence manager factory. Assuming the name of
the JPA persistence unit component is entityManagerFactory, it’s injected as follows:

因为SEAM管理的存储单元是管理器部件,它们解析其负责的值,是实体管理器工厂。因此当一个SEAM管理的存储单元注入到SEAM部件的属性,属性的类型必须是实体管理器工厂。假定JPA存储单元部件的名字为entityManagerFactory,注入如下:

@In private EntityManagerFactory entityManagerFactory;

For Hibernate, if the component is named sessionFactory, the injection looks like
this:

对于Hibernate,如果部件名为sessionFactory,注入为:

@In private SessionFactory sessionFactory;

The Seam-managed persistence unit components are actually just component templates,
meaning that neither has a @Name annotation. To actualize them as Seam components,
you must declare them in the component descriptor. Only then will the
persistence manager factory be loaded.

SEAM管理的存储单元部件只是个部件模板,意味着没有@Name。将其应用为SEAM部件,你必须在部件描述文件中声明,这样存储管理工厂才会被加载。

As with all of the built-in Seam components, Seam provides a component
namespace to ease the XML configuration burden. Seam’s persistence components
fall under http://jboss.com/products/seam/persistence, aliased as persistence
throughout this section. With the namespace declaration in place, let’s see how this
component is configured in the case of JPA and Hibernate.

有了所有的内建SEAM部件,SEAM提供了部件命名空间。本节中用别名persistence。有了名字空间,再让我们看看部件是怎么在JPA和Hibernate中控制。

BOOTSTRAPPING A JPA ENTITYMANAGERFACTORY
The component definition for the Seam-managed persistence unit must include both
a name and a reference to a persistence unit. Let’s assume you have a JPA persistence
unit named open18 defined in META-INF/persistence.xml as follows:

启动一个JPA实体管理器工厂
SEAM管理的存储单元的部件定义必须必须包括名字和存储单元和参考。假定你有一个JPA实体单元名为open18,定义在META-INF/persistence.xml:


...

For that, you declare the following declaration in the component descriptor:

为此,你在部件描述文件中声明:

persistence-unit-name="open18"/>

If the persistence-unit-name attribute is excluded from the component definition,
the name of the component is used as the persistence unit name, which in this case
would be entityManagerFactory.

如果persistence-unit-name属性被从部件定义中排除,部件名被用作实体单元名,此种情况下为entityManagerFactory。

That’s pretty much all there is to it! Internally, Seam uses the persistence unit
name to create an EntityManagerFactory as follows:

内部,SEAM使用存储单元名建立 个EntityManagerFactory如下:

EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("open18");

To have Seam defer loading of the persistence unit until it’s needed, perhaps for a
quicker deployment turnaround, you can disable the startup behavior of this
component:

让SEAM延迟加载存储单元直到真正需要之时(如一个快速部署),你可以禁用这个部件的startup行为:

persistence-unit-name="open18" startup="false"/>

JPA can accept vendor-specific properties for a persistence unit. Typically these properties
are defined inside the element in the persistence unit descriptor.
In Seam, you have the option of defining these properties on the manager component
itself:

JPA存储单元可以接受提供商指定的属性。典型地这些属性定义在存储单元描述文件元素。在SEAM中,你可以在管理部件定义这些属性:

persistence-unit-name="open18">

hibernate.show_sqltrue

Supplying these properties using Seam’s component configuration feature gives you
the flexibility to tune them for a specific environment by using a replacement token
or value expression as the property’s value. See chapter 5 for more details.
The component that loads the Hibernate configuration is a touch more
sophisticated.

使用SEAM部件配置特点来提供这些属性,给你提供了弹性,使用一个替代的令牌或值表达式作为属性值来指定环境,详见第5章。
加载Hibernate配置文件的部件更复杂些。

BOOTSTRAPPING A HIBERNATE SESSIONFACTORY
Hibernate is configured in much the same way as JPA, only instead of providing a persistence
unit name, you indicate the location where the Hibernate configuration
resides on the classpath. If the configuration file is named according to Hibernate’s
convention, you don’t even need to specify the file’s location. Hibernate automatically
looks for hibernate.cfg.xml (as well as hibernate.properties) at the root of the classpath
when it loads, unless told otherwise. In this default case, the component definition
is specified as follows:

启动一个HIBERNATE SESSIONFACTORY
Hibernate的配置与JPA基本相同,只是不是提供一个实体单元名,你指定Hibernate配置文件存在的位置。如果配置文件命名依照Hibernate规范,你甚至无须指定文件位置。Hibernate在其加载时,自动在类的跟路径定位hibernate.cfg.xml(及hibernate.properties)。在这种默认的情况,部件的指定如下:

Internally, Seam loads the Hibernate SessionFactory as follows:

在内部,SEAM加载Hibernate SessionFactory如下:

SessionFactory sessionFactory =
new AnnotationConfiguration().configure().buildSessionFactory();

If the name of the configuration file doesn’t follow the Hibernate convention, perhaps
because you’re loading a second Hibernate persistence unit, you must specify
the location of the Hibernate configuration file:

如果起名没有遵循Hibernate规范,可能是因为你正装载第二个Hibernate存储单元,你必须指定Hibernate配置文件的位置。

cfg-resource-name="hibernate-teetime.cfg.xml"/>

In this case, the load performed internally changes to

在这种情况下,加载会内在地变化到:

SessionFactory sessionFactory =
new AnnotationConfiguration().configure(cfgResourceName)
.buildSessionFactory();


With Hibernate, you have the option of configuring the persistence unit entirely in
the component descriptor, specifying the Hibernate configuration properties3 using
component configuration properties:

Hibernate中,你可以选择完全在部件描述文件中配置存储单元,用部件配置属性指定Hibernate配置属性:



hibernate.connection.driver_class
org.h2.Driver
hibernate.connection.username
open18
hibernate.connection.password
tiger
hibernate.connection.url
jdbc:h2:/home/twoputt/databases/open18-db/h2

You have to decide you want whether to define the Hibernate configuration properties
in the Hibernate persistence unit descriptor or the Seam component descriptor. If the
cfg-resource-name attribute is present, the element is ignored.

你必须决定是在Hibernate存储单元描述文件中定义Hibernate配置属性还是在SEAM部件中定义。如果有cfg-resource-name属性存在,元素会被忽略。

The Hibernate persistence unit component offers a rich set of configuration properties
for supplying the location of mapping artifacts. The properties are defined using
the , , , ,
and elements. Consult the Hibernate documentation for information
on using these settings.

Hibernate存储单元部件提供一套丰富的配置属性来支持人工映像定位。属性定义可使用, , , ,and 这些元素。详情请咨Hibernate文档。

Seam’s components are just one option you have for loading a persistence unit. In
section 9.3.3, you’ll learn how to work with a persistence manager factory stored in
JNDI, a less Seam-centric approach. We’ll forge ahead for now using the Seammanaged
persistence unit as the source from which a Seam-managed persistence context
is created.

SEAM的部件只是装载一个存储单元的一个选择。在9.3.3,你会学到怎样同存储在JNDI中的存储管理工厂工作,这是一个不太以SEAM为中心的方式。我们先用SEAM管理的存储单元作为源,从这里建立SEAM管理的存储上下文。

9.3.2 Seam-managed persistence contexts
Having just registered a persistence manager factory, you could use it to create your
own application-managed persistence manager. But why manage this resource yourself
when Seam can take the burden off your shoulders? Once again, Seam uses
a manager component to handle this task. However, in this case the persistence
manager is allocated when the Seam-managed persistence context is retrieved from
the Seam container rather than being initialized at application startup like the persistence
manager factory.

SEAM管理的存储上下文
刚刚注册一个实体管理工厂,你可以使用它来建立你自己的应用管理的存储管理器。但既然SEAM可以为你做,为什么你还要自己管理这个资源呢?另外,SEAM使用一个管理部件来处理这个任务。不管怎样,在这种情况下,当SEAM管理的存储上下文是从SEAM容器中检索的而不是像存储管理工厂那样在应用开始时初始化的,存储管理器被分配。

When the Seam-managed persistence context is created, it’s stored in the active
conversation context—regardless of whether the conversation is temporary or longrunning.
The life cycle of the underlying persistence manager is then bound to the
lifetime of the conversation. When the conversation ends, Seam calls the close()
method on the persistence manager to close the persistence context. Table 9.2 shows
the persistence manager that Seam creates for each persistence framework.

当SEAM管理的存储上下文建立后,它保存在活动的会话上下文,不管是否会话是临时的还是长期运行的。底层的存储管理器的生命周期随后绑定到会话的生命周期。当会话结束,SEAM在存储管理器上调用close()方法来关闭存储上下文。表9.2显示了SEAM为每个存储框架建立的存储管理器。

Once the Seam-managed persistence context is defined (which will be covered shortly),
you can inject it into the property of another Seam component using the @In annotation.
The target property’s type is expected to be that of the persistent manager. Assuming
the name of the JPA component is entityManager, it’s injected as follows:

一旦SEAM管理的存储上下文被定义(随后会讲到),你可以用@In注入它到另一个SEAM部件的属性。目标属性的类型应该是存储管理器期望的。假定JPA部件的名字是entityManager,会如下注入:

@In private EntityManager entityManager;

Remember that this injection can occur at any layer in your application, not just on a
JSF action bean component as you see in many of the examples in this book.

记住,这个注入可发生在你的应用的任何层,不只在JSF action bean部件,虽然本书的很多例子是那样的。

For Hibernate, where application-managed persistence contexts are your only
option, the injection is performed as follows, assuming the component is named
hibernateSession:

对Hibernate来说,应用管理的存储上下文是你唯一的选择,注入如下进行:假定部件名为hibernateSession:

@In private Session hibernateSession;

If a JTA transaction is active when the Seam-managed persistence context is injected,
the persistence manager is enlisted in that transaction. In addition, if you’re using
Hibernate, either as a provider for JPA or natively, and Hibernate filters are defined on
the component, they’re applied to the persistence manager at this time.

当SEAM管理的存储上下文被注入时,如果一个JTA事务是活动的,存储管理器被引入这个事务。另外,如果你在使用Hibernate,或者另一个JPA提供者,或原生的,或定义于部件上的Hibernate过滤器,这时它们被应用到存储管理器。

Like the Seam-managed persistence units, the Seam-managed persistence contexts
are component templates. To make them available to the application, they must be
activated using the component descriptor. Let’s see how they’re defined.

就像SEAM管理的存储单元,SEAM管理的存储上下文是一个部件模板。为了在应用上可用,它们必须使用部件描述文件激活。来看看是如何定义的。

DEFINING A MANAGED PERSISTENCE CONTEXT
When you declare the Seam-managed persistence context, you must supply a name and
a reference to a persistence manager factory. If you’ve configured a Seam-managed persistence
unit named entityManagerFactory that loads the JPA persistence unit, you
inject a reference to it as a value expression into the Seam-managed persistence context:

定义一个管理的存储上下文
当你声明SEAM管理的存储上下文,你必须提供一个名字和一个到存储管理器的参考。如果你配置一个SEAM管理的存储单元,名为entityManagerFactory,其加载JPA存储单元,你注入一个参考到它,就像值表达式到SEAM管理的存储上下文:

entity-manager-factory="#{entityManagerFactory}" auto-create="true"/>

Likewise, if you’ve configured a Seam-managed persistence unit named session-
Factory to load the Hibernate persistence unit, you inject the corresponding value
expression:

然而,如果你配置一个SEAM管理的存储单元,名为session-Factory,来加载Hibernate存储单元,你注入一个对应的值表达:

hibernate-session-factory="#{sessionFactory}" auto-create="true"/>

In the previous two declarations, the auto-create attribute is set to true. By default,
the Seam-managed persistence context components are defined with the autocreate
feature disabled. By enabling this feature, you can inject these components using an
@In annotation without having to supply the create attribute.

在前两个声明,auto-create属性被设置为true。默认下,SEAM管理的存储上下文部件的定义是autocreate特性为disabled的。通过启用这一特性,你可以使用@In注入这一部件,而不用必须支持create属性。

TIP
If you assign the name entityManager to the JPA persistence manager
and session (or hibernateSession as of Seam 2.1) to the Hibernate
persistence manager, you can save yourself a couple of keystrokes. Seam
uses these names in several of its modules to look up the Seam-managed
persistence context, unless an override is specified.

如果你指定entityManager到JPA存储管理器及session(如果是Seam 2.1,则为hibernateSession)到Hibernate存储管理器,你可以省去一些打字量。SEAM在几个模块中使用这些名字来查询SEAM管理的存储上下文,除非被指定了重载。

So far you’ve established Seam-managed persistence contexts for both JPA and Hibernate,
letting Seam handle the entire process. Although there are times when this is
the most convenient approach, Seam won’t always be in command. Fortunately, Seam
is able to look to JNDI and use a persistence unit waiting there, loaded and ready.

既然你为JPA及Hibernate都建立了SEAM管理的存储上下文,让SEAM来处理这些实体过程。虽然这经常是最方便的方式,SEAM不是总用。SEAM可以去JNDI及让存储单元等在那儿,子弹上膛。

9.3.3 Sharing the persistence manager factory through JNDI
Seam’s JPA persistence manager component is capable of obtaining a reference to a
JPA persistence unit loaded by the Java EE container, if made available through JNDI.
Seam can also retrieve a Hibernate SessionFactory stored in JNDI for use in its
Hibernate persistence manager component. We explore how to make these resources
available in JNDI and how to get Seam to use them, starting with the native Java
EE integration.

通过JNDI来分享存储管理工厂
如果通过JNDI可行,SEAM的JPA存储管理部件可以获得一个对由Java EE加载的JAP存储单元的参考。SEAM也可以检索一个保存在JNDI的Hibernate SessionFactory,以在它的Hibernate存储管理部件中使用。我们浏览怎样使这些资源在JNDI可用,及怎样让SEAM使用它们,开始于原生Java EE集成。

PERSISTENCE UNIT REFERENCES
There’s no use loading a JPA persistence unit if one’s already available, which is the case
in a standard Java EE environment. However, the Java EE container doesn’t expose the
EntityManagerFactory by default, which means it’s not published to JNDI. This isn’t
necessary for using the @PersistenceContext annotation on a Java EE component. But
now, you need to allow Seam to obtain the persistence manager factory from the Java
EE container. That requires the extra step of declaring it as a resource reference.

存储单元参考
如果已有一个加载了,加载一个JPA存储单元不再有用。这是标准Java EE中的情况。不管怎样,Java EE容器默认下不会暴露EntityManagerFactory。这意味它不会发布到JNDI。在Java EE中使用了@PersistenceContext后就不再有此必要。但现在你需要让SEAM来从Java EE容器来获得存储管理工厂。这需要额外的步骤将其声明为资源的考虑。

The persistence unit reference can be defined in either the web.xml descriptor
using the element or in a @PersistenceUnit annotation on
a Java EE component. I cover only the XML-based configuration here. The reference
associates a JNDI name in the java:comp/env namespace with the persistence unit
name, as follows:

存储单元参考可以在web.xml中用或Java EE部件中用@PersistenceUnit定义。这里我只说基于XML的。参考关联到一个名字空间java:comp/env中的JNDI名,

In order for this reference to be usable, the persistence unit descriptor and entities
must be on the classpath of a WAR or packaged as a persistence archive4 (PAR) and
placed in the lib directory of an EAR. When a PAR is in the lib directory of an EAR, its
persistence units are visible to the WAR and the EJB JAR. If the persistence unit is packaged
inside an EJB JAR, it’s private and therefore not visible to the web context or
Seam (JBoss AS is an exception).

为了这个参考可用,存储单元描述文件和实体必须位于WAR类路径,或是存储包(packaged as a persistence archive (PAR)),并放入EAR的lib目录。当PAR是在EAR的lib目录,其存储单元即对WAR 和EJB JAR可见。如果存储单元在EJB JAR包中,则为私有的,因此对WEB上下文或SEAM不可见(JBoss AS 是外例外)。

A reference to the EntityManagerFactory for this persistence unit is obtained by
looking up the qualified JNDI name java:comp/env/open18/emf in the Initial-
Context. Of course, you don’t have to perform this lookup yourself since Seam can
accept a JNDI name in the configuration of the persistence manager, replacing the
entity-manager-factory attribute:

对于这个存储单元,一个对EntityManagerFactory的参考从Initial-Context对合格的JNDI名java:comp/env/open18/emf中查询获得。
当然,你不用自己执行这个查询,因为SEAM可从存储管理器的配置中接受一人JNDI名,取代entity-manager-factory属性:

persistence-unit-jndi-name="java:comp/env/open18/emf"
auto-create="true"/>

This whole setup assumes you’re working in a Java EE 5–compliant environment, and
JBoss AS 4.2 is not. Until JBoss AS 5.0 is rolled out, the means of binding to JNDI and
the JNDI naming convention are different.

整个setup假定你是工作在Java EE 5兼容的环境,而不是JBoss AS 4.2。在JBoss AS 5.0面世前,绑定到JNDI与JNDI命名惯例是不同的。

DEALING WITH JNDI IN JBOSS AS
JBoss AS 4.2 doesn’t implement the entire Java EE 5 specification, coming up short in
the area of persistence archives. It doesn’t support the use of persistence unit references,
as described earlier. Your only option is to instruct Hibernate to bind the
EntityManagerFactory to JNDI at runtime by adding a special JNDI Hibernate property
to the persistence unit configuration:

在JBOSS AS中处理JNDI
JBoss AS 4.2没有完全实现整个Java EE 5规范,在存储管理这时就不完整。它不支持存储单元参考的使用,你唯一的选择是构建Hibernate来绑定EntityManagerFactory到JNDI,在运行时,通过增加特殊的JNDI Hibernate 属性到存储单元配置:

This trick only works, however, if Hibernate is the persistence provider. It also
depends on Hibernate being able to write to JNDI at runtime, which isn’t supported
in all environments (see the accompanying sidebar). Also note that this JNDI name
isn’t placed in the java:comp/env namespace5 but rather in the global JNDI
namespace, so the reference to the EntityManagerFactory is obtained by looking up
the JNDI name verbatim:

这种办法只在Hibernate是存储提供者时有效。另外也依赖于Hibernate可在运行时写JNDI,这并不被所有环境支持。同时还要注意,JNDI名字没有放在java:comp/env名字空间,而是放在了全局JNDI名字空间,所以对EntityManagerFactory的参考可以从JNDI名字逐字地得到。

Unfortunately, the situation with JBoss AS is even grimmer. JBoss AS 4.2 only loads persistence
units if they’re packaged as an EJB JAR inside an EAR and declared as an EJB
module in the EAR’s application.xml descriptor. If your configuration is different, you
need to have Seam bootstrap the persistence unit before it can be bound to JNDI. The
same goes if you deploy your application to a servlet container such as Tomcat or Jetty.
A Hibernate SessionFactory is bound to JNDI using the same runtime technique.

不幸地,和JBoss AS一起时,情况更糟。如果它们被打包在EAR中的EJB JAR和在EAR的application.xml中声明为EJB模块,JBoss AS 4.2会只加载存储单元。如果你的配置是不同的,我需要让SEAM在它被绑定到JNDI前启动存储单元。同样的事还会发生,如果你部署你的应用到一个servlet容器,如Tomcat or Jetty。使用同样的技术,Hibernate SessionFactory被绑定到JNDI。

Writing to the JNDI registry is not so easy
JNDI namespaces, and the rules regarding which namespaces can be modified at
runtime, vary widely across application servers. For instance, JBoss AS supports the
namespace java:/, which isn’t available on any other server. GlassFish doesn’t permit
the application to modify the java:comp/env namespace. Tomcat disables writing
to the JNDI registry at runtime entirely. Keep in mind that writing to the JNDI registry
is only necessary if the application server doesn’t support persistence unit references
or if you want to bind a Hibernate SessionFactory to JNDI.

写到JNDI注册并不易
JNDI名字空间及规则,依赖于哪个名字可在运行时被修改,这会因应用服务器的不同而很不同。如JBoss AS支持名字空间java:/,这在其它服务器上就不可用。GlassFish不允许应用修改java:comp/名字空间。Tomcat禁止在整个运行时写JNDI注册。记住,写JNDI注册只在服务器不支持存储单元参考或不想绑定一个Hibernate SessionFactory到JNDI时才需要。

GETTING THE HIBERNATE SESSION INTO JNDI
Hibernate at least has an excuse for JNDI tricks since it doesn’t answer to a standard.
The way that Hibernate is configured to bind to JNDI is so subtle that it’s often overlooked.
You simply add the name attribute to the node in the
Hibernate configuration, and that value is used as the global JNDI name to which
to bind:

让HIBERNATE SESSION进入JNDI
对于JNDI,Hibernate至少会有一个借口。因为它不标准。Hibernate配置为绑定到JNDI很精巧,以致常被忽略。你简单地增加name属性

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/21802202/viewspace-1023938/,如需转载,请注明出处,否则将追究法律责任。

转载于:http://blog.itpub.net/21802202/viewspace-1023938/

 类似资料: