关于Hibernate session.flush()

yhuiod9q  于 2023-10-23  发布在  其他
关注(0)|答案(4)|浏览(150)

我想知道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个持有的内存对象实际上被保存在数据库中?
有人能告诉我当条件成立时会发生什么吗?

bvjxkvbb

bvjxkvbb1#

Session#flush的javadoc:
强制刷新此会话。必须在工作单元结束时,在提交事务和关闭会话之前调用(根据刷新模式,Transaction.commit()调用此方法)。

  • Flushing* 是将底层持久存储与内存中保存的持久状态同步的过程。

换句话说,flush告诉Hibernate执行同步JDBC连接状态和会话级缓存中对象状态所需的SQL语句。条件if (i % 20 == 0)会使每一个20的i倍数都发生。
但是,新的Car示例仍将保存在会话级缓存中,对于大的myList.size(),您将占用所有内存并最终获得OutOfMemoryException。为了避免这种情况,文档中描述的模式是以固定的间隔(与JDBC批处理大小相同)flushANDclear会话,以持久化更改,然后分离示例,以便它们可以被垃圾收集:

13.1.批量插入

当使新对象持久化时,定期地flush()然后clear()会话,以控制一级缓存的大小。

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批处理大小。

参见

cunj1qz1

cunj1qz12#

取决于冲洗模式的设置方式。
在默认配置中,Hibernate尝试在三个位置与数据库同步。

1. before querying data
2. on committing a transaction
3. explicitly calling flush

如果FlushMode设置为FlushMode.Manual,程序员通知hibernate他/她将处理何时将数据传递到数据库。在这种配置下,session.flush()调用将把对象示例保存到数据库中。
session.clear()调用实际上可以用来清除持久化上下文。

lyfkaqu1

lyfkaqu13#

// 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

在使用SQL的过程中,一个常见的陷阱是如果你使用的是单个对象update或insert,这很好。但是如果你使用的是多个对象,导致多个insert/update,那么你就必须显式地设置排序机制。
例如

// 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用于插入汽车1用于插入附件
为了正确的安装,您必须设置

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

这样所有car的insert和所有accessories的insert就被排序在一起了。这样你就有20个insert在一个批次中触发,而不是一次触发1个sql。
对于一个事务下的不同操作,您可以查看http://docs.jboss.org/hibernate/core/3.2/api/org/hibernate/event/def/AbstractFlushingEventListener.html

oipij1gg

oipij1gg4#

是的,每20次循环,SQL都会为未保存的对象生成并执行。您还应该将批处理模式设置为20以提高性能。

相关问题