【问题标题】:how is Hibernate able to throw a NonUniqueObjectException with setCacheMode(CacheMode.IGNORE)?Hibernate 如何使用 setCacheMode(CacheMode.IGNORE) 抛出 NonUniqueObjectException?
【发布时间】:2013-01-16 06:06:59
【问题描述】:

我有以下代码和休眠配置的等效项(基本上,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 关系的顺序是否重要?我认为它不重要?)

非常感谢。

【问题讨论】:

  • 如果你使用session.merge()而不是session.save()会怎样
  • 以某种方式合并相等性检查比较失败。嗯...gist.github.com/4542563

标签: java hibernate


【解决方案1】:

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

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

这是user's guide 中关于批量更新部分的示例:

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

您还可以在同一章节中了解无状态会话。

【讨论】:

  • 真棒高质量的答案,谢谢!我想既然我在 hibernate.cfg.xml 中指定了 org.hibernate.cache.NoCacheProvider ,无论如何我设置缓存模式也没关系,所以基本上这是一次失败的初步尝试。谢谢!另一种选择是(定期或针对每个元素)flush(),然后对我添加的每个项目进行驱逐(这与我想象的 clear() 相同,您列出的方式也允许批量插入)。
【解决方案2】:

Hibernate 将一次保存所有会话对象...缓存将为其他会话存储对象...所以你不能为单个会话禁用你的...你不能这样做尝试使用 merge() ....

【讨论】:

    猜你喜欢
    • 2011-04-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多