使用Hibernate在数据库中插入100000行可能看起来像这样:
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();
这将导致大约在50,000出现一个OutOfMemoryException异常。这是因为Hibernate把所有新插入的Customer实例在session级别的缓存。在本章中,我们将向您展示如何避免这个问题。
如果你是进行批量处理,您将需要启用使用JDBC批处理。如果你想达到最佳性能,这是绝对必要的。JDBC批处理大小设置一个合理的数字(10-50,例如):
hibernate.jdbc.batch_size 20
你也可以做这样一个互动与第二级缓存是完全禁用的过程中的工作:
hibernate.cache.use_second_level_cache false
然而,这不是绝对必要的的,因为我们可以明确地设置CacheMode禁用与第二级缓存之间的互动。
Batch inserts
当新的对象持久化后,然后定期刷新一批插入和释放内存(flush()clear())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
//刷新一批插入和释放内存:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Batch updates
对于数据检索和更新,可以应用相同的方法。此外,你需要使用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();
The StatelessSession interface
另外,Hibernate提供了一个面向命令的API,可以使用detached对象的形式,并从数据库中的数据流。一个 StatelessSession没有持久化上下文与它相关的,并没有提供很多的更高层次的生命周期语义。特别是,一个无状态会话不实现第一级缓存,也不与任何第二级或查询缓存交互 。它不实现事务后写或自动脏检查。进行的操作使用一个无状态会话从来没有级联到关联实例。集合会被无状态会话忽略。通过stateless session进行的操作绕过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();
在此代码示例,Customer实例查询之后立即脱离 。他们从未与任何持久化上下文关联。
insert(), update() and delete() 操作被StatelessSession接口定义为直接的数据库行级操作。它们立即执行的SQL结果分别是INSERT,UPDATE或DELETE。插入、更新和删除在Seesion接口中有不同的语义,分别是 save(), saveOrUpdate() and delete()操作。
DML风格的操作
如前所述,自动和透明的对象/关系映射与管理对象的状态有关。对象的状态存在于内存中。这意味着直接操作数据库(使用SQL DML语句:insert,update,delete)将不影响内存中的状态。However, Hibernate provides methods for bulk SQL-style DML statement execution that is performed through the Hibernate Query Language ( HQL ).不过,Hibernate提供了批量SQL风格的DML语句的执行,是通过Hibernate查询语言(HQL ) 。伪语法UPDATE和DELETE语句是: ( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?
有几点说明:
在FROM子句,FROM关键字是可选的
只能有一个单一的实体,在FROM子句中命名。 然而,它可以是别名。 如果实体名称别名,则必须是合格的任何属性引用使用该别名。
没有关联 ,无论是显示或隐示的,可以指定在大批量HQL查询。子查询可以使用WHERE子句,子查询本身可能包含联接。
WHERE子句是可选的。
作为一个例子,执行一个HQL UPDATE ,使用Query.executeUpdate()方法。 The method is named for those familiar with JDBC's PreparedStatement.executeUpdate() :该方法被命名为那些熟悉JDBC PreparedStatement.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();
在保持与EJB3规范,HQL UPDATE语句的默认情况下,不影响的版本或时间戳为受影响的实体的属性值。但是,您可以强制Hibernate复位的version或timestamp属性值,通过使用versioned update更新。 这是实现加入后VERSIONED版本化的关键字UPDATE关键字。
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();
自定义版本类型, org.hibernate.usertype.UserVersionType ,不准与一起update versioned声明。
要执行一个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();
返回int值Query.executeUpdate()方法指示操作影响的实体。 这可能会或可能不会与在数据库中影响的行数。 一个大批量HQL操作可能导致多条实际正在执行的SQL语句(加入子类,例如)。 返回的数字表示的语句影响的实际实体。 加入子类的例子,针对一个子类的删除实际上可能会导致在删除对不只是该子类映射的表,而且“根”表,并可能加入子类表进一步向下继承层次结构。
伪语法INSERT语句: INSERT INTO EntityName properties_list select_statement 。有几点说明:
只支持insert into ... select ... 形式,不支持insert into ... values ...的形式。
select_statement可以是任何合法的HQL选择查询,警告,返回类型必须匹配插入预期的类型。
对id属性来说,insert语句也给你两个选择。您可以明确指定的id属性在properties_list,在这种情况下,它的价值是从对应的select表达式,或者在properties_list中省略它,在这种情况下使用生成值generated value 。
要么映射属性version或timestamp ,insert语句也给你两个选择。您可以指定在properties_list的财产,在这种情况下,它的值是从对应的select表达式,或省略在properties_list,在这种情况下的定义seed value由org.hibernate.type.VersionType 。
The following is an example of an HQL INSERT statement execution:
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();
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();
这将导致大约在50,000出现一个OutOfMemoryException异常。这是因为Hibernate把所有新插入的Customer实例在session级别的缓存。在本章中,我们将向您展示如何避免这个问题。
如果你是进行批量处理,您将需要启用使用JDBC批处理。如果你想达到最佳性能,这是绝对必要的。JDBC批处理大小设置一个合理的数字(10-50,例如):
hibernate.jdbc.batch_size 20
你也可以做这样一个互动与第二级缓存是完全禁用的过程中的工作:
hibernate.cache.use_second_level_cache false
然而,这不是绝对必要的的,因为我们可以明确地设置CacheMode禁用与第二级缓存之间的互动。
Batch inserts
当新的对象持久化后,然后定期刷新一批插入和释放内存(flush()clear())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
//刷新一批插入和释放内存:
session.flush();
session.clear();
}
}
tx.commit();
session.close();
Batch updates
对于数据检索和更新,可以应用相同的方法。此外,你需要使用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();
The StatelessSession interface
另外,Hibernate提供了一个面向命令的API,可以使用detached对象的形式,并从数据库中的数据流。一个 StatelessSession没有持久化上下文与它相关的,并没有提供很多的更高层次的生命周期语义。特别是,一个无状态会话不实现第一级缓存,也不与任何第二级或查询缓存交互 。它不实现事务后写或自动脏检查。进行的操作使用一个无状态会话从来没有级联到关联实例。集合会被无状态会话忽略。通过stateless session进行的操作绕过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();
在此代码示例,Customer实例查询之后立即脱离 。他们从未与任何持久化上下文关联。
insert(), update() and delete() 操作被StatelessSession接口定义为直接的数据库行级操作。它们立即执行的SQL结果分别是INSERT,UPDATE或DELETE。插入、更新和删除在Seesion接口中有不同的语义,分别是 save(), saveOrUpdate() and delete()操作。
DML风格的操作
如前所述,自动和透明的对象/关系映射与管理对象的状态有关。对象的状态存在于内存中。这意味着直接操作数据库(使用SQL DML语句:insert,update,delete)将不影响内存中的状态。However, Hibernate provides methods for bulk SQL-style DML statement execution that is performed through the Hibernate Query Language ( HQL ).不过,Hibernate提供了批量SQL风格的DML语句的执行,是通过Hibernate查询语言(HQL ) 。伪语法UPDATE和DELETE语句是: ( UPDATE | DELETE ) FROM? EntityName (WHERE where_conditions)?
有几点说明:
在FROM子句,FROM关键字是可选的
只能有一个单一的实体,在FROM子句中命名。 然而,它可以是别名。 如果实体名称别名,则必须是合格的任何属性引用使用该别名。
没有关联 ,无论是显示或隐示的,可以指定在大批量HQL查询。子查询可以使用WHERE子句,子查询本身可能包含联接。
WHERE子句是可选的。
作为一个例子,执行一个HQL UPDATE ,使用Query.executeUpdate()方法。 The method is named for those familiar with JDBC's PreparedStatement.executeUpdate() :该方法被命名为那些熟悉JDBC PreparedStatement.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();
在保持与EJB3规范,HQL UPDATE语句的默认情况下,不影响的版本或时间戳为受影响的实体的属性值。但是,您可以强制Hibernate复位的version或timestamp属性值,通过使用versioned update更新。 这是实现加入后VERSIONED版本化的关键字UPDATE关键字。
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();
自定义版本类型, org.hibernate.usertype.UserVersionType ,不准与一起update versioned声明。
要执行一个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();
返回int值Query.executeUpdate()方法指示操作影响的实体。 这可能会或可能不会与在数据库中影响的行数。 一个大批量HQL操作可能导致多条实际正在执行的SQL语句(加入子类,例如)。 返回的数字表示的语句影响的实际实体。 加入子类的例子,针对一个子类的删除实际上可能会导致在删除对不只是该子类映射的表,而且“根”表,并可能加入子类表进一步向下继承层次结构。
伪语法INSERT语句: INSERT INTO EntityName properties_list select_statement 。有几点说明:
只支持insert into ... select ... 形式,不支持insert into ... values ...的形式。
select_statement可以是任何合法的HQL选择查询,警告,返回类型必须匹配插入预期的类型。
对id属性来说,insert语句也给你两个选择。您可以明确指定的id属性在properties_list,在这种情况下,它的价值是从对应的select表达式,或者在properties_list中省略它,在这种情况下使用生成值generated value 。
要么映射属性version或timestamp ,insert语句也给你两个选择。您可以指定在properties_list的财产,在这种情况下,它的值是从对应的select表达式,或省略在properties_list,在这种情况下的定义seed value由org.hibernate.type.VersionType 。
The following is an example of an HQL INSERT statement execution:
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();