简体   繁体   English

关于Hibernate session.flush()的问题

[英]Question about Hibernate session.flush()

I want to inquire about what actually the flush method does in the following case: 我想询问以下情况下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();
}

Does this means that after the iteration 20, the cache is flushed, and then the 20 held memory objects are actually saved in the database ? 这是否意味着在迭代20之后,刷新缓存,然后20个持有的内存对象实际上保存在数据库中?

Can someone please explain to me what will happen when the condition is true. 有人可以向我解释当条件成立时会发生什么。

From the javadoc of Session#flush : Session#flush的javadoc:

Force this session to flush. 强制此会话刷新。 Must be called at the end of a unit of work, before committing the transaction and closing the session (depending on flush-mode , Transaction.commit() calls this method). 必须在提交事务并关闭会话之前在工作单元的末尾调用(取决于flush-modeTransaction.commit()调用此方法)。

Flushing is the process of synchronizing the underlying persistent store with persistable state held in memory. 刷新是将底层持久存储与内存中保持的可持久状态同步的过程。

In other words, flush tells Hibernate to execute the SQL statements needed to synchronize the JDBC connection's state with the state of objects held in the session-level cache. 换句话说, flush告诉Hibernate执行将JDBC连接的状态与会话级缓存中保存的对象状态同步所需的SQL语句。 And the condition if (i % 20 == 0) will make it happen for every i multiple of 20. 并且if (i % 20 == 0)将使每20的每个i倍数发生。

But, still, the new Car instances will be held in the session-level cache and, for big myList.size() , you're going to eat all memory and ultimately get an OutOfMemoryException . 但是,仍然,新的Car实例将保存在会话级缓存中,对于大的myList.size() ,您将吃掉所有内存并最终获得OutOfMemoryException To avoid this situation, the pattern described in the documentation is to flush AND clear the session at regular intervals (same size as the JDBC batch size) to persist the changes and then detach the instances so that they can be garbage collected: 为了避免这种情况,文档中描述的模式是定期flush AND clear会话(与JDBC批处理大小相同)以保留更改,然后分离实例以便可以对它们进行垃圾回收:

13.1. 13.1。 Batch inserts 批量插入

When making new objects persistent flush() and then clear() the session regularly in order to control the size of the first-level cache. 在使新对象持久化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(); 

The documentation mentions in the same chapter how to set the JDBC batch size. 该文档在同一章中提到了如何设置JDBC批处理大小。

See also 也可以看看

Depends on how the FlushMode is set up. 取决于如何设置FlushMode。

In default configuration Hibernate tries to sync up with the database at three locations. 在默认配置中,Hibernate尝试在三个位置与数据库同步。

1. before querying data
2. on commiting a transaction
3. explictly calling flush

If the FlushMode is set as FlushMode.Manual, the programmer is informing hibernate that he/she will handle when to pass the data to the database.Under this configuration the session.flush() call will save the object instances to the database. 如果FlushMode设置为FlushMode.Manual,则程序员通知hibernate他/她将处理何时将数据传递到数据库。在此配置下, session.flush()调用将对象实例保存到数据库。

A session.clear() call acutally can be used to clear the persistance context. 可以使用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();

}

Few more pointers regarding why the flushing should match batch size To enable batching you need to set the jdbc batch size 关于为什么刷新应该与批量大小相匹配的更多指针要启用批处理,您需要设置jdbc批量大小

// In your case 
hibernate.jdbc.batch_size =20

One common pitfall in using batching is if you are using single object update or insert this goes fine.But in case you are using mutiple objects leading to multiple inserts /updates then you will have to explicitly set the sorting mechanism. 使用批处理的一个常见缺陷是,如果您使用单个对象更新或插入这很好。但是如果您使用多个对象导致多个插入/更新,那么您将必须显式设置排序机制。

For example 例如

// 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();
    }

Here in this case two sql are generated 1 for insert in car 1 for insert in accessory 在这种情况下,在这种情况下生成两个sql用于插入汽车1中以插入附件中

For proper batching you will have to set the 要进行正确的批处理,您必须设置

<prop  key="hibernate.order_inserts">true</prop>

so that all the inserts for car is sorted together and all inserts of accessories are sorted together.By doing so you will have 20 inserts firing in a batch rather then 1 sql firing at a time. 所以汽车的所有插件都被整理在一起,并且所有附件的插件都被分类在一起。通过这样做你将有20个插件批量发射,而不是一次一个sql发射。

For different operation under one transaction, you can have a look at http://docs.jboss.org/hibernate/core/3.2/api/org/hibernate/event/def/AbstractFlushingEventListener.html 对于一个事务下的不同操作,您可以查看http://docs.jboss.org/hibernate/core/3.2/api/org/hibernate/event/def/AbstractFlushingEventListener.html

Yes every 20 loop, sql is generated and executed for the unsaved objects. 是每20个循环,为未保存的对象生成并执行sql。 Your should also set batch mode to 20 to increase performances. 您还应将批处理模式设置为20以提高性能。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM