mirror of
https://github.com/hibernate/hibernate-orm
synced 2025-02-24 04:05:39 +00:00
Migrate User Guide Batching chapter extras to test folder
This commit is contained in:
parent
03eb9fd276
commit
f3386c37da
@ -1,6 +1,6 @@
|
||||
[[batch]]
|
||||
== Batching
|
||||
:sourcedir: extras
|
||||
:sourcedir: ../../../../../test/java/org/hibernate/userguide/batch
|
||||
|
||||
[[batch-jdbcbatch]]
|
||||
=== JDBC batching
|
||||
@ -39,52 +39,63 @@ The following settings control this behavior.
|
||||
|
||||
The following example shows an anti-pattern for batch inserts.
|
||||
|
||||
.Naive way to insert 100000 lines with Hibernate
|
||||
[[batch-session-batch-example]]
|
||||
.Naive way to insert 100 000 entities with Hibernate
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/batch_insert.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-session-batch-example]
|
||||
----
|
||||
====
|
||||
|
||||
This fails with an `OutOfMemoryException` after around 50000 rows on most systems.
|
||||
The reason is that Hibernate caches all the newly inserted `Customer` instances in the session-level cache.
|
||||
There are several problems associated to this example:
|
||||
|
||||
There are several ways to avoid this problem.
|
||||
Before batch processing, enable JDBC batching. To enable JDBC batching, set the property `hibernate.jdbc.batch_size` to an integer between 10 and 50.
|
||||
. Hibernate caches all the newly inserted `Customer` instances in the session-level c1ache, so, when the transaction ends, 100 000 entities are managed by the persistence context.
|
||||
If the maximum memory allocated to the JVM is rather low, this example could fails with an `OutOfMemoryException`.
|
||||
The Java 1.8 JVM allocated either 1/4 of available RAM or 1Gb, which can easily accommodate 100 000 objects on the heap.
|
||||
. long-running transactions can deplete a connection pool so other transactions don't get a chance to proceed.
|
||||
. JDBC batching is not enabled by default, so every insert statement requires a database roundtrip.
|
||||
To enable JDBC batching, set the property `hibernate.jdbc.batch_size` to an integer between 10 and 50.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Hibernate disables insert batching at the JDBC level transparently if you use an identity identifier generator.
|
||||
====
|
||||
|
||||
If the above approach is not appropriate, you can disable the second-level cache, by setting `hibernate.cache.use_second_level_cache` to `false`.
|
||||
|
||||
[[batch-session-batch-insert]]
|
||||
==== Batch inserts
|
||||
|
||||
When you make new objects persistent, employ methods `flush()` and `clear()` to the session regularly, to control the size of the first-level cache.
|
||||
|
||||
[[batch-session-batch-insert-example]]
|
||||
.Flushing and clearing the `Session`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/flush_and_clear_session.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-session-batch-insert-example]
|
||||
----
|
||||
====
|
||||
|
||||
==== Batch updates
|
||||
[[batch-session-scroll]]
|
||||
==== Session scroll
|
||||
|
||||
When you retrieve and update data, `flush()` and `clear()` the session regularly.
|
||||
In addition, use method `scroll()` to take advantage of server-side cursors for queries that return many rows of data.
|
||||
|
||||
[[batch-session-scroll-example]]
|
||||
.Using `scroll()`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/using_scroll.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-session-scroll-example]
|
||||
----
|
||||
====
|
||||
|
||||
[IMPORTANT]
|
||||
====
|
||||
You should always close the `ScrollableResults`, to deallocate the associated `PreparedStatement` and avoid resource leaking.
|
||||
====
|
||||
|
||||
==== StatelessSession
|
||||
|
||||
`StatelessSession` is a command-oriented API provided by Hibernate.
|
||||
@ -106,11 +117,12 @@ Limitations of `StatelessSession`:
|
||||
* Due to the lack of a first-level cache, Stateless sessions are vulnerable to data aliasing effects.
|
||||
* A stateless session is a lower-level abstraction that is much closer to the underlying JDBC.
|
||||
|
||||
[[batch-stateless-session-example]]
|
||||
.Using a `StatelessSession`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/using_a_StatelessSession.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-stateless-session-example]
|
||||
----
|
||||
====
|
||||
|
||||
@ -127,13 +139,15 @@ They have different semantics from the `save()`, `saveOrUpdate()`, and `delete()
|
||||
DML, or Data Manipulation Language, refers to SQL statements such as `INSERT`, `UPDATE`, and `DELETE`.
|
||||
Hibernate provides methods for bulk SQL-style DML statement execution, in the form of Hibernate Query Language (HQL).
|
||||
|
||||
[[batch-bulk-hql-update-delete]]
|
||||
==== HQL/JPQL for UPDATE and DELETE
|
||||
|
||||
Both the Hibernate native Query Language and JPQL (Java Persistence Query Language) provide support for bulk UPDATE and DELETE.
|
||||
|
||||
[[batch-bulk-hql-update-delete-example]]
|
||||
.Psuedo-syntax for UPDATE and DELETE statements using HQL
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
UPDATE FROM EntityName e WHERE e.name = ?
|
||||
|
||||
@ -143,40 +157,46 @@ DELETE FROM EntityName e WHERE e.name = ?
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
The `FROM` and `WHERE` clauses are each optional.
|
||||
The `FROM` and `WHERE` clauses are each optional, but it's good practice to use them.
|
||||
====
|
||||
|
||||
The `FROM` clause can only refer to a single entity, which can be aliased.
|
||||
If the entity name is aliased, 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.
|
||||
|
||||
[NOTE]
|
||||
====
|
||||
Joins, either implicit or explicit, are prohibited in a bulk HQL query.
|
||||
You can use sub-queries in the `WHERE` clause, and the sub-queries themselves can contain joins.
|
||||
====
|
||||
|
||||
[[batch-bulk-jpql-update-example]]
|
||||
.Executing a JPQL `UPDATE`, using the `Query.executeUpdate()`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/jpql_update.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-bulk-jpql-update-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[batch-bulk-hql-update-example]]
|
||||
.Executing an HQL `UPDATE`, using the `Query.executeUpdate()`
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/hql_update.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-bulk-hql-update-example]
|
||||
----
|
||||
====
|
||||
|
||||
In keeping with the EJB3 specification, HQL `UPDATE` statements, by default, do not effect the version or the timestamp property values for the affected entities.
|
||||
You can use a versioned update to force Hibernate to reset the version or timestamp property values, by adding the `VERSIONED` keyword after the `UPDATE` keyword.
|
||||
|
||||
[[batch-bulk-hql-update-version-example]]
|
||||
.Updating the version of timestamp
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/updating_version.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-bulk-hql-update-version-example]
|
||||
----
|
||||
====
|
||||
|
||||
@ -187,19 +207,21 @@ If you use the `VERSIONED` statement, you cannot use custom version types, which
|
||||
This feature is only available in HQL since it's not standardized by JPA.
|
||||
====
|
||||
|
||||
[[batch-bulk-jpql-delete-example]]
|
||||
.A JPQL `DELETE` statement
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/jpql_delete.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-bulk-jpql-delete-example]
|
||||
----
|
||||
====
|
||||
|
||||
[[batch-bulk-hql-delete-example]]
|
||||
.An HQL `DELETE` statement
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/hql_delete.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-bulk-hql-delete-example]
|
||||
----
|
||||
====
|
||||
|
||||
@ -212,9 +234,12 @@ In the example of joined-subclass, a `DELETE` against one of the subclasses may
|
||||
|
||||
.Pseudo-syntax for INSERT statements
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
INSERT INTO EntityName properties_list SELECT properties_list FROM ...
|
||||
INSERT INTO EntityName
|
||||
properties_list
|
||||
SELECT properties_list
|
||||
FROM ...
|
||||
----
|
||||
====
|
||||
|
||||
@ -243,12 +268,13 @@ For properties mapped as either version or timestamp, the insert statement gives
|
||||
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 the org.hibernate.type.VersionType is used.
|
||||
|
||||
[[batch-bulk-hql-insert-example]]
|
||||
.HQL INSERT statement
|
||||
====
|
||||
[source,java]
|
||||
[source, JAVA, indent=0]
|
||||
----
|
||||
include::{sourcedir}/hql_insert.java[]
|
||||
include::{sourcedir}/BatchTest.java[tags=batch-bulk-hql-insert-example]
|
||||
----
|
||||
====
|
||||
|
||||
This section is only a brief overview of HQL. For more information, see <<chapters/query-hql/HQL.adoc#hql,HQL>>.
|
||||
This section is only a brief overview of HQL. For more information, see <<chapters/query-hql/HQL.adoc#hql,HQL>>.
|
||||
|
@ -1,8 +0,0 @@
|
||||
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();
|
@ -1,15 +0,0 @@
|
||||
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();
|
@ -1,11 +0,0 @@
|
||||
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();
|
@ -1,9 +0,0 @@
|
||||
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();
|
@ -1,12 +0,0 @@
|
||||
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();
|
@ -1,11 +0,0 @@
|
||||
EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
EntityTransaction tx = entityManager.getTransaction();
|
||||
|
||||
String jpqlDelete = "delete Customer c where c.name = :oldName";
|
||||
// or String jpqlDelete = "delete Customer where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlDelete )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
entityManager.close();
|
@ -1,12 +0,0 @@
|
||||
EntityManager entityManager = entityManagerFactory.createEntityManager();
|
||||
EntityTransaction tx = entityManager.getTransaction();
|
||||
|
||||
String jpqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
|
||||
// or String query = "update Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
|
||||
tx.commit();
|
||||
entityManager.close();
|
@ -1,9 +0,0 @@
|
||||
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();
|
@ -1,13 +0,0 @@
|
||||
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();
|
@ -1,19 +0,0 @@
|
||||
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();
|
@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Hibernate, Relational Persistence for Idiomatic Java
|
||||
*
|
||||
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
*/
|
||||
package org.hibernate.userguide.batch;
|
||||
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.EntityManager;
|
||||
import javax.persistence.EntityTransaction;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Version;
|
||||
|
||||
import org.hibernate.CacheMode;
|
||||
import org.hibernate.ScrollMode;
|
||||
import org.hibernate.ScrollableResults;
|
||||
import org.hibernate.Session;
|
||||
import org.hibernate.SessionFactory;
|
||||
import org.hibernate.StatelessSession;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
import org.hibernate.resource.transaction.spi.TransactionStatus;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import org.jboss.logging.Logger;
|
||||
|
||||
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BatchTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
private static final Logger log = Logger.getLogger( BatchTest.class );
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Customer.class,
|
||||
Partner.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScroll() {
|
||||
withScroll();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testStatelessSession() {
|
||||
withStatelessSession();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testBulk() {
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.persist( new Customer( "Vlad" ) );
|
||||
entityManager.persist( new Customer( "Mihalcea" ) );
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Vlad";
|
||||
String newName = "Alexandru";
|
||||
//tag::batch-bulk-jpql-update-example[]
|
||||
int updatedEntities = entityManager.createQuery(
|
||||
"update Customer c " +
|
||||
"set c.name = :newName " +
|
||||
"where c.name = :oldName" )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
//end::batch-bulk-jpql-update-example[]
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Alexandru";
|
||||
String newName = "Vlad";
|
||||
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
//tag::batch-bulk-hql-update-example[]
|
||||
int updatedEntities = session.createQuery(
|
||||
"update Customer " +
|
||||
"set name = :newName " +
|
||||
"where name = :oldName" )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
//end::batch-bulk-hql-update-example[]
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Vlad";
|
||||
String newName = "Alexandru";
|
||||
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
//tag::batch-bulk-hql-update-version-example[]
|
||||
int updatedEntities = session.createQuery(
|
||||
"update versioned Customer " +
|
||||
"set name = :newName " +
|
||||
"where name = :oldName" )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
//end::batch-bulk-hql-update-version-example[]
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String name = "Alexandru";
|
||||
|
||||
//tag::batch-bulk-jpql-delete-example[]
|
||||
int deletedEntities = entityManager.createQuery(
|
||||
"delete Customer c " +
|
||||
"where c.name = :name" )
|
||||
.setParameter( "name", name )
|
||||
.executeUpdate();
|
||||
//end::batch-bulk-jpql-delete-example[]
|
||||
assertEquals(1, deletedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String name = "Mihalcea";
|
||||
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
//tag::batch-bulk-hql-insert-example[]
|
||||
int insertedEntities = session.createQuery(
|
||||
"insert into Partner (id, name) " +
|
||||
"select c.id, c.name " +
|
||||
"from Customer c " +
|
||||
"where name = :name" )
|
||||
.setParameter( "name", name )
|
||||
.executeUpdate();
|
||||
//end::batch-bulk-hql-insert-example[]
|
||||
assertEquals(1, insertedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String name = "Mihalcea";
|
||||
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
//tag::batch-bulk-hql-delete-example[]
|
||||
int deletedEntities = session.createQuery(
|
||||
"delete Customer " +
|
||||
"where name = :name" )
|
||||
.setParameter( "name", name )
|
||||
.executeUpdate();
|
||||
//end::batch-bulk-hql-delete-example[]
|
||||
assertEquals(1, deletedEntities);
|
||||
} );
|
||||
}
|
||||
|
||||
private void withoutBatch() {
|
||||
//tag::batch-session-batch-example[]
|
||||
EntityManager entityManager = null;
|
||||
EntityTransaction txn = null;
|
||||
try {
|
||||
entityManager = entityManagerFactory().createEntityManager();
|
||||
|
||||
txn = entityManager.getTransaction();
|
||||
txn.begin();
|
||||
|
||||
for ( int i = 0; i < 100_000; i++ ) {
|
||||
Customer customer = new Customer( String.format( "Customer %d", i ) );
|
||||
entityManager.persist( customer );
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
} catch (RuntimeException e) {
|
||||
if ( txn != null && txn.isActive()) txn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
if (entityManager != null) {
|
||||
entityManager.close();
|
||||
}
|
||||
}
|
||||
//end::batch-session-batch-example[]
|
||||
}
|
||||
|
||||
private void withBatch() {
|
||||
int entityCount = 100;
|
||||
//tag::batch-session-batch-insert-example[]
|
||||
EntityManager entityManager = null;
|
||||
EntityTransaction txn = null;
|
||||
try {
|
||||
entityManager = entityManagerFactory().createEntityManager();
|
||||
|
||||
txn = entityManager.getTransaction();
|
||||
txn.begin();
|
||||
|
||||
int batchSize = 25;
|
||||
|
||||
for ( int i = 0; i < entityCount; ++i ) {
|
||||
Customer customer = new Customer( String.format( "Customer %d", i ) );
|
||||
entityManager.persist( customer );
|
||||
|
||||
if ( i % batchSize == 0 ) {
|
||||
//flush a batch of inserts and release memory
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
}
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
} catch (RuntimeException e) {
|
||||
if ( txn != null && txn.isActive()) txn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
if (entityManager != null) {
|
||||
entityManager.close();
|
||||
}
|
||||
}
|
||||
//end::batch-session-batch-insert-example[]
|
||||
}
|
||||
|
||||
private void withScroll() {
|
||||
withBatch();
|
||||
|
||||
//tag::batch-session-scroll-example[]
|
||||
EntityManager entityManager = null;
|
||||
EntityTransaction txn = null;
|
||||
ScrollableResults scrollableResults = null;
|
||||
try {
|
||||
entityManager = entityManagerFactory().createEntityManager();
|
||||
|
||||
txn = entityManager.getTransaction();
|
||||
txn.begin();
|
||||
|
||||
int batchSize = 25;
|
||||
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
|
||||
scrollableResults = session
|
||||
.createQuery( "select c from Customer c" )
|
||||
.setCacheMode( CacheMode.IGNORE )
|
||||
.scroll( ScrollMode.FORWARD_ONLY );
|
||||
|
||||
int count = 0;
|
||||
while ( scrollableResults.next() ) {
|
||||
Customer customer = (Customer) scrollableResults.get( 0 );
|
||||
processCustomer(customer);
|
||||
if ( ++count % batchSize == 0 ) {
|
||||
//flush a batch of updates and release memory:
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
}
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
} catch (RuntimeException e) {
|
||||
if ( txn != null && txn.isActive()) txn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
if (scrollableResults != null) {
|
||||
scrollableResults.close();
|
||||
}
|
||||
if (entityManager != null) {
|
||||
entityManager.close();
|
||||
}
|
||||
}
|
||||
//end::batch-session-scroll-example[]
|
||||
}
|
||||
|
||||
private void withStatelessSession() {
|
||||
withBatch();
|
||||
|
||||
//tag::batch-stateless-session-example[]
|
||||
StatelessSession statelessSession = null;
|
||||
Transaction txn = null;
|
||||
ScrollableResults scrollableResults = null;
|
||||
try {
|
||||
SessionFactory sessionFactory = entityManagerFactory().unwrap( SessionFactory.class );
|
||||
statelessSession = sessionFactory.openStatelessSession();
|
||||
|
||||
txn = statelessSession.getTransaction();
|
||||
txn.begin();
|
||||
|
||||
scrollableResults = statelessSession
|
||||
.createQuery( "select c from Customer c" )
|
||||
.scroll(ScrollMode.FORWARD_ONLY);
|
||||
|
||||
while ( scrollableResults.next() ) {
|
||||
Customer customer = (Customer) scrollableResults.get( 0 );
|
||||
processCustomer(customer);
|
||||
statelessSession.update( customer );
|
||||
}
|
||||
|
||||
txn.commit();
|
||||
} catch (RuntimeException e) {
|
||||
if ( txn != null && txn.getStatus() == TransactionStatus.ACTIVE) txn.rollback();
|
||||
throw e;
|
||||
} finally {
|
||||
if (scrollableResults != null) {
|
||||
scrollableResults.close();
|
||||
}
|
||||
if (statelessSession != null) {
|
||||
statelessSession.close();
|
||||
}
|
||||
}
|
||||
//end::batch-stateless-session-example[]
|
||||
}
|
||||
|
||||
private void processCustomer(Customer customer) {
|
||||
if ( customer.getId() % 1000 == 0 ) {
|
||||
log.infof( "Processing [%s]", customer.getName());
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
private String name;
|
||||
|
||||
public Customer() {}
|
||||
|
||||
public Customer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
@Entity(name = "Partner")
|
||||
public static class Partner {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
@Version
|
||||
private int version;
|
||||
|
||||
private String name;
|
||||
|
||||
public Partner() {}
|
||||
|
||||
public Partner(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
@ -103,10 +103,10 @@ public void testBuildLockRequest() {
|
||||
Person person = entityManager.find( Person.class, id );
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
session
|
||||
.buildLockRequest( LockOptions.NONE )
|
||||
.setLockMode( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
.lock( person );
|
||||
.buildLockRequest( LockOptions.NONE )
|
||||
.setLockMode( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
.lock( person );
|
||||
//end::locking-buildLockRequest-example[]
|
||||
} );
|
||||
|
||||
@ -116,11 +116,11 @@ public void testBuildLockRequest() {
|
||||
Person person = entityManager.find( Person.class, id );
|
||||
Session session = entityManager.unwrap( Session.class );
|
||||
session
|
||||
.buildLockRequest( LockOptions.NONE )
|
||||
.setLockMode( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
.setScope( true )
|
||||
.lock( person );
|
||||
.buildLockRequest( LockOptions.NONE )
|
||||
.setLockMode( LockMode.PESSIMISTIC_READ )
|
||||
.setTimeOut( LockOptions.NO_WAIT )
|
||||
.setScope( true )
|
||||
.lock( person );
|
||||
//end::locking-buildLockRequest-scope-example[]
|
||||
} );
|
||||
|
||||
|
@ -1,105 +0,0 @@
|
||||
package org.hibernate.userguide.ql;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.GregorianCalendar;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.Id;
|
||||
|
||||
import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hibernate.userguide.util.TransactionUtil.doInJPA;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
/**
|
||||
* @author Vlad Mihalcea
|
||||
*/
|
||||
public class BulkTest extends BaseEntityManagerFunctionalTestCase {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
Customer.class
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testUpdate() {
|
||||
final Calendar calendar = new GregorianCalendar();
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
entityManager.persist( new Customer( "Vlad" ) );
|
||||
entityManager.persist( new Customer( "Mihalcea" ) );
|
||||
} );
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Vlad";
|
||||
String newName = "Mr. Vlad";
|
||||
|
||||
String jpqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Mr. Vlad";
|
||||
String newName = "Vlad";
|
||||
|
||||
|
||||
String jpqlUpdate = "update Customer set name = :newName where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlUpdate )
|
||||
.setParameter( "oldName", oldName )
|
||||
.setParameter( "newName", newName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Vlad";
|
||||
|
||||
String jpqlDelete = "delete Customer c where c.name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlDelete )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
|
||||
doInJPA( this::entityManagerFactory, entityManager -> {
|
||||
String oldName = "Mihalcea";
|
||||
|
||||
String jpqlDelete = "delete Customer where name = :oldName";
|
||||
int updatedEntities = entityManager.createQuery( jpqlDelete )
|
||||
.setParameter( "oldName", oldName )
|
||||
.executeUpdate();
|
||||
assertEquals(1, updatedEntities);
|
||||
} );
|
||||
}
|
||||
|
||||
@Entity(name = "Customer")
|
||||
public static class Customer {
|
||||
|
||||
@Id
|
||||
@GeneratedValue
|
||||
private Long id;
|
||||
|
||||
private String name;
|
||||
|
||||
public Customer() {
|
||||
}
|
||||
|
||||
public Customer(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
}
|
51
documentation/src/test/resources/log4j.properties
Normal file
51
documentation/src/test/resources/log4j.properties
Normal file
@ -0,0 +1,51 @@
|
||||
#
|
||||
# Hibernate, Relational Persistence for Idiomatic Java
|
||||
#
|
||||
# License: GNU Lesser General Public License (LGPL), version 2.1 or later.
|
||||
# See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
|
||||
#
|
||||
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
|
||||
log4j.appender.stdout.Target=System.out
|
||||
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
|
||||
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n
|
||||
|
||||
log4j.rootLogger=info, stdout
|
||||
|
||||
log4j.logger.org.hibernate=info
|
||||
#log4j.logger.org.hibernate=warn
|
||||
|
||||
log4j.logger.org.hibernate.ejb=info
|
||||
log4j.logger.org.hibernate.ejb.packaging=info
|
||||
log4j.logger.org.hibernate.reflection=info
|
||||
|
||||
#log4j.logger.org.hibernate.engine.Cascades=warn
|
||||
#log4j.logger.org.hibernate.hql=warn
|
||||
|
||||
### log just the SQL
|
||||
log4j.logger.org.hibernate.SQL=debug
|
||||
|
||||
### log JDBC bind parameters ###
|
||||
#log4j.logger.org.hibernate.type=info
|
||||
log4j.logger.org.hibernate.type=trace
|
||||
|
||||
### log schema export/update ###
|
||||
log4j.logger.org.hibernate.tool.hbm2ddl=info
|
||||
|
||||
### log HQL parse trees
|
||||
#log4j.logger.org.hibernate.hql=warn
|
||||
|
||||
### log cache activity ###
|
||||
#log4j.logger.org.hibernate.cache=warn
|
||||
|
||||
### log JDBC resource acquisition
|
||||
#log4j.logger.org.hibernate.jdbc=warn
|
||||
|
||||
### enable the following line if you want to track down connection ###
|
||||
### leakages when using DriverManagerConnectionProvider ###
|
||||
#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace
|
||||
|
||||
### When entity copy merge functionality is enabled using:
|
||||
### hibernate.event.merge.entity_copy_observer=log, the following will
|
||||
### provide information about merged entity copies.
|
||||
#log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=warn
|
||||
|
Loading…
x
Reference in New Issue
Block a user