1

我正在使用带有 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"/>

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

<!-- 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 标志时,在执行刷新时或在实体管理器中查询具有相同 ID 的对象时,我看不到任何更新。选择都是可见的。更新:在事务结束时,实际上调用了更新并将所有内容写入数据库。所以我的问题是在交易过程中“只是”。

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

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

4

1 回答 1

2

您需要仔细查看休眠合并行为。根据文档

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

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

当您调用 find 方法时,休眠返回会话中的持久对象而不是可管理的持久对象,这就是为什么您找不到通过 find 返回的对象中的更改。

要解决您的问题,请更改更新方法的重复类型

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());

也看看这篇文章

于 2012-07-04T17:21:30.920 回答