HIBERNATE - Relational Persistence for Idiomatic Java
Hibernate Reference Documentation
Hibernateレファレンスドキュメンテーション
3.2.2
Table of Contents(コンテンツテーブル)
Preface(序文)
1. Introduction to Hibernate(Hibernateの紹介)
2. Architecture(アーキテクチャ)
3. Configuration(設定)
4. Persistent Classes(永続クラス)
6. Collection Mapping(コレクションのマッピング)
7. Association Mappings(関連マッピング)
8. Component Mapping(コンポーネントのマッピング)
9. Inheritance Mapping(継承マッピング)
10. Working with objects(オブジェクトを扱う)
11. Transactions And Concurrency(トランザクションと並行性)
12. Interceptors and events(インターセプタとイベント)
13.1. Batch inserts(バッチ挿入)
13.2. Batch updates(バッチ更新)
13.3. The StatelessSession interface
13.4. DML-style operations
Chapter 13. Batch processing
A naive approach to inserting 100 000 rows in the database using Hibernate might look like this:
Hibernateを使ってデータベースに100,000行を挿入する愚直な方法は、このようなものです:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
}
tx.commit();
session.close();
This would fall over with an OutOfMemoryException somewhere around the 50 000th row. That's because Hibernate caches all the newly inserted Customer instances in the session-level cache.
これは50,000番目の行のあたりでOutOfMemoryExceptionで失敗するでしょう。Hibernateがセッションレベルキャッシュで、新しく挿入されたすべてのCustomerインスタンスをキャッシュするからです。
In this chapter we'll show you how to avoid this problem. First, however, if you are doing batch processing, it is absolutely critical that you enable the use of JDBC batching, if you intend to achieve reasonable performance. Set the JDBC batch size to a reasonable number (say, 10-50):
この章では、この問題を回避する方法を紹介します。しかしバッチ処理をするなら、JDBCバッチが使用可能であることが非常に重要です。そうでなければ手頃なパフォーマンスが得られません。JDBCバッチサイズを手頃な数値(例えば、10から50)に設定してください:
hibernate.jdbc.batch_size 20
Note that Hibernate disables insert batching at the JDBC level transparently if you use an identiy identifier generator.
Hibernateは、Identiy識別子ゼネレータを使う場合はJDBC透過的レベルにバッチ挿入を無効にすることに注意して下さい。
You also might like to do this kind of work in a process where interaction with the second-level cache is completely disabled:
また二次キャッシュが全く効かないプロセスで、このような作業をしたいと思うかもしれません:
hibernate.cache.use_second_level_cache false
However, this is not absolutely necessary, since we can explicitly set the CacheMode to disable interaction with the second-level cache.
しかし、これは絶対に必要というわけではありません。なぜなら明示的にCacheModeを設定して、二次キャッシュとの相互作用を無効にすることができるからです。
13.1. Batch inserts(バッチ挿入)
When making new objects persistent, you must flush() and then clear() the session regularly, to control the size of the first-level cache.
新しいオブジェクトを永続化するとき、一次キャッシュのサイズを制限するため、セッションをflush()してclear()しなければなりません。
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
Customer customer = new Customer(.....);
session.save(customer);
if ( i % 20 == 0 ) { //20, same as the JDBC batch size
//flush a batch of inserts and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
13.2. Batch updates(バッチ更新)
For retrieving and updating data the same ideas apply. In addition, you need to usescroll() to take advantage of server-side cursors for queries that return many rows of data.
データを復元したり更新したりするには同じアイディアを適用します。それに加えて、データの行を多く返すクエリに対して有効なサーバーサイドのカーソルの利点を生かしたければ scroll()を使う必要があります。
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
int count=0;
while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
if ( ++count % 20 == 0 ) {
//flush a batch of updates and release memory:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
13.3. The StatelessSession interface(StatelessSessionインターフェイス)
Alternatively, Hibernate provides a command-oriented API that may be used for streaming data to and from the database in the form of detached objects. AStatelessSession has no persistence context associated with it and does not provide many of the higher-level lifecycle semantics. In particular, a stateless session does not implement a first-level cache nor interact with any second-level or query cache. It does not implement transactional write-behind or automatic dirty checking. Operations performed using a stateless session do not ever cascade to associated instances. Collections are ignored by a stateless session. Operations performed via a stateless session bypass Hibernate's event model and interceptors. Stateless sessions are vulnerable to data aliasing effects, due to the lack of a first-level cache. A stateless session is a lower-level abstraction, much closer to the underlying JDBC.
また別の方法として、Hibernateはコマンド指向のAPIを用意しています。これは分離オブジェクトの形で、データベースとのデータストリームのやり取りに使うことができます。StatelessSessionは関連する永続コンテキストを持たず、高レベルのライフサイクルセマンティクスの多くを提供しません。特にステートレスセッションは、一時キャッシュを実装せず、またどのような二次キャッシュやクエリキャッシュとも相互作用しません。トランザクショナルなwrite-behindや自動ダーティチェックも実装しません。ステートレスセッションを使って行われる操作が、関連するインスタンスへカスケードされることは決してありません。コレクションは、ステートレスセッションからは無視されます。ステートレスセッションを通して行われる操作は、Hibernateのイベントモデルやインターセプタの影響を受けません。一時キャッシュを持たないため、ステートレスセッションは別名を持つデータに上手く対処できません。ステートレスセッションは低レベルの抽象化であり、JDBCに非常によく似ています。
StatelessSession session = sessionFactory.openStatelessSession();
Transaction tx = session.beginTransaction();
ScrollableResults customers = session.getNamedQuery("GetCustomers")
.scroll(ScrollMode.FORWARD_ONLY);
while ( customers.next() ) {
Customer customer = (Customer) customers.get(0);
customer.updateStuff(...);
session.update(customer);
}
tx.commit();
session.close();
Note that in this code example, the Customer instances returned by the query are immediately detached. They are never associated with any persistence context.
このコード例では、クエリが返すCustomerインスタンスは即座に(セッションから)分離されることに注意してください。これは、どのような永続コンテキストとも決して関連しません。
The insert(), update() and delete() operations defined by the StatelessSession interface are considered to be direct database row-level operations, which result in immediate execution of a SQL INSERT, UPDATE or DELETE respectively. Thus, they have very different semantics to the save(), saveOrUpdate() and delete() operations defined by theSession interface.
StatelessSessionインターフェイスで定義されている insert(), update(), delete()は、低レベルの直接的なデータベース操作と考えられます。結果として、SQLのINSERT, UPDATE, DELETEがそれぞれ即座に実行されます。このように、これらはSessionインターフェイスで定義されている save(), saveOrUpdate(), delete()とは非常に異なる意味を持ちます。
13.4. DML-style operations(DMLスタイルの操作)
As already discussed, automatic and transparent object/relational mapping is concerned with the management of object state. This implies that the object state is available in memory, hence manipulating (using the SQL Data Manipulation Language (DML) statements: INSERT, UPDATE, DELETE) data directly in the database will not affect in-memory state. However, Hibernate provides methods for bulk SQL-style DML statement execution which are performed through the Hibernate Query Language (Chapter 14,HQL: The Hibernate Query Language).
すでに議論したように、自動的かつ透過的なオブジェクト/リレーショナルマッピングは、オブジェクトの状態の管理であると考えられます。これはメモリ内のオブジェクトの状態を利用できるということです。そのため(SQLのデータ操作言語(DML)文:INSERT,UPDATE,DELETEを使って)データベース内のデータを直接操作しても、メモリ内の状態には影響を与えません。しかしHibernateは、バルクSQLスタイルのDML文実行に対応するメソッドを用意しています。これはHibernateクエリ言語(Chapter 14, HQL: The Hibernate Query LanguageHQL)を通して実行されます。
The pseudo-syntax for UPDATE and DELETE statements is: ( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?. Some points to note:
UPDATEとDELETE文の疑似構文は:( UPDATE | DELETE ) FROM? エンティティ名 (WHERE条件節)?です。注意すべき点がいくつかあります:
? In the from-clause, the FROM keyword is optional
from節において、FROMキーワードはオプションです。
? There can only be a single entity named in the from-clause; it can optionally be aliased. If the entity name is aliased, then any property references must be qualified using that alias; if the entity name is not aliased, then it is illegal for any property references to be qualified.
from節では単一のエンティティ名だけが可能で、任意で別名を付けることができます。エンティティ名に別名が与えられると、どのようなプロパティ参照も、その別名を使って修飾しなければなりません。もしエンティティ名に別名が与えられなければ、どのようなプロパティ参照も修飾してはなりません。
? No Section 14.4, "Forms of join syntax" (either implicit or explicit) can be specified in a bulk HQL query. Sub-queries may be used in the where-clause; the subqueries, themselves, may contain joins.
(暗黙的であれ明示的であれ)<xref linkend="queryhql-joins-forms">結合をバルクHQLクエリ内で指定することはできません。サブクエリはwhere節で使うことができますサブクエリそのものは、結合を含められます。
? The where-clause is also optional.
whereはオプションです。
As an example, to execute an HQL UPDATE, use the Query.executeUpdate() method (the method is named for those familiar with JDBC's PreparedStatement.executeUpdate()):
例として、HQLのUPDATEを実行するには、Query.executeUpdate()メソッドを使ってください。(このメソッドはおなじみのJDBCPreparedStatement.executeUpdate()から名付けられました):
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
// or String hqlUpdate = "update Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
HQL UPDATE statements, by default do not effect the Section 5.1.7, "version (optional)"or the Section 5.1.8, "timestamp (optional)" property values for the affected entities; this is in keeping with the EJB3 specification. However, you can force Hibernate to properly reset the version or timestamp property values through the use of a versioned update. This is achieved by adding the VERSIONED keyword after the UPDATE keyword.
HQLのUPDATE文は、デフォルトでは、作用するエンティティの Section 5.1.7, "version (optional)"versionや Section 5.1.8, "timestamp (optional)"timestampプロパティの値には影響しません。これはEJB3の仕様にも受け継がれています。しかしversioned updateを使って、versionやtimestampプロパティの値を強制的にリセットさせることができます。これはUPDATEキーワードの後にVERSIONEDキーワードを追加することで行えます。
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName";
int updatedEntities = s.createQuery( hqlUpdate )
.setString( "newName", newName )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
Note that custom version types (org.hibernate.usertype.UserVersionType) are not allowed in conjunction with a update versioned statement.
カスタムバージョン型(org.hibernate.usertype.UserVersionType)はupdate versioned文と一緒に使えないことに注意してください。
To execute an HQL DELETE, use the same Query.executeUpdate() method:
HQLのDELETEを実行するには、同じQuery.executeUpdate()メソッドを使ってください:
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlDelete = "delete Customer c where c.name = :oldName";
// or String hqlDelete = "delete Customer where name = :oldName";
int deletedEntities = s.createQuery( hqlDelete )
.setString( "oldName", oldName )
.executeUpdate();
tx.commit();
session.close();
The int value returned by the Query.executeUpdate() method indicate the number of entities effected by the operation. Consider this may or may not correlate to the number of rows effected in the database. An HQL bulk operation might result in multiple actual SQL statements being executed, for joined-subclass, for example. The returned number indicates the number of actual entities affected by the statement. Going back to the example of joined-subclass, a delete against one of the subclasses may actually result in deletes against not just the table to which that subclass is mapped, but also the "root" table and potentially joined-subclass tables further down the inheritence hierarchy.
Query.executeUpdate()メソッドが返すintの値は、この操作が影響を及ぼしたエンティティの数です。これが影響するデータベース内の行数と、相互に関係するかどうかを考えてみてください。HQLバルク操作は、結果として、実際のSQL文が複数実行されることになります。例えばjoined-subclassです。返される数は、その文によって影響された実際のエンティティの数を示します。joined-subclassの例に戻ると、サブクラスの一つに対する削除は、そのサブクラスがマッピングされたテーブルだけではなく、「ルート」テーブルと継承階層をさらに下ったjoined-subclassのテーブルの削除になります。
The pseudo-syntax for INSERT statements is: INSERT INTO EntityName properties_list select_statement. Some points to note:
INSERT文の疑似構文は:INSERT INTO エンティティ名 プロパティリスト select文です。注意すべき点がいくつかあります:
? Only the INSERT INTO ... SELECT ... form is supported; not the INSERT INTO ... VALUES ... form.
INSERT INTO ... SELECT ... の形式だけがサポートされています。INSERT INTO ... VALUES ... の形式はサポートされていません。
The properties_list is analogous to the column speficiation in the SQL INSERT statement. For entities involved in mapped inheritence, only properties directly defined on that given class-level can be used in the properties_list. Superclass properties are not allowed; and subclass properties do not make sense. In other words, INSERT statements are inherently non-polymorphic.
プロパティリストは、SQLのINSERT文におけるカラムの仕様に類似しています。継承のマッピングに含まれるエンティティに対して、クラスレベルで直接定義されたプロパティだけが、プロパティリストに使えます。スーパークラスのプロパティは認められず、サブクラスのプロパティは効果がありません。言い換えるとINSERT文は、本質的にポリモーフィックではありません。
? select_statement can be any valid HQL select query, with the caveat that the return types must match the types expected by the insert. Currently, this is checked during query compilation rather than allowing the check to relegate to the database. Note however that this might cause problems between Hibernate Types which areequivalent as opposed to equal. This might cause issues with mismatches between a property defined as a org.hibernate.type.DateType and a property defined as aorg.hibernate.type.TimestampType, even though the database might not make a distinction or might be able to handle the conversion.
select文の返り値の型がinsert文が期待する型とマッチしていれば、そのselect文は妥当なHQL selectクエリとなりえます。現在このチェックをデータベースへ任せるのではなく、クエリのコンパイル時にチェックします。このことは、equalとは違い、HibernateのType間の equivalent に関する問題を引き起こすことに注意してください。これはorg.hibernate.type.DataTypeとして定義されたプロパティと、rg.hibernate.type.TimestampTypeとして定義されたプロパティの間のミスマッチの問題を引き起こします。データベースがそれらを区別できなくても、変換することができても、この問題は発生します。
? For the id property, the insert statement gives you two options. You can either explicitly specify the id property in the properties_list (in which case its value is taken from the corresponding select expression) or omit it from the properties_list (in which case a generated value is used). This later option is only available when using id generators that operate in the database; attempting to use this option with any "in memory" type generators will cause an exception during parsing. Note that for the purposes of this discussion, in-database generators are considered to beorg.hibernate.id.SequenceGenerator (and its subclasses) and any implementors oforg.hibernate.id.PostInsertIdentifierGenerator. The most notable exception here isorg.hibernate.id.TableHiLoGenerator, which cannot be used because it does not expose a selectable way to get its values.
idプロパティに対して、insert文には二つの選択肢があります。プロパティリストで明示的にidプロパティを指定するか(この場合、対応するselect式から値が取られます)、プロパティリストから除外するか(この場合、生成される値が使われます)のいずれかです。後者の選択肢は、データベース内を操作するidジェネレータを使うときのみ、利用可能です。この選択肢を採る場合、「インメモリ」型のジェネレータを使うと、構文解析時に例外が発生します。この議論では、インデータベース型ジェネレータはorg.hibernate.id.SequenceGenerator(とそのサブクラス)と、org.hibernate.id.PostInsertIdentifierGeneratorの実装であると考えています。ここで最も注意すべき例外は、org.hibernate.id.TableHiLoGeneratorです。値を取得する選択可能な方法がないため、このジェネレータを使うことはできません。
? For properties mapped as either version or timestamp, the insert statement gives you two options. You can either specify the property in the properties_list (in which case its value is taken from the corresponding select expressions) or omit it from the properties_list (in which case the seed value defined by theorg.hibernate.type.VersionType is used).
versionやtimestampとしてマッピングされるプロパティに対して、insert文には二つの選択肢があります。プロパティリストで明示的にプロパティを指定するか(この場合、対応するselect式から値が取られます)、プロパティリストから除外するか(この場合、org.hibernate.type.VersionTypeで定義された シード値が使われます)のいずれかです。
An example HQL INSERT statement execution:
HQlのINSERT文の例です。
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c where ...";
int createdEntities = s.createQuery( hqlInsert )
.executeUpdate();
tx.commit();
session.close();
No comments:
Post a Comment