您好,登錄后才能下訂單哦!
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在事務傳輸和存儲管理上給你帶來的方便。
8.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并了解其架構。
8.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存儲。
8.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存儲的目錄是在實體實例與數據庫間移動數據。本書中你已大量使用實體了。來快速瀏覽一下其已經擔當的角色。
8.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.
當實體作為數據的代表存儲到數據庫表,不用模仿數據庫的語句。這個間隙由映射元數據填補了。
8.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將每次在應用啟動時建立數據庫。可用自下而上的或自上而下的開發模式。
下面看看實體怎樣幫助存儲數據更容易。
8.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高效,你恰當地管理存儲上下文及事務。
8.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映射。細節請參考相關文檔。
元數據自己是無法讓類做持久化的,必須關聯到持久化單元。
8.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持久化,你首先要設置持久單元。
8.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,這些都是昂貴的操作,它們應只做一次。當應用啟動時,這就是持久化管理器工廠的工作。
8.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持久化的中堅。
8.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工作。
8.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設置正確。
8.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存儲速成班。
8.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.
事務
事務和存儲操作一樣重要。沒有事務,就會處于損壞數據的危險中。在操作數據庫時,確保事務邊界正確定義。
8.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。
來看看事務提供了什么。
8.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的執行,另一個負責重畫(見下一章)。
8.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應用更可擴展且方便開發和使用。
8.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.
你可以用在整個用例中重用同一個存儲管理器
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。