我正在使用带有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上的事务管理器配置有关。
希望有人可以帮助我,因为我已经失去了一天半没有运气。
答案 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。