SEAM IN ACTION 第8章
8、Understanding Java persistence
This chapter covers
■ Managing entities
■ Using transactions
■ Choosing between JPA and Hibernate
理解JAVA存储
管理实例
使用事务
在JPA或Hibernate间选择
Java persistence is the mechanism by which object-based entities are translated
between the Java runtime environment and a relational database. It’s undoubtedly
the most popular feature of the Java EE platform, perhaps even the Java language.
This popularity can be attributed to the fact that persisting data is central to nearly
all enterprise applications. For that reason, persistence is a core part of Seam. In
fact, you can’t get very deep into a Seam application without encountering it. As
you’re probably aware, you’ve been using Java persistence in the sample application
since chapter 2—though solely the Java Persistence API (JPA) variety.
JAVA存储是一种机制,面向对象的的实体可以从JAVA运行时环境翻译到数据库,无疑这是Java EE甚至JAVA语言最出名的特性。这个特性反应了存储数据是所以企业应用的中心这一事实。因为这一原因,存储是SEAM的核心部分。事实上,在没有遇到它之前,你还没有深入SEAM。你可能意识到,你在第二章的例子中已使用了JAVA存储。though solely the Java Persistence API (JPA) variety
This chapter provides a crash course in Java persistence and prepares you to use
it in Seam. The two frameworks covered are JPA—the standard persistence
mechanism in Java EE—and Hibernate—the popular open source persistence
framework–turned–JPA implementation, both of which Seam support out of the box.
Given the fact that these APIs, and Seam’s built-in components to support them, are
so similar, this chapter establishes a persistence terminology that can be used to address
them both in a general way. At the end of this chapter, I compare JPA and Hibernate and
you’ll learn whether it’s worth adhering to the Java EE standard or better to venture onto
the bleeding edge with Hibernate, or if it’s possible to have it both ways. Since you can’t
get far persisting data in the absence of explicit transaction boundaries, this chapter also
covers the role transactions play in the Java persistence mechanism.
本章对JAVA存储深入分析,让你在SEAM中使用它。涉及的两个框架是JPA(标准的Java EE存储机制)和Hibernate(流行的开源存储框架)。这两个都是SEAM天生支持的。这些API与SEAM内建部件很类似,本章使用存储术语可以用通用的方式描述它们。本章末尾,我比较JPA and Hibernate,你会看到坚持Java EE标准是否值得,或冒险使用未经验证的Hibernate,或兼而有之。因为在没有明确事务边界的情况下,存储数据也不会深入,所以本章也涉及JAVA存储机制中的角色事务。
One important point missing from the discussion in the previous chapter is the
role that the persistence context plays in the conversation. In this chapter, you’re
introduced to the persistence context, and I show you how to extend it across multiple
HTTP requests. In the next chapter, you’ll discover how Seam offers to manage the
extended persistence context, using the conversation as a vehicle, so you can align the
lifetime of the persistence context to the boundaries of a use case.
前一章没讲的一个重要的讨论是会话中存储上下文的角色。本章你认识存储上下文,也看看它怎样跨过多个HTTP请求。下一章,我们了解SEAM怎样借用会话来管理扩展的存储上下文,这使得你可以将存储上下文的生命周期与用例的边界统一起来。
Trying to cover all aspects of Java persistence in a single chapter would be impossible,
so the focus here is on understanding the concepts you need to know when using
it with Seam. Besides, a number of books are available that explain the fundamentals
of transactions and persistence using either JPA or Hibernate in tremendous detail. I
highly recommend Java Persistence with Hibernate (Manning 2007) to start, as well as
EJB 3 in Action (Manning 2007), JPA 101 Java Persistence Explained (SourceBeat 2008),
and Spring in Action, Second Edition (Manning 2007). That only scratches the surface
of what’s available.1 By the end of this chapter, you’ll be ready to decide which persistence
API to use and learn what Seam brings to the table with its own transaction and
persistence management.
在一章里讲完JAVA存储的所有方面是不可能的。所以这里的重点是理解概念。另外一些书可以帮助你理解JPA及Hibernate。本章末尾,你就可以决定使用哪个API。了解SEAM在事务传输和存储管理上给你带来的方便。
1 Java persistence principles
Persisting data, and doing it consistently and reliably, is vital to enterprise business
applications. But transactions and persistence are complex subjects. They are both
technically challenging—to the point of being academic—and they can be difficult to
manage and tune. The complexity is magnified by the fact that a lot of misinformation
exists out there. Once you start down the wrong path, it can be expensive and time
consuming to correct your approach. The goal of this section is to “reset” your view of
Java persistence and examine its architecture.
JAVA存储原则
统一、可靠地存储数据对于企业应用至关重要。但是事务和存储是复杂的任务,难于管理和调整。一旦误入歧途,就很难修正。本节的目的是复位你的JAVA存储的view并了解其架构。
1.1 Establishing expectations
Developers shouldn’t expect to sprinkle magic pixie dust on POJOs in hopes they will
become persistent. You have to understand the underlying mechanisms and spend a
respectable amount of time dedicated to getting the mappings to the database right.
Java persistence is intended to make the process of persisting objects to the database
easier, but the impression you get from reading many developer blogs is that Java
persistence is expected to do all the work. This shallow, magic pixie dust approach is
what got folks who spread fear, uncertainty, and doubt (FUD) about the capabilities
of Hibernate and JPA into such hot water in the first place.
建立异常
开发者不期望POJO能被保存。你必须理解底层的机制。花一段时间来正确地数据库映射。JAVA存储希望使对象映射的数据库更容易些。但你从开发者blogs了解到JAVA存储被希望做所有的事情。这使人们怀疑Hibernate and JPA有此能力。
In contrast to what may have been reported in blogs, these frameworks are stunningly
adept at handling and optimizing persistence operations. Sadly, developers are
doomed from the start because of problems that stem from the stateless architecture
of the frameworks that try to manage the persistence resources, not from poor or
careless application code. For instance, the persistence context is often scoped to the
thread-based (or database) transaction, or worse, each persistence operation. This
usage scenario is the nexus of the most frequently reported “bug” in Hibernate: the
unnerving LazyInitializationException. In this chapter and the next, you’ll learn
why this exception happens and how not to fear it anymore. In the process, you’ll discover
that the persistence context was intended to represent a unit of work (i.e., use
case) and should therefore be held open until that work is complete.
对比之下,这些框架出色地完成了存储处理和优化操作。不幸的是开发者注定会有无状态架构来管理存储资源带来的麻烦。例如,存储上下文经常定界为基于线程(或数据库)的事务,或更糟,界定于每个存储操作。这导致最常见的Hibernate "bug"--LazyInitializationException。本章及下一章,你会知道异常是怎样产生。在此过程中,你会发现存储上下文希望代表一个工作单元(用例),将会处于打开直到工作完成。
Throughout this chapter, you can expect to learn about not only Java persistence
but also the principles behind its design and how it is supposed to work. You’ll
then appreciate the vital enhancements that Seam weaves into Java persistence,
introduced in the next chapter. The definitions I present here are going to be integral
to the remainder of the book, where I’ll assume you know how to use the persistence
mechanism.
整个章节,你会了解JAVA存储及其原则,会开心SEAM对存储的增强(见下一章)。本书的剩余部分假定你已了解这里所讲的存储机制。
Fortunately for you, seam-gen sets up the persistence configuration so that you can
focus on learning the core Seam concepts right out of the gate. The basic seam-gen
configuration includes a data source connection pool, a persistence unit, a persistence
manager, and a transaction manager. In chapter 2, you used seam-gen to build a
set of entity classes and transactional components to manage the database by reverseengineering
the database schema. But you won’t always have seam-gen to do all the
work for you, so you need to take the time to learn how to get started with Java persistence
in a more hands-on manner and understand its moving parts.
幸运的是seam-gen构建了存储配置,你可以专注于学习SEAM核心概念。基本的seam-gen配置包括一个数据源连接池、一个存储单元、存储管理器、事务管理器。在第2 章,你使用seam-gen建立了一套实体类、反向工程生成的可管理数据库的事务部件。如果你不是总让seam-gen来帮你做一切,你就需要学会如何手工地开始一个Java存储。
1.2 The four pillars of Java persistence
From the perspective of the database, Java persistence is no different than any other
database client. It performs read and write queries—nothing more, nothing less.
However, from the developer’s perspective, Java persistence is so much more than
that. In fact, the whole reason that Java persistence was created (and when I say Java
persistence I am referring to object-relational mapping [ORM]) is to extract the SQL
out of the code and replace it with object manipulation. The database operations take
place transparently to reflect the changes in the state of the objects.
JAVA存储的四个立柱
从数据库的角度,JAVA存储与其它数据库客户端没有差别。做读与写的操作。然而从开发者的角度,JAVA存储要比这些多。事实上,JAVA存储产生的原因(当我说JAVA存储,我是在说ORM)从代码中抽取出SQL语句,替换成对象实现。数据库操作透明地反映对象状态的变化。
Don’t assume, though, that Java persistence was meant to shun SQL as an inferior
technology. Rather, the goal is to take the burden of performing that SQL off you, the
developer, a majority of the time and allow you to form an object representation of the
database that fits more cleanly with the rest of the object-oriented application. The four
pillars of Java persistence that form this abstraction over SQL are as follow:
■ Entities (entity classes)
■ The persistence unit (represented at runtime by a persistence manager factory)
■ The persistence manager
■ Transactions
毫无疑问,JAVA存储的目的就是要把SQL变成内部的技术。将操作SQL的负担去除。用来抽象SQL的JAVA存储的四个立柱是:
实体类
存储单元(运行时由实体管理工厂代替)
实体管理器
事务
NOTE
Java persistence encompasses both JPA and the native Hibernate API.
Hibernate shares a close resemblance to JPA and therefore the persistence
terminology introduced in this section applies to both frameworks.
When I present code, only the JPA classes are shown.
JAVA存储包括JPA和原生Hibernate API。Hibernate极似JPA,所以本书同时介绍这两个框架。当我示范代码,只显示JPA类。
Figure 8.1 illustrates the relationship between these constituents. The persistence unit
organizes and manages metadata, which maps entities to the database. The persistence
manager factory obtains the mapping metadata from the persistence unit and uses that
information to create persistence managers. The persistence managers are responsible
for moving entities between the Java runtime and the database, a process known as the
entity life cycle. Operations performed by the persistence manager should always be
wrapped within the scope of a transaction. A transaction can also encompass operations
performed by two or more persistence managers as a single atomic unit.
图8.1示例了这些要素的关系。存储单元组织和管理映射实体到数据库的元数据,存储管理器工厂从存储单元获得映射元数据,使用这些信息建立存储管理器,存储管理器负责在JAVA运行时和数据库间移动实体,这一过程对就实现生命周期。实体管理 器的操作将总是在事务的范围。事务可以包含两个或多个存储管理器的原子单元。
The fundamental goal of Java persistence is to move data between entity instances and
the database. You’ve already used entities quite extensively throughout this book.
Let’s quickly shed some light on what has already been at play.
JAVA存储的目录是在实体实例与数据库间移动数据。本书中你已大量使用实体了。来快速浏览一下其已经担当的角色。
2 Entities and relationships
Entities in an ORM tool, such as JPA or Hibernate, are the join point between the
application and the underlying database, transporting data between them, as illustrated
in figure 8.2. Because they are such a central piece of the application, the entities
should be treated as more than just dumb data holders. Seam allows you to bind
entity classes directly to a JSF view to capture form data, establish prototypes for new
实体和关系
实体在ORM工具(JPA or Hibernate)中,是应用与底层数据库的结合点,在其间传递数据。如图所示。因为这是应用的中心环节,实体将比哑数持有更复杂。SEAM让你直接绑定实体类到JSF view来获得数据,为新的瞬时实体建立原型,及在view中延迟加载数据。这些对象是跨越SEAM的多层的。
transient instances, and lazy-load data in the view. These objects transcend the layers
of a Seam application.
While the entities serve as a representation of the data stored in the database
tables, they don’t have to mimic the database schema. That gap is filled by the mapping
metadata.
当实体作为数据的代表存储到数据库表,不用模仿数据库的语句。这个间隙由映射元数据填补了。
2.1 Mapping metadata
The ORM tool gives you free reign to assemble your entity graph as you choose, perhaps
by following domain-driven design or other common object-oriented principles. You
then use the mapping metadata of the ORM tool to form-fit the classes to the database
schema. The flexibility that the mapping provides includes, but is not limited to, preventing
certain properties in the entities from being persisted to the database (using
@Transient), using different names for the properties that are mapped to their respective
columns (using @Column), organizing tables along an inheritance hierarchy (using
@Inheritance), subdividing a table across multiple entities (using @SecondaryTable),
or molding data from a single table into composite objects (using @Embedded). Naturally,
there are limits to how far you can stretch the mappings. If the mapping requirements
are too steep and the object model is rigid, you have to question whether the
database schema is serving its purpose of representing the domain of the business or
whether ORM is the right solution to your problem.
映射元数据
ORM工具给你自由组合你的实体图。可以遵循域驱动设计或其它公共面向对象原则。其后使用ORM工具的映射元数据去映射类及数据库语句。映射提供的弹性包括但不限于防止一些实体属性被保存到数据库(@Transient),属性与数据库表名不同(@Column),按继承来组织表(@Inheritance),跨多个实体切分表(@SecondaryTable),融合多个表于复合表(@Embedded)。自然地,在映射上会有一些限制。如果映射需求太多则对象模型就会太死板。这时你就要想想从代表域的角度是否合理或是不是应该使用ORM。
One of the benefits of having mapping metadata is that it can be used to export
the schema at runtime and have it build the database tables, foreign keys, and constraints
automatically. You’ve taken this approach for each entity that was added to
Open 18 since running seam generate in chapter 2. You might recall the following
two questions from the seam-gen questionnaire:
一个使用映射元数据的好处是可以在运行时导出数据库语句,可用来自动地建立数据库表、外键和限制。你可以在每个实体上使用第二章曾经seam generate用于Open 18的方法。你可以回忆下面两个来自seam-gen问题:
■ Are you working with tables that already exist in the database?
■ Do you want to drop and re-create the database tables and data in import.sql
each time you deploy?
是否数据库表已存在
是否要在每次部署时删除并用import.sql重建表
Had you answered no for the first question and yes for the second, you could’ve
started your application from existing entities alone. You’d generate the user interface
using the command seam generate-ui and Hibernate would build the database
each time the application starts. You should appreciate that mapping metadata can
either be the result of bottom-up development or consulted for top-down development
(to follow up on a point made back in chapter 2).
Let’s next explore how entities help make the task of managing persistence data
simpler, particularly related data.
你用seam generate-ui生成用户界面,Hibernate将每次在应用启动时建立数据库。可用自下而上的或自上而下的开发模式。
下面看看实体怎样帮助存储数据更容易。
2.2 Transitive persistence
One of the core benefits of entities in ORM is transparent association handling.
There are two sides to this feature. The first side is the read operations. Managed
entities can load associated entities on demand (a feature known as lazy loading) by
traversing them within the confines of an active persistence context (and ideally
within a transaction). The other side is the write operations. When an entity is
flushed to persistence storage, modifications to any associated objects are also processed
and synchronized with the database. When a managed entity is removed, the
removal may cascade into child entities, depending on the attributes in the mapping.
This process is referred to as transitive persistence.
株连(Transitive)存储
ORM中一个重要益处是对透明关系的处理。这个特性有两面,一个是读操作,在活动的存储上下文内,被管理的实体可以应招装载相关的实体(延迟加载),这对事务很方便。另一方面是写操作。当一个实体被持久化保存,关联的对象也同步到数据库。当被管理的实体被删除,依赖映射的属性,删除会级联到子实体。这个过程叫株连存储。
Entities can save you a lot of time, not because they shield you from SQL but
because they handle the majority of the grunt work necessary to store related objects
in a database. However, to use ORM effectively, you must manage the persistence context
and transactions appropriately—or confusion reigns.
实体可省去你很多时间,不是因为替你挡开了SQL,而是帮你处理了大量的关联存储操作。然而,要让ORM高效,你恰当地管理存储上下文及事务。
2.3 Bringing annotations to the persistence layer
If you’ve bought into the benefits of annotations, you’ll likely use them to configure
your entities. The standard Java persistence annotations (in the package javax.
persistence.*) work in both JPA and Hibernate. In addition to the standard JPA
annotation set, Hibernate has its own “vendor” annotations to support additional
mapping features and association types that aren’t part of the JPA specification. Hibernate
strives to be the prototype for future versions of the JPA specification, so some of
these annotations represent early versions of what may become available in JPA. Seam
also takes advantage of some of Hibernate’s other vendor extensions, such as manual
flushing of the persistence context, covered in the next chapter.
将annotations带到持久层
如果尝到了annotations的甜头,你会用它来配置实体。标准的JAVA实体annotations(javax.persistence.*包)可以JPA and Hibernate中工作,除了标准JPA annotation集,Hibernate有自己的annotations支持附加的映射特性及JPA规范中没有的附属类型,Hibernate努力成为未来版的JPA原型,所以一些annotations就是未来JPA的预览版。SEAM也利用了一些Hibernate的其它扩展,如手动冲刷(flushing)持久上下文,见下一章。
The @Entity annotation is used to declare a Java class as an entity. You’ve seen this
annotation used many times throughout this book, often accompanying the @Name
annotation to allow the class to serve a dual purpose as persistence entity and Seam component.
Listing 8.1 shows an excerpt of the Course entity, which is used to store information
about a golf course. Several key mapping annotations are shown in this listing
that define how the class maps to the table in the database.
@Entity用于声明一个Java为实体。本书中你已见了多次。经常伴着@Name允许一个类有双重身份,持久化实例和SEAM部件。表8.1是Course的摘要。用于存储高尔夫课程信息。表中几个主要映射annotations定义了类如何映射到表。
It is also possible to define all of the entity metadata in XML mapping files, regardless
of whether you’re using JPA or Hibernate. In JPA, all of the XML mappings are
declared in the file META-INF/orm.xml. Hibernate reads XML mappings from individual
*.hbm.xml files. Consult the reference document for Hibernate2 or the Hibernate
EntityManager (JPA)3 for details on using the mapping descriptors in the
respective frameworks.
The metadata alone is not enough to allow these classes to be persisted. They must
be associated with a persistence unit.
不管你是用JPA or Hibernate,也可以在一个XML映射文件中定义所有的实例元数据。所有XML映射在META-INF/orm.xml是声明,Hibernate从*.hbm.xml文件读取XML映射。细节请参考相关文档。
元数据自己是无法让类做持久化的,必须关联到持久化单元。
3 The persistence unit
The persistence unit groups the entities to be managed and determines how they are
to be associated with a database runtime. It also indicates which transaction type is to
be used when the database operations occur. The persistence unit consists of three
main parts:
■ Entity metadata—A set of all annotated classes or XML mappings to be managed,
containing instructions for how Java classes and bean properties are mapped to
relational database tables. It also indicates the relationships between entities
and defines the global fetching strategy used to traverse relationships.
■ Persistence unit descriptor—Specifies which persistence provider to use (not applicable
for native Hibernate), database connection information, transaction type
and lookup, and vendor extensions.
■ Persistence manager factory—The runtime object representing the configuration
of the persistent unit as a whole. The factory is used to create individual persistence
managers that provide the services for managing entity instances.
持久化单元
持久化单元分组实体并决定怎样将其关联到数据库。它也指明操作数据库进使用哪个事务类型。持久化单元由三部分组成:
实体元数据。一个annotated的类的集合或被管理的XML映射,包含决定JAVA类和bean属性如何映射到表的指令。也决定着实体与全局抓取策略的关系。
持久单元描述文件。指定使用哪个持久提供者(不适用于原生native Hibernate),数据库连接信息,事务类型,查询及提供商的扩展。
持久管理工厂。运行时对象,总体代表存储单元的配置。工厂是用来建立各自的持久管理器,提供管理实体实例服务。
It’s important to understand the distinction between application-managed and container-
managed persistence managers. The former is where the application bootstraps
the persistence unit and is responsible for creating its own persistence managers. The
latter, which only applies to JPA, is where the container loads the persistence unit and
dishes out persistence managers as requested. Regardless of which style of Java persistence
you’re using, you must first set up a persistence unit.
理解应用管理及容器管理的区别很重要。前者是应用存储管理单元,并负责建立自己的持久管理器。后者,只应用于JPA,是容器加载持久单元的位置,并可在被请求时处理持久管理器。不管你使用哪种JAVA持久化,你首先要设置持久单元。
3.1 Defining a JCA data source
There is one prerequisite for setting up a persistence unit: a data source. After all, the
goal of persistence is to talk to a database, and the data source provides the channel to
that resource. Application servers employ JCA to allow a database resource adapter to
integrate with the server connection pooling. What that basically means is that it’s possible
to stick a database connection configuration into JNDI and have it managed as a
connection pool. Data sources can be of the nontransaction, local transaction, or XA
transaction variety. Up until now, you’ve been using a local transaction, but you’ll get a
chance to play with XA transactions in chapter 14 (online).
定义JCA数据源
有一个设置持久单元的前提:数据源。毕竟,持久的目标是跟数据库打交道,数据源提供了这一通道。应用服务器使用JCA允许数据源集成于数据连接池。简单地说是绑定数据连接配置到JNDI并作为连接池管理。数据源可以是非事务、本地事务或XA事务。到目前为止,你已使用了本地事务,将会在第14章(online)玩玩XA事务。
In JBoss AS, files that end in *-ds.xml are used to install a data source. seam-gen sets
up one of these deployment artifacts for each profile, dev and prod, and puts it in the
resources folder of the project. When the build runs, the file is shipped off to JBoss AS.
If you’re using a different application server, such as GlassFish, you may set up the
data source in the administration panel instead. As an alternative, you can define your
database connection (JDBC) configuration directly in the persistence unit. In the case
of JPA, this is done with vendor-specific JDBC properties (supported in Hibernate,
TopLink Essentials, and OpenJPA).
在JBoss AS,以*-ds.xml结束的文件用于安装数据源。seam-gen为每种部署(profile, dev and prod)设置了一个样板,位于项目资源文件夹。当编译运行,文件发送到JBoss AS。如果你使用一个不同的应用服务器,如GlassFish,你可以在其管理页面设置数据源。另外,你可以直接在持久单元定义你的数据连接(JDBC)配置。对于JPA,由提供商的JDBC属性来决定。
Once the data source is in place, you’re ready to configure the persistence unit.
The persistence unit descriptor hosts the only XML required in Java persistence.
一旦数据源就位,你就可以配置持久单元。持久单元描述文件控制关着JAVA持久化所需要的唯一XML。
8.3.2 The persistence unit descriptor
The persistence unit descriptor brings all the entity classes together under a single
persistence unit and hitches them to an actual database. For JPA, the persistence unit
descriptor is META-INF/persistence.xml, and for Hibernate it is hibernate.cfg.xml.
Each has a distinct XML schema. Listing 8.2 shows the JPA persistence unit descriptor
used in the Open 18 directory application.
持久单元描述文件
持久单元描述文件将所有实体类放到一个单独的持久单元并关联到数据库。JPA描述文件是META-INF/persistence.xml。Hibernate的是hibernate.cfg.xml。分别有清晰的XML schema。表8.2列出了Open 18目录应用的JPA持久单元描述文件。
表8.2中的文件标明了告诉容器如何操作的几个关键信息。事实上只有
持久单元配置建立一个名为open18的持久单元,以Hibernate作为JPA提供者,使用JNDI数据源管理器用来获得数据库连接。JTA事务,(5)指定用哪个类来维护UserTransaction and TransactionManager的JNDI名。TransactionManager lookup是唯一与应用管理持久相关。在JTA不可用环境下,或你不想用时,你也可以使用resource-local事务(只当作实体事务)。其它属性是Hibernate提供商的。
NOTE
The data source defined in the
the
refers to a javax.sql.DataSource in JNDI. seam-gen creates applications
that use this configuration. Alternatively, you can configure a JDBC connection
using vendor-specific persistence unit properties. The JNDI data
source is typically a better choice to offload management of this resource.
Note that Seam uses the Embedded JBoss container to provide a local
JNDI registry in which to store the data source in a testing environment.
如果数据源定义在持久描述文件的
So why use annotations for the mappings and XML for the persistence unit configuration?
After all, they both represent metadata about how entity classes tie in to database
columns and tables. The answer involves the essence of ORM.
为什么使用annotations来映射,而XML用来持久单元配置?毕竟,他们都是代表怎样实体类绑定到数据库列和表的元数据。答案关系到ORM的本质。
One of the core principles of Hibernate and JPA is to abstract vendor-specific database
information from the Java code. The entity mappings are generally fixed, regardless
of which database you use, so annotations are appropriate. It’s still possible to
override the entity mappings in XML if you really need to, perhaps because a different
table-naming convention is used in a given database. This setup gives you the rapid
development of using annotations without losing the flexibility of configuration provided
by an XML descriptor. Where XML is best suited, though, is in defining the SQL
dialect, transaction manager, connection URL, and credentials, which are practically
guaranteed to change when you switch among databases or deployment environments.
These property values can even be tokenized so that a build can sweep through
and apply the appropriate replacement values.
Hibernate and JPA的一个重要原则是从JAVA代码中抽象提供高的数据库信息。整个映射是固定的,不管你用的是什么数据库,所以用annotations比较合适。如果有必要,也可以用XML重写实体映射,这可能是因为不同的表命名习惯。这种双配置给了你弹性。XML最好是用在定义SQL方言,事务管理器,连接URL,在数据库与部署环境间切换时的临时许可,这些属性值甚至可以令牌化,使编译可以方便地切换。
There are important differences in how JPA handles the persistence unit descriptor
in comparison to Hibernate. In JPA, the following rules apply:
在JPA怎样处理持久单元描述文件上,与Hibernate相比有一个重要的不同。JPA遵循下列规则:
■ The persistence unit descriptor must be located at META-INF/persistence.xml.
■ Annotated classes are automatically discovered unless indicated otherwise in
the descriptor by declaring the
■ In a Java EE environment, if META-INF/persistence.xml is present, the persistence
units in this descriptor will automatically be loaded.5
持久单元描述文件必须位于META-INF/persistence.xml
被注释的类(Annotated)自动被发现,除非用
在Java EE环境,如果META-INF/persistence.xml存在,这个文件中的持久单元将被自动加载
As you can see, some optimizations in JPA allow it to follow configuration-by-exception
semantics. The fact that you can’t change the location and name of the persistence
unit descriptor may leave you scratching your head as to how to define multiple persistence
units. Unlike the Hibernate configuration, JPA supports multiple persistence
units within the same descriptor, so you don’t need separate files.
如你所见,一些JPA中的优化允许“以异常来配置”。你不能改变持久单元描述文件的位置和名称,这使你难于定义多个持久单元。不像Hibernate的配置,JPA在一个描述文件中支持多个持久单元,不需要分离的文件。
Hibernate does less work for you when setting up a persistence unit, perhaps as a
trade-off for giving you more control. If you’re using JPA annotations, you must explicitly
define each class in the Hibernate configuration file. You also need multiple Hibernate
configuration descriptors (hibernate-database1.cfg.xml, hibernate-database2.cfg.xml)
if you need multiple persistence units. Finally, Hibernate isn’t automatically loaded into
the Java EE environment. If you want to stay away from the proprietary API and configurations
of native Hibernate, you’re better off using Hibernate as a JPA provider. Putting
JPA in front of Hibernate permits you to switch to a different JPA vendor more easily if
you feel the need to do so.
当你设置持久单元时,Hibernate做很少的工作,可能是为了给你更多的控制权。如果你使用JPA annotations,你必须在Hibernate配置文件中定义每个类,如果你需要多个持久化单元,你也需要多个Hibernate配置描述文件(hibernate-database1.cfg.xml, hibernate-database2.cfg.xml)。最后一点,Hibernate不会自动加载到Java EE环境。如果你不想使用属性API,并配置原生Hibernate,最好不要用Hibernate作为JPA提供者。将JPA放在Hibernate前面,可以让你在需要换成其它提供者时非常容易。
Reading the persistence unit descriptor, interpreting the XML mappings, and scanning
the classpath for entity annotations are expensive operations. They should be
done only once, when the application boots. That’s the role of the persistence manager
factory.
读持久化单元描述文件,翻译XML映射,扫描类路径以查找实体annotations,这些都是昂贵的操作,它们应只做一次。当应用启动时,这就是持久化管理器工厂的工作。
3.3 The persistence manager factory
When the persistence unit is loaded, either by the container or by the application, its
configuration is stored in a runtime object known as the persistence manager factory.
In JPA, the persistence manager factory class is EntityManagerFactory. The equivalent
class in Hibernate is SessionFactory. Once the configuration is loaded into this
object, it is immutable. For each persistence unit (either a single
in a JPA persistence unit descriptor or the
file), there’s a persistence manager factory object to manage it.
无论是通过容器还是应用,当持久化单元被加载,其配置被保存在叫作持久化管理工厂的运行时对象中。对于JPA,持久化管理工厂叫EntityManagerFactory,在Hibernate叫SessionFactory。一旦配置加载到这个对象,就不再可变。对于每个持久化单元(或者是单个的JPA的
When the persistence unit is managed by the container, within a Java EE environment,
the persistence manager factory can be injected into a bean property of a Java
EE component (a JSF managed bean or an EJB component) using the @Persistence-
Unit annotation:
当持久单元受容器管理,在Java EE环境,持久化管理工厂可以使用@Persistence-Unit annotation注入到一个Java EE部件的bean属性(JSF管理bean或EJB部件)。
@PersistenceUnit
private EntityManagerFactory emf;
In the absence of container-managed persistence, you must load the persistence unit
in application code using the Persistence class. For instance, you could load the
open18 persistence unit using a call to a static method on the Persistence class in JPA:
当没有容器管理持久化,你必须用Persistence类来将持久单元加载到应用代码。例如,你可以通过调用JPA的Persistence类上的静态方法加载open18持久单元:
EntityManagerFactory entityManagerFactory =
Persistence.createEntityManagerFactory("open18");
The term persistence manager factory reflects its primary function: to create persistence
managers. It’s a thread-safe object designed to be loaded once when the application
starts and closed when the application ends for the sole reason that it’s very
expensive to create. Therefore, it’s almost always stored in the application scope, the
longest-running scope in the Servlet API.
词组persistence manager factory反映着它的主要功能就是建立持久管理器。当线程安全对象被指定为当应用启动时加载,当应用关闭时关闭,原因就是其建立很昂贵。所以它总是保存在应用范围,Servlet API的长期运行范围。
That wraps up our discussion of the persistence unit. As you’ve learned, the persistence
unit defines which entity classes are to be managed by the persistence API and
specifies the resources involved, such as the database dialect and the transaction
lookup mechanism. You’re now aware that the persistence unit can be loaded by the
container or by the application. With the persistence runtime established, we can
move on to the persistence manager, the real workhorse of Java persistence.
总结持久化单元的讨论,持久化单元定义哪个实体类被持久化API管理,指定涉及的资源,如数据库方言和事务查找机制。你现在知道了持久单元可被容器或应用加载。持久化运行时建立后,你可以使用持久化管理器,这是JAVA持久化的中坚。
4 The persistence manager
The persistence manager is the API that you use to move entity instances to and from
the database. It’s also used to track changes to the state of the entity instances that it
manages to ensure those changes are propagated to the database. In JPA, the persistence
manager class is EntityManager; in Hibernate, it is the Session class.
持久化管理器
持久化管理器是用于在数据库中来回移动实体实例的API。也用于跟踪实体实例的状态变化,以确保变化应用到了数据库。在JPA中,实体管理器类是EntityManager,Hibernate中是Session类。
8.4.1 Obtaining a persistence manager
A persistence manager is created from a persistence manager factory. In contrast to
the persistence manager factory, persistence managers are very inexpensive to create.
In fact, they don’t even allocate an underlying JDBC connection until a transaction
begins. Assuming you’ve managed to obtain a reference to an EntityManagerFactory,
you’d use it to create an EntityManager instance as follows:
获得持久化管理器
存储管理器由存储管理器工厂建立。对比于工厂,管理器的建立并不昂贵。事实上,它并不分派底层的JDBC连接,直到事务开始。假如你已获得一个EntityManagerFactory的引用,你如下建立EntityManager实例:
EntityManager entityManager =
entityManagerFactory.createEntityManager();
When container-managed persistence is being used (available in a Java EE environment),
a persistence manager can be injected into a bean property of a Java EE component
using the @PersistenceContext annotation, saving you from having to create
it yourself:
当使用容器管理的持久化(Java EE环境下),一个存储管理器可以用@PersistenceContext注入到Java EE部件的bean属性。而不用你自己建立。
@PersistenceContext
private EntityManager em;
You also have the option of creating your own persistence manager in a container environment
by injecting a persistence manager factory, as shown earlier. Outside the container
(such as in a Java SE environment or JavaBean component), you have no other
choice but to create the persistence manager manually from a persistence manager
factory. But that doesn’t mean you can’t delegate this task to Seam. As you’ll learn in
the next chapter, Seam provides its own version of container-managed persistence so
that you can inject a Seam-managed persistence manager into any component using
@In. Seam’s solution also allows you to work with Hibernate in the same way.
你也可以在容器环境通过注入一个存储管理器工厂来建立你自己的存储管理器,如前面所示。在容器之外(如在Java SE环境或JavaBean部件),你没有别的选择,只能从存储管理器工厂手动建立存储管理器。但这并不意味你不能让SEAM来代理,如下章将学,SEAM提供了其自己的容器管理的存储,你可以用@In注入一个SEAM管理的存储管理器到任何部件。SEAM的方案让你用同样的方式同Hibernate工作。
4.2 The management functions of a persistence manager
The persistence manager is more than just a database mapper and query engine. It
takes care of its entities from the moment they’re loaded until they’re kicked out the
door. To that end, the persistence manager has three main responsibilities:
存储管理器的管理功能
存储管理器不只是一个数据库映射器及查询引擎。它照看它的实体,从装进来直到踢出去。主要有三个责任:
■ Manage entity instances within the scope of a single use case —Entities are managed
via the persistence manager API. This API has methods to create, remove,
update, find by id, and query entity instances. It also manages the life cycle of
an entity instance as it moves between four possible states: transient, persisted,
detached, and removed.
■ Maintain a persistence context —The persistence context is an in-memory cache of
all entity instances that have been loaded into memory by this manager. It is the
key to optimizing performance and enabling write-behind database operations
(queued SQL statements). It’s often referred to as the “first-level” cache. The terms
persistence context and persistence manager are often used interchangeably.
■ Perform automatic dirty checking —The state of managed objects that reside in the
persistence context are monitored throughout the lifetime of the persistence
context. When the persistence manager is flushed, the pending changes in the
entity instances are sent to the database as a batch of SQL statements. Once an
object becomes detached, changes to it are no longer monitored.
在单个用例范围中管理实体实例。实例是通过存储管理API管理的,这个API中的方法可以建立、删除、更新、用ID查找、查询实体实例。也在四种可能的阶段(瞬时、存储、脱管、删除)中管理实体实例的生命周期。
管理一个存储上下文。存储上下文是一个内存中所有被这个管理器加载的实体实例的缓冲。这是优化性能的关键。也允许了数据库的“后写”操作。
自动做脏数据检查。被管理的对象的状态存放在存储上下文,在整个存储上下文生命周期中被监视。当存储管理器清理时,实体实例中的未决变动被发送到数据库作为SQL声明的批处理。一旦对象脱管,其改变不再受监视。
The persistence manager works at a higher level than SQL. It understands that data
going to and from the database has a structure (the entity) and that this structured
data has a life cycle, shown in figure 8.3. Entity instances start off as unmanaged, the
transient state. They then become managed, allowing them to be synchronized with
the database. If they are removed, that synchronization becomes a deletion. When
a removal occurs, or the persistence context is closed, the entity instance becomes
detached, which means it has been abandoned by the persistence manager and
changes to it are no longer monitored.
存储管理器工作在比SQL高的层次。可以理解数据库中结构化的数据(实体),这结构化的数据还有生命周期,如图8.3所示。实体实例开始时不受管理,瞬时状态,随后成为受管理,可与数据库同步。有删除则同步删除。当删除发生,存储上下文关闭,实体实例脱管,这表示已被存储管理器抛弃,其状态不再受监视。
The most significant aspect of the persistence manager is its persistence context. In fact, you could argue that the persistence context is what makes using Java persistence worthwhile. The persistence manager will forgo trips to the database when it recognizes that the requested instance has already been loaded into the persistence context.What’s more important is that the persistence manager guarantees uniqueness of
each instance in the persistence context according to its identifier and the object
identity of those instances is preserved. As a result, the persistence manager can monitor
the state of the entity instances and will propagate changes made to them to the
database, even cascading into related entities, whenever the persistence context is
flushed. As long as the persistence manager remains open, you can traverse lazy associations
and the persistence manager will go back to the database to load the data
without requiring you to assemble a query. These features are what make it a persistence
manager, not just a database access layer. But to use these features, the persistence
context must be scoped appropriately.
存储管理最重要的方面是存储上下文。事实上,你可以认为存储上下文使JAVA存储有了价值。当它认为请求实例已经被加载进了存储上下文,存储管理器会放弃访问数据库。更重要的是存储管理器根据ID保证存储上下文中的每个实例的唯一性,实例的对象标识被保存。所以存储管理器可以监视实体实例的状态,无论何时存储上下文清理时,将改变发往数据库,甚至级联到相关实体。只要存储上下文保持打开,你可以跨越延迟关联,存储管理器会回到数据库加载数据而不会你发出请求。要拥有这些特性,你还要将存储上下文的scope设置正确。
4.3 Persistence context scoping
The persistence manager (and accordingly the persistence context) is often misrepresented
as being bound to either a database connection or transaction. This misguided
information was brought about by the persistence manager being misused as a means
to an end in stateless architectures, popularized by the Spring Framework. The result
is that many developers now fear keeping the persistence manager open for an
extended period of time or believe that it isn’t supposed to remain open beyond the
scope of a transaction. The persistence manager was actually designed to serve a use
case, for however long that use case may last. The persistence manager will reestablish
database connections as needed, and by no means does it leave connections open just
because it lives on.
存储上下文的范围
因为关系到数据库的连接或事务,存储管理器(及对应的存储上下文)经常被错误地表示。这些被误导的信息使得存储管理器被误用到被Spring框架普及了的无状态架构。其结果是很多开发者怕让存储管理器保持打开到扩展的范围,或认为在事务范围之外不会被支持。存储管理器实际被设计用于用例,不管用例持续多久。存储管理器会在必要时重建数据库连接,and by no means does it leave connections open just because it lives on.
The truth of the matter is that when the persistence manager is scoped incorrectly,
Java persistence can become more of a hindrance than a help. When the lifetime
of the persistence manager is cut short, perhaps because it’s tied to a
transaction, it leads to detached entity instances, a topic discussed in depth in section
8.6. By putting the persistence context on such a short leash, you’re stripping
out all of its value as a manager of entity instances. The persistence manager was
designed so that it could outlive a transaction and later be re-associated with a new
transaction, informing that transaction, and the database, of the changes to the entities
while it was away (a process known as dirty checking). Without this ability, the
persistence manager is reduced to a mediator for accessing the database.
事实上,当存储管理器范围不正确,JAVA存储只会帮倒忙。当存储管理器被截短,可能因为绑定到事务,这导致脱管的实体实例。详细讨论见8.6。通过将存储上下文放在如此的一个短的约束,就去除了作为实体实例管理器的所有值。存储管理器被设计成可以存活于事务之外,之后可以重新关联到新事务,当实体有变时,通知这个事务及数据库(即脏数据检查)。没有这个能力,存储管理器就失去了中间人的作用。
What you want to do is treat the persistence manager as a stateful object. That
means letting it live through the request and beyond, a need filled by the conversation
context. You have to be careful that you don’t put it in a shared scope, though,
because the persistence manager is not thread safe. In section 8.6, you’ll learn how
to extend the persistence context’s scope by letting a stateful session bean manage
it. In the next chapter, you’ll see that the conversation is best suited for managing
the persistence context, which is exactly how a Seam-managed persistence context
is handled.
你想要将存储管理器当作有状态对象,这意味着让它超越请求的边界,处于会话上下文。你必须小心不要将其放在共享的上下文,因为存储管理器不是线程安全的。在8.6节,你会学到怎样让有状态的session bean来管理它而扩展存储上下文的范围。下一章,你会看到会话最适合于管理存储上下文,解释了SEAM处理的存储上下文是怎样处理的。
That covers how entities are formed and how they’re used to move data between
the Java runtime and the database. But, as you know, data consistency is paramount to
persisting data. A brief discussion of the purpose of transactions and how they’re controlled
wraps up this crash course in Java persistence.
这涉及到实体是怎样形成,它们是怎样用来在JAVA运行时和数据库间移动数据。但正如你所知,数据的一致性是存储数据的首务。关于事务目的的简单讨论,它们怎样控制包装这个JAVA存储速成班。
5 Transactions
Transactions are about as important as the persistence operations themselves. Without
transactions, you’re risking corrupted or inconsistent data. It is crucial that whenever
you perform work against a database, you ensure that the boundaries of a
transaction are well defined and that all work is conducted within the scope of such a
well-defined transaction.
事务
事务和存储操作一样重要。没有事务,就会处于损坏数据的危险中。在操作数据库时,确保事务边界正确定义。
5.1 Sorting out the transaction APIs
A database transaction is a grouping of SQL statements that perform an atomic unit
of work. This grouping is demarcated by special database statements (e.g., BEGIN,
COMMIT, or ROLLBACK). An alternative to issuing these statements explicitly is to use
one of various Java transaction APIs responsible for handling this task. You have
three choices:
排序事务API
数据库事务是操作原子单元的一组SQL声明。这个分组是由特殊的数据库语句声明的,(例如BEGIN,COMMIT, or ROLLBACK)。另一个发布明确声明的方式是通过各种JAVA事务API,有三个选择:
■ JDBC transactions
■ Resource-local transactions
■ JTA transactions
JDBC事务
本地资源事务
JTA事务
At the most basic level, the JDBC API provides a thin wrapper around these statements.
However, when you’re working with ORM, you want to work at a higher level to allow
the ORM to involve the persistence context in the transaction commit. Resource-local
transactions, represented by the RESOURCE_LOCAL constant in the JPA persistence unit
descriptor, are those controlled via the persistence manager API (Hibernate or JPA).
This is a descriptive term that can be translated as “database focused.”
在基本的级别,JDBC API提供了一个较小的对这些声明的包装。不你使用ORM,你希望在事务提交时,在高级别让ORM包含存储上下文。Resource-local事务,在JPA存储单元中用RESOURCE_LOCAL常量表示,是通过存储管理器API(Hibernate or JPA)控制。这个描述语句可理解为“面向数据”。
When working with more than one persistence manager, you need an API that can
facilitate a transaction across several resources. Java Transaction API (JTA) provides a
comprehensive transaction manager that can handle several resources in a single
transaction. JTA transactions are therefore referred to as global or system transactions.
当使用多于一个的存储管理器,你需要一个API来推进一个事务通过多个资源。JAVA事务API(JTA)提供复杂的事务管理器,可以一个事务中处理几个资源。JTA事务因此可关联全局或系统事务。
JTA is a standard Java EE API and is favored when working in a Java EE–compliant
environment. JTA is also used behind the scenes by EJB components that use container-
managed transactions. Resource-local transactions are typically used in Java SE
environments or servlet containers. If available, JTA is the best choice because it simplifies
the task of obtaining an active transaction and issuing rollbacks. It can also
enlist multiple resources into the transaction, so if you’re partway through development
you don’t have to change your existing code if you must add a new transactional
resource. Seam makes working with the various transaction APIs simple by providing a
wrapper that can delegate to the configured transaction API.
Let’s now look at the guarantees that a transaction provides.
JTA是标准Java EE API,最好工作于Java EE兼容环境。EJB部件隐含使用JTA,其使用容器管理的事务。Resource-local事务典型应用在Java SE环境或servlet容器。如果可能,JTA是最好的选择,因为简化了获得活动事务和引发回回滚的任务。也可以加多个资源到事务中,所以如果你在已开发过程中,如果你必须增加新的事务资源,你不用改变你现存的代码。SEAM简单地提供一个包装的代理来配置事务API来处理各种事务API。
来看看事务提供了什么。
5.2 Atomic units of work
From the standpoint of the application, a transaction is an atomic unit of work. An
atomic unit of work is a set of operations, or tasks, that you want to perform on the
database. Since you’re working with Java persistence, you perform these operations
against the persistence manager rather than the database. When you reach the point
when you want to commit the changes to the database, you’re guaranteed by the transaction
that either they all happen or none of them happen.
工作的原子单元
从应用的立场看,事务是工作的原子单元。一个原子工作单元是一套在应用到数据库的操作集合。既然用JAVA存储工作,你就是在对存储管理器而不是数据库操作。当你要提交数据变化,事务可以担保要么完成功,要么就什么都不发生。
KEEPING DATA CONSISTENT
Rather than rehash the overused bank account scenario to explain transactions, we’re
going to talk golf! Consider that you use a tee-time reservation system to secure your
time slot at your favorite golf course. As a user, you browse through the available times
for your course and find one that fits best with your schedule. You pick one and then
submit the form. The action method is then tasked with performing an atomic unit of
work. The following code shows several operations that are performed within a
resource-local transaction using JPA. Proper exception handling is excluded for clarity,
but certainly not optional:
保持数据一致性
我们用高尔夫的例子。假设你使用tee-time预定系统,去确保你高尔夫课程的时间片。作为一个用户,你可以在多个时间片中选一个最符合你的日程的并提交。action方法被调用来处理原子工作单元。下列代码显示了使用JPA对resource-local的几个操作。清晰起见,这里没包括异常处理。
entityManager.getTransaction().begin();
Course course = entityManager.find(Course.class, courseId);
TeeTime teeTime = new TeeTime(course, selectedDate);
course.reserveTeeTime(teeTime);
Golfer golfer = entityManager.find(Golfer.class, currentGolfer.getId());
golfer.addTeeTimeToSchedule(teeTime);
entityManager.flush();
entityManager.getTransaction().commit();
The operations involve marking the time as occupied in the COURSE_SCHEDULE table and
then adding a row to the GOLFER_SCHEDULE table so that you don’t forget about your
obligation. The transaction guarantees that information in these two tables remains
consistent—meaning they tell the same story. It ensures that if the insert operation were
to fail on the GOLFER_SCHEDULE table, the slot would open back up on the
COURSE_SCHEDULE table, and vice versa. You certainly don’t want tee times blocked off
without anyone intending to show up. You also don’t want to show up to the golf course
to find a foursome of golfers chatting at the first tee at your scheduled time.
这些操作包括做时间标记,如COURSE_SCHEDULE表,向GOLFER_SCHEDULE表加下一行,这样你就不会忘记这一义务。事务保证信息在这两个表中保持一致。这确保如果GOLFER_SCHEDULE表插入操作失败,COURSE_SCHEDULE的动作取消,反之亦然。
INFO
It’s often necessary to handle data exchange between two or more persistence
managers (and in turn, two or more databases). This scenario calls
for a distributed transaction that involves XA-compliant data sources. The
XA transaction has the same guarantees but works using a Java-based
transaction manager rather than delegating the establishment of transaction
boundaries to the database.
经常需要在两个或多个存储管理器间处理数据交换(也就对应两个或多个数据库)。这一场景需要涉及XA兼容数据源的分散的事务。XA事务同样保证但使用的是基于JAVA的事务管理器,而不是代表数据库事务边界的建立。
The previous example mirrors the classic credit-debit account scenario often cited.
Let’s consider another source of inconsistency that transactions can protect against.
前一个例子反映了经常引用的经典的借贷帐户场景。
让我们考虑另一个事务要加以保护的不一致的源头。
IT’S ALL OR NOTHING
Assume that you’re adding a new golf course to the directory. You spent a good half
hour collecting all the data for the course and populating the form. You click Submit
to save your work. Once again, the action method is tasked with performing a unit of
work. It must save the main information to the course table, a row for each hole in the
HOLE table, a row for each tee set in the TEE_SET table, and finally a row for each tee
(the number of tee sets times the number of holes) in the TEE table. Assume that
somewhere along the line, one of the inserts chokes and the database kicks back an
error. If a transaction wasn’t active, partial course information could be left spread
across the tables. If you tried to submit the form again, it would bail out because the
top-level record already exists in the database, even though its related data is incomplete.
If the application is smart enough to handle incomplete course data, you may
be able to start the form over by editing the data that was inserted, but programming
for that situation is complicated. You have a mess on your hands. The damage is magnified
if thousands of users are encountering the problem at once.
或者全有或者无
假定你向目录增加一个新的高尔夫课程。你花了大半个小时收集课程的所有数据,添入表单,提交以保存。再一次,action方法受命完成这一工作单元。它必须保存课程表的主要信息,HOLE表每洞一列。TEE_SET表中每个tee一列。最终TEE表每tee一列(tee数乘以holes数)。假定过程中,一个插入失败,数据库返回错误。如果没用事务,会存入部分信息。如果再存,数据库会列出部分信息,如果程序非常聪明,你可以接着上回的继续编辑,但这样的程序太复杂了。如果同时有上千的用户访问,就更麻烦。
These two scenarios should give you a compelling reason to use transactions when
interacting with the persistence manager. However, even if you’re not performing write
operations, transactions are still important. In fact, for databases that support transactions,
it’s impossible to execute a SQL statement without a transaction. It’s just that it
doesn’t last longer than this one statement, behaving the same as auto-commit mode.
这两个场景足以说服你使用事务管理器,甚至在没有写操作时,事务也很重要。
READS NEED PROTECTING TOO
The database will open and close a transaction on every operation if explicit transaction
boundaries are not set. This mechanism is referred to as an implicit transaction. When you
forgo the use of transactions, you’re just letting the database handle it for you, one SQL
statement at a time. These repeated processes of opening and closing transactions incur
an unnecessary performance cost (even if optimized). Therefore, even when you’re just
reading data, you should do so within explicit transaction boundaries.
读也要保护
每个操作,数据库会开、关一次事务,如果不设定明确的事务边界,则为隐含事务机制。当你忘记使用事务,数据库还是会来做事务处理,每次一人SQL声明,这个重复地开、关事务会导致不必要的属性消耗(优化了也会有)。因此当你只是要读数据,应明确指定事务边界。
Using a transaction for successive read-only operations guarantees you the isolation
that transactions provide. If the database were to change in the middle of the rendering
process, for instance, a transaction could guarantee that you won’t end up
showing some of the old and some of the new data. If you use Seam’s transaction management,
you get at least two transactions per request: one that covers the execution
of the actions and one that covers the rendering of the response (which you’ll learn
about in the next chapter).
对后续的只读操作使用事务提供了隔离。如果数据库要在重画过程中改变,事务不会显示部分旧数据、部分新数据。如果你使用SEAM的事务管理,每个请求你会有两个事务,一个负责actions的执行,另一个负责重画(见下一章)。
5.3 ACID abridged
A proper database transaction adheres to the ACID criteria. This acronym stands for
Atomicity, Consistency, Isolation, and Durability. Each criterion is essential to ensuring
the integrity of the database and the operations executed against it. However,
from the standpoint of the business logic, worrying about the details of each criterion
is too low-level. You can instead group them into two key guarantees, which, as an
application developer, you want your business logic to adhere to:
ACID删剪
适当的数据库事务依附于ACID标准。这个缩写代表Atomicity, Consistency, Isolation, and Durability.每个标准用来确保数据库的一致。从业务逻辑的的立场,关心每个标准的细节太底层了。作为应用开发者,你应只围绕事务。
■ All logically grouped operations succeed or the database remains untouched.
■ Your data isn’t intermixed with the data from other concurrent operations.
所有的逻辑分组操作成功或不碰数据库
你的数据不会混合其它同步操作
Although some may criticize this as an oversimplification of transactions, if it helps to
bring along those developers who merely view transactions as something that makes
JPA and Hibernate work, I will have done my job. If you’re interested in learning about
the specifics of the ACID principle, consult the resources listed at the beginning of the
chapter. To go deeper into the topic of transactions and concurrency, check out chapter
5 of Martin Fowler’s Patterns of Enterprise Application Architecture (Addison-Wesley
Professional, 2002).
虽然一些人批评这是事务的过分指定,如果现在开发者只把事务看成JPA和Hibernate工作,我的任务就完成了。如果你对对ACID感兴趣,可去看看本章前所列的资源。要深入了解事务和同步,可参见Martin Fowler’s Patterns of Enterprise Application Architecture(Addison-Wesley Professional, 2002)第5章。
You’re now familiar with the four pillars of Java persistence and how they work
together to exchange data between the database and object-based entities while at the
same time ensuring that the integrity of the data is upheld. Although the operations
on the database form the foundation of Java persistence, the state maintained by the
persistence manager is the value added by this abstraction. That’s because any time
you can avoid hitting the database, the more scalable your application will become
(based on the assumption that the database is the least scalable tier). In the next section,
you’ll learn about a lesser-known feature of Java persistence: using the persistence
manager as a stateful context that extends the lifetime of managed entity
instances over a series of requests, thus making database-oriented web applications
more scalable and less cumbersome to develop and use.
你现在已熟悉了JAVA存储的4个立柱及它们是如何在数据库间交换数据,基于对象的实体,同时,确保数据一致。虽然数据库操作是JAVA存储的基础,被存储管理器维护的状态是这一抽象的附加值。这是因为任何时间,你可以避免冲击数据库,尤其是你的应用变大后(这基于数据库是最难扩展的假定)。下一节,你会学到JAVA存储的少为人所知的特性,使用存储管理器作为状态上下文来扩展被管理实体实例的生命周期跨越一系统请求,因此面向数据库的WEB应用更可扩展且方便开发和使用。
6 Managing persistence in the enterprise
The servlet environment, an abstraction over the HTTP protocol, is a less-than-ideal
setting for performing transactional data processing. The lack of continuity between
the stateless HTTP requests means that database connections and persistence managers
are constantly being turned over. To further disrupt continuity, a web application
is typically partitioned into layers, relying on a data layer to perform Java persistence
operations, then shut down connections afterwards. When a persistence manager is
closed, the entities it manages become detached and no longer support lazy loading
(at least they shouldn’t) or automatic dirty checking, two valuable features of ORM.
在企业应用管理存储
servlet环境下,一个HTTP协议的抽象,是一个对于事务不甚理想的设定。
对于无状HTTP请求的连续性的缺乏,意味数据库连接及存储管理器总是要切换。进一步的是,WEB应用典型地分成多层,依赖依赖数据层进行JAVA存储,然后关闭连接。当存储管理器关闭后,其管理的实体脱管,不再支持延迟加载(至少它们不会)或自动脏数据检查,这是两个ORM的价值所在。
You can instill continuity by reusing the same persistence manager throughout the
duration of a use case. That’s the design goal of the extended persistence context. In
this section, we put Hibernate aside and focus on using JPA in a standard Java EE environment
to implement an extended persistence context and explore the benefits of
doing so. In the next chapter, you’ll learn how Seam mirrors this pattern using either
JPA or Hibernate operating independently of Java EE.
你可以用在整个用例中重用同一个存储管理器
免责声明:
① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。
② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341