关于Hibernate session.flush()的问题
我想询问以下情况下flush方法的实际用途:
for (int i = 0; i < myList.size(); i++) { Car c = new Car( car.get(i).getId(),car.get(i).getName() ); getCurrentSession().save(c); if (i % 20 == 0) getCurrentSession().flush(); }
这是否意味着在迭代20之后,刷新缓存,然后20个持有的内存对象实际上保存在数据库中?
有人可以向我解释当条件成立时会发生什么。
从Session#flush
的javadoc:
强制此会话刷新。 必须在提交事务并关闭会话之前在工作单元的末尾调用(取决于flush-mode , Transaction.commit()调用此方法)。
刷新是将底层持久存储与内存中保持的可持久状态同步的过程。
换句话说, flush
告诉Hibernate执行将JDBC连接的状态与会话级缓存中保存的对象的状态同步所需的SQL语句。 条件if (i % 20 == 0)
将使每20的每个倍数发生。
但是,仍然,新的Car
实例将保存在会话级缓存中,对于大的myList.size()
,您将吃掉所有内存并最终获得OutOfMemoryException
。 为了避免这种情况,文档中描述的模式是定期flush
AND clear
会话(与JDBC批处理大小相同)以保留更改,然后分离实例以便可以对它们进行垃圾回收:
13.1。 批量插入
在使新对象持久化flush()然后清除()会话时,为了控制第一级缓存的大小。
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();
该文档在同一章中提到了如何设置JDBC批处理大小。
也可以看看
- 10.10。 刷新会话
- 第13章批处理
取决于如何设置FlushMode。
在默认配置中,Hibernate尝试在三个位置与数据库同步。
1. before querying data 2. on commiting a transaction 3. explictly calling flush
如果FlushMode
设置为FlushMode.Manual,则程序员通知hibernate他/她将处理何时将数据传递到数据库。在此配置下, session.flush()
调用将对象实例保存到数据库。
可以使用session.clear()
调用来清除持久性上下文。
// Assume List to be of 50 for (int i = 0; i < 50 ; i++) { Car c = new Car( car.get(i).getId(),car.get(i).getName() ); getCurrentSession().save(c); // 20 car Objects which are saved in memory syncronizes with DB if (i % 20 == 0) getCurrentSession().flush(); }
关于为什么刷新应该与批量大小匹配的更多指针要启用批处理,您需要设置jdbc批处理大小
// In your case hibernate.jdbc.batch_size =20
使用批处理的一个常见缺陷是,如果您使用单个对象更新或插入这很好。但是如果您使用多个对象导致多个插入/更新,那么您将必须显式设置排序机制。
例如
// Assume List to be of 50 for (int i = 0; i < 50 ; i++) { Car c = new Car( car.get(i).getId(),car.get(i).getName() ); // Adding accessory also in the card here Accessories a=new Accessories("I am new one"); c.add(a); // Now you got two entities to be persisted . car and accessory // Two SQL inserts getCurrentSession().save(c); // 20 car Objects which are saved in memory syncronizes with DB // Flush here clears the car objects from 1st level JVM cache if (i % 20 == 0) getCurrentSession().flush(); getCurrentSession().clear(); }
在这种情况下,在这种情况下生成两个sql用于插入汽车1中以插入附件中
要进行正确的批处理,您必须设置
true
所以汽车的所有插件都被整理在一起,并且所有附件的插件都被分类在一起。通过这样做你将有20个插件批量发射,而不是一次一个sql发射。
对于一个事务下的不同操作,您可以查看http://docs.jboss.org/hibernate/core/3.2/api/org/hibernate/event/def/AbstractFlushingEventListener.html
是每20个循环,为未保存的对象生成并执行sql。 您还应将批处理模式设置为20以提高性能。
- Hibernate使用新生成的ID将对象值复制到新对象中
- PostgreSQL串行类型的Hibernate注释
- 如何在Hibernate中设置内部查询的限制?
- 如何使用hibernate.properties文件而不是hibernate.cfg.xml
- hibernate OneToMany标准返回重复项
- ClassCastException:org.springframework.orm.jpa.EntityManagerHolder无法强制转换为org.springframework.orm.hibernate5.SessionHolder
- 如何在Hibernate条件api查询中插入“优化器提示”
- 理解注释和JPA(hibernate)
- Hibernate外键与复合主键的一部分