刷新后,hibernate不会发出更新

时间:2012-07-04 12:31:17

标签: java spring hibernate jpa jta

我正在使用带有spring 3.0.1的hibernate 3.2.7(3.2.5上的相同问题),所有这些都部署在weblogic 10.3和Oracle 10g数据库上。我正在使用JTA事务管理并且事务是分布式的(它实际上是在另一个应用程序中启动和结束,这段代码介于两者之间)。

hibernate使用的配置在我的persistence.xml中声明,如下所示:

<property name="hibernate.dialect" value="org.hibernate.dialect.Oracle10gDialect"/>
<property name="hibernate.transaction.manager_lookup_class" value="org.hibernate.transaction.WeblogicTransactionManagerLookup"/>
<property name="hibernate.query.factory_class" value="org.hibernate.hql.classic.ClassicQueryTranslatorFactory"/>
<property name="hibernate.current_session_context_class" value="jta"/>
<property name="hibernate.connection.release_mode" value="auto"/>

关于事务管理器的弹簧配置如下:

<!-- Instructs Spring to perfrom declarative transaction managemenet on annotated classes -->
<tx:annotation-driven transaction-manager="txManager" proxy-target-class="true"/>

<!-- Data about transact manager and session factory -->
<bean id="txManager" class="org.springframework.transaction.jta.WebLogicJtaTransactionManager">
  <property name="transactionManagerName" value="javax.transaction.TransactionManager"/> 
  <property name="defaultTimeout" value="${app.transaction.timeOut}"/>
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  <!-- persistence unit is missing jta data source so that application server is not 
      creating EntitiyManagerFactory, spring will create its own LocalContainerEntityManagerFactoryBean overriding data source-->
  <property name="dataSource" ref="myDataSource"/>
  <!-- specific properties like jpa provider and jpa provider properties are in persistance unit -->
  <property name="persistenceUnitName" value="my.persistence.unit"/>
</bean>


<!-- define data source in application server -->
<jee:jndi-lookup id="myDataSource" jndi-name="${db.jndiName}"/>

我正在使用通用的CrudDao,其更新方法如下所示:

public void update(Object entity) {
    //entityManager injected by @PersistenceContext
    entityManager.merge(entity);
    entityManager.flush();
}

public Object getById(Object id, Class entityClass) throws PersistenceException{
    return (Object)entityManager.find(entityClass, id);
}

更新:添加了getById方法。

不能按预期工作的代码如下所示:

MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther);
// till now was null
myObj.setSomeDateAttr(someDate);
genericDao.update(myObj); 

MyObject myObjFromDB = genericDao.getById(myObj.getId(), MyObject.class);

结果是如果我打印myObj.getSomeDateAttr()它会返回someDate的值,如果我打印myObjFromDB.getSomeDateAttr()它仍然为null。

我尝试将更新方法更改为:

org.hibernate.Session s = (org.hibernate.Session) entityManager.getDelegate();
s.evict(entity);
s.update(entity);
s.flush();

它仍然不起作用。

当打开hibernate的show_sql标志时,我没有看到在执行flush时发生任何更新,也没有在实体管理器中查询具有相同id的对象时。选择都是可见的。 更新: 在事务结束时,实际调用更新,并将所有内容写入db。所以我的问题是在交易期间“正好”。

我担心这个问题可能与spring和hibernate上的事务管理器配置有关。

希望有人可以帮助我,因为我已经失去了一天半没有运气。

1 个答案:

答案 0 :(得分:2)

您需要仔细查看hibernate合并行为。根据文件

  • 如果当前存在具有相同标识符的持久性实例 与会话相关联,将给定对象的状态复制到 持久化实例
  • 如果当前没有与会话关联的持久性实例,请尝试从数据库加载它,或者创建新的持久性实例
  • 返回持久化实例
  • 给定的实例不会与会话相关联,它 保持独立

根据你在日志中对sql查询的陈述,它看起来像 MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne,idOther);返回持久对象但是当您修改它(变脏)并调用merge方法时,会将新状态复制到会话中的当前持久对象。如果你看到第三点合并返回持久对象,它实际上是你需要在后续操作中使用的新的可管理持久对象。

当你调用find方法时,hibernate返回会话中的持久对象,而不是maneagable持久对象,这就是为什么你没有找到对象返回的变化。

要修复问题,请更改更新方法的转储类型

public Object update(Object entity) { 
    //entityManager injected by @PersistenceContext 
    return  entityManager.merge(entity); 
}

并且在服务中你需要使用如下

MyObject myObj = getMyObjectThroughSomeOneToManyRelation(idOne, idOther); 
// till now was null 
myObj.setSomeDateAttr(someDate); 
//You can use myObj as well instead myNewObj
MyObject myNewObj= genericDao.update(myObj);  
 //No need to call get
//MyObject myObjFromDB = genericDao.getById(myObj.getId(), MyObject.class); 
System.out.println("Updated value:"+myNewObj.getSomeDateAttr());

同时查看此artical