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

Java org.hibernate.Session.clear()被认为有害吗?,java,hibernate,session,Java,Hibernate,Session,这是一个设计问题,具体代码没有提交保护我的底部 使用Hibernate时,标准工作流如下所示: 公开会议 启动事务 开展业务(读取和修改数据) 提交事务 闭门会议 可能通过2-4次迭代 Session.clear()的合理用例是什么 答:我遇到的具体问题是一段(很大的)代码,它加载和修改实体,然后清除()会话,基本上丢弃了所做的更改。(要完成的业务任务不包括修改实体,因此代码“起作用”) 在我看来,正确的设计应该是确保(大的)代码不会做出它不想保存的更改 我猜Session.clear()的存在

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

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

  • 公开会议
  • 启动事务
  • 开展业务(读取和修改数据)
  • 提交事务
  • 闭门会议
  • 可能通过2-4次迭代

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

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

    在我看来,正确的设计应该是确保(大的)代码不会做出它不想保存的更改

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

    我是否误解了冬眠哲学

    C:子问题:当任务完成时,框架代码无条件地清除()会话是个坏主意吗?嗯,如果任务完成时会话脏了,框架应该抱怨!任务完成后,会话应关闭。。。(不考虑会议记录的执行情况)


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

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

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

    您也可以使用

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

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


    Ad.C:当用户用脏的更改清除会话时,警告用户(可能通过发出警告消息而不是抛出异常)实际上是个好主意。另外,我认为框架代码不应该无条件地调用
    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<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();
    
    //开始事务
    SessionFactory sf=HibernateSessionFactory.getFactory();
    会话dbSession=sf.getCurrentSession();
    dbSession.beginTransaction();
    //对存储过程的第一次调用
    Query Query=dbSession.getNamedQuery(“RR_CUST_OPP_DATA”);
    query.setString(“custName”、“A”);
    List shipSummaryRows=query.List();
    //对存储过程的第二次调用
    Query Query=dbSession.getNamedQuery(“RR_CUST_OPP_DATA”);
    query.setString(“custName”、“B”);
    List shipSummaryRows=query.List();
    //两者都犯
    dbSession.getTransaction().commit();
    
    如果第一次调用后没有clear(),第一次调用的resultset行将复制到第二次调用的resultset中。我正在使用Oracle 11gR2

    复制此错误的关键是在同一事务中进行两次调用。因为我使用的是视图模式中的开放会话,所以两个调用都会在同一事务中自动发生(因为原始代码在存储每个调用结果的循环中调用proc)。因此我称之为虫子;else可以被视为一个特性,但即使如此,clear()也不会在声明应该调用它的代码示例中被调用。session.flush()未执行任何操作。 映射文件如下所示。因此,我在所有过程调用的末尾添加了clear()。尚未使用我的自定义SQL调用进行测试。这是琐碎的东西;令人惊讶的是,这个bug居然存在

    <?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>
    
    
    {调用RR_DASHBOARD_REPORTS_PKG.RR_CUST_OPP_DATA(?,:custName)}
    
    ad A):在一个事务中处理大型数据集对我来说听起来像是糟糕的设计(当然,我可能没有想到所有可能的问题…)。“显式”持久化实体是什么意思?会话。是否保存(实体)?Ad C):听起来我们同意框架不应该这样做-框架不可能确定客户端做什么。:-)@Mortenlaurisenkhodabocus:显然,在一个Hibernate事务中加载和修改数千条记录是应该使用不同工具的标志。是的,我的意思是显式地调用
    save()
    ,而不是让Hibernate发现脏的实体。@Mortenlaurisenkhodabocus请告诉我。为什么在一个事务中处理大型只读数据集是个坏主意?在我看来,如果它涉及到数据库端的订购,那么它将是智能的,因为它将避免需要多次重新订购。使用事务难道不意味着DB会在属于同一事务的不同查询中记住您的有序状态吗?另外,“使用一个事务”不正是Hibernate的ScrollableResults API所做的吗?