Details of hibernate batch operations

  • 2020-05-07 19:45:16
  • OfStack

This article illustrates the method of batch operation of hibernate. Share with you for your reference, as follows:

Hibernate batch processing

Hibernate operates on the database entirely in an object-oriented manner, and when a persistent object is operated on in an object-oriented manner in a program, it is automatically converted to an operation on the database. For example, Session's delete() method is called to delete the persistent object, and Hibernate is responsible for deleting the corresponding data record. When the set method of the persistent object is executed, Hibernate is automatically converted to the corresponding update method, modifying the corresponding records of the database.

The problem is if you need to update 100  at the same time; 000 records, is it to load 100  one by one? 000 records, and then calling the set method in turn -- not only is this tedious, but the data access performance is 10 percent worse. For this batch processing scenario, Hibernate provides a solution for batch processing. The following sections describe how to deal with this batch processing from three aspects: batch insert, batch update and batch delete.

1   inserts in bulk

If you need to add 100  000 records are inserted into the database. Typically Hibernate might do the following:


Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
for ( int i=0; i<100000; i++ ) {
 User u = new User (.....);
 session.save(customer);
}
tx.commit();
session.close();

But as the program runs, it always fails at some point and throws an OutOfMemoryException (out-of-memory exception). This is because Session of Hibernate holds a required level 1 cache, and all User instances will be cached in the Session level cache.

To solve this problem, there is a very simple idea: flush Session cached data into the database on a regular basis, instead of 1 being cached at Session level. Consider designing an accumulator that increases by 1 for every instance of User saved. Based on the value of the accumulator, determine whether the data in the Session cache needs to be brushed into the database.

So let's add 100  Code snippets for 000 User instances:


private void testUser()throws Exception
{
 // Open the Session
 Session session = HibernateUtil.currentSession();
 // Start the transaction 
 Transaction tx = session.beginTransaction();
 // cycle 100 000 Time, insert 100 000 records 
 for (int i = 0 ; i < 1000000 ; i++ )
 {
  // create User The instance 
  User u1 = new User();
  u1.setName("xxxxx" + i);
  u1.setAge(i);
  u1.setNationality("china");
  // in Session Level cache User The instance 
  session.save(u1);
  // Whenever the accumulator is 20 When I'm a multiple of theta, I'm going to Session The data in the Session The cache 
  if (i % 20 == 0)
  {
   session.flush();
   session.clear();
   tx.commit();
   tx = session.beginTransaction();
  }
 }
 // Commit the transaction 
 tx.commit();
 // Close the transaction 
 HibernateUtil.closeSession();
}

In the above code, when i%20 == 0, the cached data at Session is written to the database manually and the transaction is committed manually. If the transaction is not committed, the data will still be cached in the transaction -- not in the database, and will also cause an out-of-memory exception.

This is the processing of the Session level cache, and the SessionFactory level 2 cache should also be turned off by the following configuration.

hibernate.cache.use_second_level_cache false

Note: in addition to clearing the Session level cache manually, it is best to close the SessionFactory level 2 cache. Otherwise, even if the Session level cache is manually cleared, an exception may be thrown because there is still a cache at SessionFactory level.

2   updates in batches

The method described above is also suitable for batch updates, and if you need to return multiple rows of data, you can use the scroll() method to take advantage of the performance benefits of server-side cursors. Here is the code snippet for the batch update:


private void testUser()throws Exception
{
 // Open the Session
 Session session = HibernateUtil.currentSession();
 // Start the transaction 
 Transaction tx = session.beginTransaction();
 // Query the User All records in the table 
 ScrollableResults users = session.createQuery("from User")
  .setCacheMode(CacheMode.IGNORE)
  .scroll(ScrollMode.FORWARD_ONLY);
 int count=0;
 // traverse User All records in the table 
 while ( users.next() )
 {
  User u = (User) users.get(0);
  u.setName(" A new user name " + count);
  // when count for 20 When a multiple of will update the result from Session In the flush To the database 
  if ( ++count % 20 == 0 )
  {
   session.flush();
   session.clear();
  }
 }
 tx.commit();
 HibernateUtil.closeSession();
}

This way, although you can perform batch updates, they are not very effective. The execution is inefficient, and the data query needs to be executed first, then the data update, and this update will be a row by row update, that is, every row of record updated, requires one update statement to be executed, which is very poor performance.
To avoid this, Hibernate provides a batch update and batch delete HQL syntax similar to SQL.

3   SQL style batch update/delete

The HQL statements provided by Hibernate also support batch UPDATE and DELETE syntax.
The syntax of batch UPDATE and DELETE statements is as follows:


UPDATE | DELETE FROM? ClassName [WHERE WHERE_CONDITIONS]

There are four things to note about the syntax above:

● in the FROM clause, the FROM keyword is optional. The FROM keyword is completely unwritten.
● there can be only one class name in the FROM clause, and the class name cannot have an alias.
● you cannot use joins in bulk HQL statements, either explicitly or implicitly. However, you can use subqueries in the WHERE clause.
● the entire WHERE clause is optional.

Suppose you need to make batch changes to the name properties of an User class instance. This can be done in the following code snippet:


private void testUser()throws Exception
{
 // Open the Session
 Session session = HibernateUtil.currentSession();
 // Start the transaction 
 Transaction tx = session.beginTransaction();
 // Define batch updates HQL statements 
 String hqlUpdate = "update User set name = :newName";
 // Perform the update 
 int updatedEntities = session.createQuery( hqlUpdate )
       .setString( "newName", " The new name " )
       .executeUpdate();
 // Commit the transaction 
 tx.commit();
 HibernateUtil.closeSession();
}

As you can see from the code above, this syntax is very similar to executeUpdate syntax for PreparedStatement. In fact, this batch update of HQL is a direct reference to the UPDATE statement of SQL syntax.

Note: with this batch update syntax, it is usually only necessary to execute the UPDATE statement of SQL once to update all the conditional records. However, you may also need to execute multiple UPDATE statements because of special circumstances such as inheritance mappings, such as having one instance of Person with a subclass instance of Customer. When you batch update the Person instance, you also need to update the Customer instance. If the joined-subclass or union-subclass mapping strategy is used, Person and Customer instances are kept in different tables, so multiple UPDATE statements may be required.

Execute 1 HQL DELETE, again using the Query.executeUpdate () method, and the following is a code snippet that removes all of the above records once:


private void testUser()throws Exception
{
 // Open the Session The instance 
 Session session = HibernateUtil.currentSession();
 // Start the transaction 
 Transaction tx = session.beginTransaction();
 // Define batch deleted HQL statements 
 String hqlUpdate = "delete User";
 // Perform batch deletion 
 int updatedEntities = session.createQuery( hqlUpdate )
       .executeUpdate();
 // Commit the transaction 
 tx.commit();
 // Shut down Session
 HibernateUtil.closeSession();
}

The Query.executeUpdate () method returns an integer value that is the number of records affected by this operation. In fact, the underlying operation of Hibernate is done through JDBC. Therefore, if a batch UPDATE or DELETE operation is converted into multiple UPDATE or DELETE statements, the method returns the number of rows of records affected by the last SQL statement.

I hope this article is helpful for you to design Java based on Hibernate framework.


Related articles: