使用 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();
这段程序大概运行到 50,000 条记录左右会失败并抛出内存溢(OutOfMemoryException)。
这是因为 Hibernate 把所有新插入的客户(Customer)实例在 session 级别的缓存区进行了缓存的缘故。
先说下hibernate缓存机制,优先session,而后sessionfatory(二级缓存),而后去数据库中查找,具体如下:
if(session开启){
hibernate生成sql;
去session执行sql;
if(session中有){
获得session结果集;
}else{
去SessionFactory中查找;
if(二级缓存关闭或查不到) {
发送sql去数据库中查;
获得数据库结果集;
}else{
获得sessionFactory结果集;
}
}
}else{
发送sql去数据库中查;
获得数据库结果集;
}
Hibernate缓存配置:
jar包:hibernate-ehcache
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-ehcache -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.0.0.Final</version>
</dependency>
hibernate配置
<!-- 二级缓存: 开启 提供类 缓存配置xml位置-->
<property name="cache.use_second_level_cache">true</property>
<property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
<property name="cache.provider_configuration_file_resource_path">hbm.ehcache.hbm.xml</property>
映射配置:
<cache usage="read-only"/><!-- 开启二级缓存:只读 -->
缓存策略:
只读 read-only
非严格读/写 nonstrict-read-write
读写 read-write
事务缓存 transactional
批量插入(Batch inserts)
如果要将很多对象持久化,你必须通过经常的调用 flush() 以及稍后调用 clear() 来控制第一级
缓存的大小
@Test
public void Test12() {
Configuration cfg = new Configuration().configure();//获取配置
SessionFactory sessionFactory = cfg.buildSessionFactory();//创建会话工厂
Session session = sessionFactory.openSession();//开启会话
Transaction transaction = session.beginTransaction();//开启事务
for(int i = 1;i<=25;i++) {
Dept dept = new Dept();
dept.setDname("gz"+i);
session.save(dept);
if(i%10 == 0) {
session.flush();//
session.clear();
}
}
transaction.commit();
}catch(Exception e) {
e.printStackTrace();
transaction.rollback();//事务异常则回滚
}finally{//关闭资源
session.close();
sessionFactory.close();
}
}
执行结果:
Hibernate:
select
hibernate_sequence.nextval
from
dual
//10遍
Hibernate:
insert
into
dept1
(dname, loc, deptno)
values
(?, ?, ?)//10遍
Hibernate:
select
hibernate_sequence.nextval
from
dual
//10遍
Hibernate:
insert
into
dept1
(dname, loc, deptno)
values
(?, ?, ?)//10遍
Hibernate:
select
hibernate_sequence.nextval
from
dual
//5遍
Hibernate:
insert
into
dept1
(dname, loc, deptno)
values
(?, ?, ?)//5遍
批量更新:
ScrollableResults depts = session.getNamedQuery("getDepts")
.setCacheMode(CacheMode.IGNORE)
.scroll(ScrollMode.FORWARD_ONLY);
int i = 0;
while (depts.next()) {
Dept dept = (Dept) depts.get(0);
dept.setDname("gz3");
if(++i%5 == 0) {
session.flush();
session.clear();
}
}
transaction.commit();
分页查询:
Query query = session.createQuery("from Dept");
query.setMaxResults(5);
query.setFirstResult(3);
List<Dept> list = query.list();
for(Dept d:list) {
System.out.println(d.getDeptno());
}
transaction.commit();//提交事务
发送的sql:
Hibernate:
select
*
from
( select
row_.*,
rownum rownum_
from
( select
dept0_.deptno as deptno0_,
dept0_.dname as dname0_,
dept0_.loc as loc0_
from
dept1 dept0_ ) row_
where
rownum <= ?
)
where
rownum_ > ?