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

时间:2011-11-14 07:20:35

标签: java hibernate session clear

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

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

  1. 公开会话
  2. 开始交易
  3. 做生意(阅读和修改数据)
  4. 提交交易
  5. 关闭会话
  6. 可能迭代到2-4。

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

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

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

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

    我是否误解了Hibernate哲学?

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

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

2 个答案:

答案 0 :(得分:29)

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

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

您也可以使用stateless sessions

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

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

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

答案 1 :(得分:3)

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

//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<ShipSummaryRow> shipSummaryRows = query.list();

//Second call to stored procedure
Query query = dbSession.getNamedQuery("RR_CUST_OPP_DATA");
query.setString("custName", "B");
List<ShipSummaryRow> shipSummaryRows = query.list();

//Commit both    
dbSession.getTransaction().commit();

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

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

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
    <class name="com.jfx.rr.model.ShipSummaryRow">
        <id name="id" type="integer"/>
        <property name="shipQtrString" not-null="true" type="string"/>
        <property name="shipAmount" not-null="true" type="double"/>
    </class>
    <sql-query callable="true" name="RR_CUST_OPP_DATA">
        <return class="com.jfx.rr.model.ShipSummaryRow">
            <return-property column="SHIPPED_ID" name="id"/>
            <return-property column="SHIP_QTR" name="shipQtrString"/>
            <return-property column="SHIPPED_AMOUNT" name="shipAmount"/>
        </return>
        { call RR_DASHBOARD_REPORTS_PKG.RR_CUST_OPP_DATA(?, :custName) }
    </sql-query>
</hibernate-mapping>