1

我具有以下代码和休眠配置的等效项(基本上, StreamRef 属于磁带,并且在该磁带上必须是唯一的):

<class name="StreamRef" table="StreamRefToTape">
 <composite-id> <key-property name="UUID"/> 
   <key-many-to-one class="Tape" name="tape">
     <column name="Tape_TapeId" not-null="true"/>
   </key-many-to-one>
 </composite-id>
 ...</class>

 <class name="Tape" table="Tape">
 <id column="TapeId" name="tapeId"/></class>

我有数百万个这样的 StreamRef,我想将它们全部保存在同一个事务中,但我也想在此事务期间保存在 RAM 上。

所以我尝试了下面的代码,我的假设是如果我关闭 CacheMode,那么它不会在内部跟踪对象,所以它会节省大量的 RAM(这在某种程度上似乎有帮助)。但是在测试这个假设时,像这样:

 session = sessionFactory.openSession();
 session.setCacheMode(CacheMode.IGNORE);   // disable the first level cache
 session.beginTransaction();
 Tape t = new Tape();
 StreamRef s1 = new StreamRef("same uuid");
 StreamRef s2 = new StreamRef("same uuid"); // force a primary key collision
 session.saveOrUpdate(t);
 for(StreamRef s : t.getStreams()) {
     session.save(s);
 }
 session.commit();

我本以为这不会引发,因为我关闭了 CacheMode (但它引发了 NonUniqueObjectException https://gist.github.com/4542569)。有人可以确认1)休眠内部缓存不可禁用吗?2)这个异常与CacheMode无关?有什么方法可以在这里完成我想要的(在事务中不使用大量的休眠 RAM?)

有点相关:https ://stackoverflow.com/a/3543740/32453

(作为一个附带问题...... setCacheMode 被称为 vin 与 beginTransaction 关系的顺序是否重要?我认为它不重要?)

非常感谢。

4

2 回答 2

1

例外是有道理的。你违反了你告诉 Hibernate 你要遵守的规则。如果你真的想做你编写的代码,你需要使用 StatelessSession API 或 createSQLQuery API。就目前而言, Session.setCacheMode 用于与二级缓存交互,而不是会话缓存。

关于内存使用,您需要逐步将成批的记录刷新到磁盘,以便 Hibernate 可以清除其ActionQueue

以下是用户指南中批量更新部分的示例:

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

您还可以在同一章中阅读有关无状态会话的内容。

于 2013-01-15T03:25:16.163 回答
1

Hibernate 将一次保存所有会话对象...缓存将为其他会话存储对象...因此您不能禁用单个会话的对象...您不能尝试使用 merge()... .

于 2013-01-15T03:32:44.590 回答