【问题标题】:Data persisting in session object of hibernate after the request is processed处理请求后数据持久保存在hibernate的会话对象中
【发布时间】:2017-03-16 09:19:02
【问题描述】:

我最近开始从事一个使用 SOAP Web 服务、Spring 和 Hibernate 的项目。

我面临以下问题:

我们使用 SOAP UI 发送请求来测试我们的代码。我写了一个处理账单的服务。基本上有 2 种服务,一种是创建账单,另一种是创建账单。

我们有一个名为BillTb 的表。在处理账单之前,我们会检查账单的状态。如果账单状态为 3(待处理),我们会对其进行处理。如果它不等于 3,我们不处理它。处理完帐单后,我们将状态更改为 4(已处理)。

现在如果账单状态为 3,我们在其他表中做一些条目,最后状态变为 4。

如果在处理之间,如果处理失败,我们需要还原所有这些条目。所以我们在一个事务中调用这些条目。

带有hibernate代码的DAO层如下:

    import javax.persistence.EntityManager;
    import javax.persistence.PersistenceContext;
    import javax.persistence.PersistenceContextType;
    import javax.persistence.Query;

        @PersistenceContext(type = PersistenceContextType.EXTENDED)
            private EntityManager entityManager;

        public class BillDAOImpl implements BillDao {

        ...
        ...
        ...

        int pendingStatus = 3;
        int processedStatus = 4;

        Session session = null;

        for(int id: ids){

           Bill bill = null;


        try{
          session = entityManager.unwrap(Session.class);

          bill= entityManager.find(Bill.class, id);

           session.getTransaction().begin();

          if(bill.status() != pendingStatus ){
             System.out.println("The bill is already processed");
        continue;
          }
        ...
...
bill.setStatus(processedStatus);
entityManager.persist(bill);

          session.getTransaction().commit();

        } catch(Exception e){

        }

        }




        }

现在的问题是,一旦账单状态从 3 更改为 4,如果我通过在数据库中触发更新查询将状态再次更改为 3,它应该再次工作,但不知何故,它只将状态读取为 4 .

如果我关闭服务器,然后再次执行请求,则它适用于相同的条目。

其他交易相关参数设置为:

<property name="hibernate.cache.use_query_cache" value="false" />

还有,

<bean id="projectEntityManagerFactory"
        class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
        p:persistenceXmlLocation="classpath*:META-INF/persistence.xml"
        p:persistenceUnitName="persistenceUnit" p:loadTimeWeaver-ref="loadTimeWeaver"
        p:jpaVendorAdapter-ref="jpaVendorAdapter" p:jpaDialect-ref="jpaDialect"
        p:dataSource-ref="datasourceBean">
        <property name="jpaProperties">
            <props>
                <prop key="hibernate.transaction.manager_lookup_class">org.hibernate.transaction.BTMTransactionManagerLookup
                </prop>
                <prop key="hibernate.transaction.flush_before_completion">false</prop>
                ...
                ...             
                <prop key="hibernate.connection.isolation">3</prop>
                <prop key="hibernate.connection.release_mode">auto</prop>
            </props>
        </property>
    </bean>

所以这里似乎会话以某种方式存储账单对象,当我直接在数据库中更新账单对象时,它存储了陈旧的数据。那么在这种情况下应该怎么做。我应该在方法结束时清除会话吗?

【问题讨论】:

  • 状态变化发生在哪里?尝试添加 impl
  • 我已经更新了代码。状态在事务提交之前更新。
  • 你为什么要同时使用 EntitymanagerSession... 你在另一个对象上重新开始会话。我强烈建议清理您的代码(使用EntityManager,不要将其解包到Session

标签: java spring hibernate web-services soap


【解决方案1】:

你应该在事务内部执行查询,并且记得每次都提交事务(如果你触发了继续,那就省略了)。

其实我会这样写:

    for(int id: ids){

        Bill bill = null;

        Transaction tx = session.getTransaction();
        tx.begin();

        try{          
          bill= entityManager.find(Bill.class, id);

          if(bill.status() != pendingStatus ){
             System.out.println("The bill is already processed");
             tx.commit();
             continue;
          }

          bill.setStatus(processedStatus);
          entityManager.persist(bill);   

          session.flush();
          tx.commit();
        }catch(Exception e){
          tx.rollback();
          throw e;
        }
    }

【讨论】:

  • 这似乎有效。只有最后一个问题,如果我把它放在最后,它总是会尝试提交事务。如果有异常,它会进入 Catch 块并且会有回滚。所以我不能最终提交..所以任何解决方案。
  • 这里有 2 个 try 块,一个没有 finally 或 catch 块。我认为它会给出编译错误。我尝试了许多组合,但无法弄清楚在哪里刷新会话。上面的那个是行不通的,因为如果有一张账单成功处理而另一张失败了,它会回滚这两个账单对象,因为事务是在外面提交的。
  • 好的,如果你想在每次迭代后提交,那么我已经稍微更新了答案
猜你喜欢
  • 1970-01-01
  • 2014-04-01
  • 2012-01-14
  • 2011-05-30
  • 2022-11-28
  • 2011-09-04
相关资源
最近更新 更多