org.hibernate.Session.clear()被认为有害吗?

这是一个设计问题,没有提交具体代码来保护我的底线。

使用Hibernate时,标准工作流程如下:

  1. 公开会议
  2. 开始交易
  3. 做生意(阅读和修改数据)
  4. 提交交易
  5. 关闭会话

可能迭代到2-4。

Session.clear()的合理用例是什么?

答:我遇到的具体问题是一段(大)代码,它加载并修改实体,然后清除()会话,基本上抛弃了所做的更改。 (要完成的业务任务不包括修改实体,因此代码“有效”)。

在我看来,正确的设计是确保(大)代码不会进行不想保存的更改?

B:我猜想Session.clear()是为了方便/灵活而存在,不是因为使用它是个好主意。

我误解了Hibernate的理念吗?

C:Subquestion:框架代码在任务完成时无条件清除()会话是不是一个坏主意? 恕我直言,如果任务完成时会话是脏的,框架应该抱怨! 应该关闭会话,看看任务完成…(忽略分钟的表现)

(标签A,B和C,以便您可以指出您要回答的部分)。

广告。 :看起来你知道clear()作用。 明确调用它的原因是从L1缓存中删除所有托管实体,以便在一个事务中处理大型数据集时它不会无限增长。

它会丢弃对未明确保留的托管实体所做的所有更改。 这意味着您可以安全地修改实体,明确更新它并清除会话。 这是正确的设计。 显然,如果没有进行任何更改(长,但只读会话), clear()始终是安全的。

您还可以使用无状态会话 。

广告。 B :不,它存在的原因如上:确保L1(会话缓存)不会增长太多。 当然,手动维护它是一个糟糕的想法,并表明另一个工具应该用于大型数据集,但有时它是必须的。

请注意,在JPA规范中还有clear()flush()方法。 在这种情况下,在调用clear()之前,应始终先调用flush()将更改推送到数据库(显式更新clear()

广告。 C :当他/她用肮脏的变化清除会话时,警告用户(可能通过发出警告消息而不是抛出exception)实际上是一个好主意。 此外,我不认为框架代码应该无条件地调用clear() ,除非它确定它运行的用户代码刷新或不做任何更改。

这是我刚遇到的另一个原因:在同一事务中多次调用存储过程时缓存以前的结果。 简化代码如下。

 //Begin transaction SessionFactory sf = HibernateSessionFactory.getFactory(); Session dbSession = sf.getCurrentSession(); dbSession.beginTransaction(); //First call to stored procedure Query query = dbSession.getNamedQuery("RR_CUST_OPP_DATA"); query.setString("custName", "A"); List shipSummaryRows = query.list(); //Second call to stored procedure Query query = dbSession.getNamedQuery("RR_CUST_OPP_DATA"); query.setString("custName", "B"); List shipSummaryRows = query.list(); //Commit both dbSession.getTransaction().commit(); 

在第一次调用之后没有clear(),第一次调用的结果集行被复制到第二次调用的结果集中。 我正在使用Oracle 11gR2。

复制此错误的关键是在同一事务中进行两次调用。 由于我在视图模式中使用开放会话,因此两个调用都在同一事务中自动发生(因为原始代码在存储每个结果的循环中调用proc)。 因此我称之为虫子; else可以被认为是一个特性,但即使这样,在代码样本中也没有调出clear(),表明它应该被调用。 session.flush()什么也没做。 映射文件如下。 结果我在所有程序调用结束时添加了clear()。 尚未使用我的自定义SQL调用进行测试。 这是微不足道的东西; 惊讶于这个bug存在。

               { call RR_DASHBOARD_REPORTS_PKG.RR_CUST_OPP_DATA(?, :custName) }