πŸ“œ ⬆️ ⬇️

Hibernate Developer Documentation - Chapter IV. Batch processing

I present to you the translation of the fourth chapter of the official documentation Hibernate .

Article translation is relevant for the version Hibernate 4.2.19.Final

Next chapter - Hibernate Developer Documentation - Chapter V. Locks
')
Content
4.1. Batch inserts
4.2. Batch updates
4.3. StatelessSession
4.4. Hibernate query language for DML
4.4.1. HQL for UPDATE and DELETE
4.4.2. HQL syntax for INSERT

The following example demonstrates the anti-pattern of package inserts.

Example 4.1. A naive way to insert 100,000 rows using Hibernate
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 code will fall with the exception OutOfMemoryException after processing about 50,000 lines on most systems. The reason is that Hibernate caches all newly created Customer instances in the session-level cache. There are several ways to avoid this problem.
Before you start working with batch processing, allow it to be used in JDBC. To enable batch processing, enter a value between 10 and 50 in the hibernate.jdbc.batch_size property.

Important
Hibernate turns off batch inserts at the JDBC level transparently if you use an id generator

If this approach is not acceptable, you can turn off the second-level cache (second-level cache) by setting the hibernate.cache.use_second_level_cache property to false

4.1. Batch inserts


When you make new objects persistent, use the flush () and clear () session methods to control the size of the first-level cache.

Example 4.2. Flushing and clearing the session

 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(); 

4.2. Batch updates


Use flush () and clear () regularly when you extract and modify data. In addition, use the scroll () method to take advantage of working with database cursors for queries that return a large number of rows.

Example 4.3. Using 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() 

4.3. StatelessSession


StatelessSession is a command-oriented API provided by Hibernate. Use it to stream data to and from the database in the form of detached objects. The statelessSession does not have an associated persistence context and does not provide most of the high-level semantics.

Features not provided by StatelessSession:

StatelessSession restrictions:

Example 4.4. Using StatelessSession

 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(); 

The Customer objects returned by the request will be disconnected immediately. They will not be associated with any persistence context.

The insert () , update () , and delete () operations defined in the StatelessSession interface work directly with table rows. They lead to the immediate execution of the corresponding SQL operations, since they have different semantics than the save () , saveOrUpdate () , and delete () methods defined in the Session interface.

4.4. Hibernate query language for DML


DML, or Data Markup Language , is related to SQL expressions such as INSERT, UPDATE, and DELETE. Hibernate provides methods for group execution of SQL-like DML operations, in the form of HQL ( Hibernate Query Language ).

4.4.1 HQL for UPDATE and DELETE



Example 4.5. Pseudo-syntax for UPDATE and DELETE expressions using HQL

 ( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)? 

Suffix? means optional parameter. FROM and WHERE are both optional.
FROM can only point to one entity that can have an alias. If the entity name has an alias, any references to the properties must be qualified by this alias. If the entity name does not have a pseudonym, then the references should not be limited (qualified).

Join'y, implicit or explicit, are prohibited in group HQL-queries. You can use subqueries in the WHERE clause, and the subqueries themselves can contain joines.

Example 4.6. Execute HQL UPDATE using the Query.executeUpdate () method

 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 = session.createQuery( hqlUpdate ) .setString( "newName", newName ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close(); 

In accordance with the EJB3 specification, HQL UPDATE expressions, by default, do not affect the values ​​of the version or the timestamp of modified entities. You can use a versioned update to force Hibernate to reset a version or a timestamp by adding the VERSIONED keyword after UPDATE.

Example 4.7. Update timestamp version

 Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName"; int updatedEntities = session.createQuery( hqlUpdate ) .setString( "newName", newName ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close(); 

Important
If you use a VERSIONED expression, you cannot use custom version types that use the org.hibernate.usertype.UserVersionType class

Example 4.8. HQL DELETE Expression

 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 = session.createQuery( hqlDelete ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close(); 

The Query.executeUpdate () method returns an int value that indicates the number of entities affected by the operation. This number does not have to be correlated with the number of rows updated in the database. A group operation in HQL can be several SQL expressions, for example for a joined subclass (joined-subclass). In the example with the subclass to be joined, the DELETE for one of the subclasses may actually result in deletions in the tables under the join or lower in the inheritance hierarchy.

4.4.2 HQL syntax for INSERT


Example 4.9. Pseudo-syntax for INSERT statements

 INSERT INTO EntityName properties_list select_statement 

Only the form INSERT INTO ... SELECT ... is supported. You cannot specify explicit values ​​to insert.

properties_list is the equivalent for specifying columns in an INSERT SQL statement. For entities involved in mapping inheritance , you can specify properties that are directly specified in the class itself, but not from subclasses or the parent class. In other words, an INSERT expression is not polymorphic in its essence.

The select_statement can be any valid HQL select query, but the return types must match the types expected by INSERT. Hibernate checks the returned types at compile time, without waiting for the DBMS to check them. Problems can come from Hibernate types, which are more likely equivalent, but not equal. One example of this is the mismatch of the property defined as org.hibernate.type.DateType and the property defined as org.hibernate.type.TimestampType, even if the database does not differentiate between them, or is capable of doing type conversion itself.

If the id property is not specified in properties_list , Hibernate generates a value automatically. Automatic generation is available only if you use id generators. Otherwise, Hibernate will throw an exception during parsing. Database generators are org.hibernate.id.SequenceGenerator and its subclasses, and objects that implement org.hibernate.id.PostInsertIdentifierGenerator . The most notable exception is org.hibernate.id.TableHiLoGenerator , which does not provide any way to get its values.
For properties that are projected as a version or timestamp, the insert statement gives you two options. You can either specify a property in properties_list , in which case the value will be taken from the accompanying select expression, or removed from properties_list , in which case the initial (seed) value defined in org.hibernate.type.VersionType will be used.

Example 4.10. HQL INSERT expression

 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 = session.createQuery( hqlInsert ) .executeUpdate(); tx.commit(); session.close(); 

Source: https://habr.com/ru/post/269029/


All Articles