休眠和弹簧持久性问题。可能的身份值没有增加?
Posted
技术标签:
【中文标题】休眠和弹簧持久性问题。可能的身份值没有增加?【英文标题】:hibernate and spring persistance problem. Possible identity value not incremented? 【发布时间】:2009-10-13 16:57:44 【问题描述】:我使用的是 hibernate 3.2.6 和 spring 2.5.6 我连接的数据库是:DB2 for Z OS 390 V8.1
当我运行我的测试用例(如下)时,我保存了测试文件对象。 Hibernate DOES 将对象保存到数据库,但我的测试在保存后失败,它试图用正确的 id 更新对象。我认为它没有获得正确的 id(看起来它的 id 为“0”),或者我什至不确定它为什么要尝试更新已经持久化的对象。我不知道这是否是 spring、hibernate、映射、方言或其他问题。
我的配置:
业务对象:
<hibernate-mapping>
<class name="cat.edis.tmiweb.business.File" table="FILE">
<id name="id" type="java.lang.Long" column="gen_file_id">
<generator class="native"></generator>
</id>
<property name="creationTimeStamp" type="java.util.Date" column="crte_ts" />
<property name="name" type="java.lang.String" column="file_nm" />
<property name="type" type="java.lang.String" column="file_typ_desc" />
<property name="description" type="java.lang.String" column="file_desc" />
<property name="length" type="java.lang.Long" column="file_lgth" />
<property name="contentBlob" type="blob" column="file_cntnt" />
</class>
</hibernate-mapping>
宝乔:
/*
* Created on Oct 9, 2009
*
*/
package cat.edis.tmiweb.business;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Blob;
import java.sql.SQLException;
import java.util.Date;
import org.hibernate.Hibernate;
/**
* @author dudekta
*/
public class File
private Long id;
private Date creationTimeStamp;
private String name;
private String type;
private String description;
private Long length;
private byte[] content;
/** Don't invoke this. Used by Hibernate only. */
public void setContentBlob(Blob imageBlob)
this.content = this.toByteArray(imageBlob);
/** Don't invoke this. Used by Hibernate only. */
public Blob getContentBlob()
return Hibernate.createBlob(this.content);
private byte[] toByteArray(Blob fromBlob)
ByteArrayOutputStream baos = new ByteArrayOutputStream();
try
return toByteArrayImpl(fromBlob, baos);
catch (SQLException e)
throw new RuntimeException(e);
catch (IOException e)
throw new RuntimeException(e);
finally
if (baos != null)
try
baos.close();
catch (IOException ex)
private byte[] toByteArrayImpl(Blob fromBlob, ByteArrayOutputStream baos)
throws SQLException, IOException
byte[] buf = new byte[4000];
InputStream is = fromBlob.getBinaryStream();
try
for (;;)
int dataSize = is.read(buf);
if (dataSize == -1)
break;
baos.write(buf, 0, dataSize);
finally
if (is != null)
try
is.close();
catch (IOException ex)
return baos.toByteArray();
/**
* @return Returns the creationTimeStamp.
*/
public Date getCreationTimeStamp()
return creationTimeStamp;
/**
* @param creationTimeStamp
* The creationTimeStamp to set.
*/
public void setCreationTimeStamp(Date creationTimeStamp)
this.creationTimeStamp = creationTimeStamp;
/**
* @return Returns the description.
*/
public String getDescription()
return description;
/**
* @param description
* The description to set.
*/
public void setDescription(String description)
this.description = description;
/**
* @return Returns the id.
*/
public Long getId()
return id;
/**
* @param id
* The id to set.
*/
public void setId(Long id)
this.id = id;
/**
* @return Returns the length.
*/
public Long getLength()
return length;
/**
* @param length
* The length to set.
*/
public void setLength(Long length)
this.length = length;
/**
* @return Returns the name.
*/
public String getName()
return name;
/**
* @param name
* The name to set.
*/
public void setName(String name)
this.name = name;
/**
* @return Returns the type.
*/
public String getType()
return type;
/**
* @param type
* The type to set.
*/
public void setType(String type)
this.type = type;
/**
* @return Returns the content.
*/
public byte[] getContent()
return content;
/**
* @param content
* The content to set.
*/
public void setContent(byte[] content)
this.content = content;
应用程序上下文:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<!-- Webservices -->
<bean id="FPSService" class="cat.edis.tmiweb.services.fps.FPSServiceImpl">
<constructor-arg type="java.lang.String" value="http://localhost:8888/someendpoint" />
<constructor-arg type="java.lang.String" value="bill" />
<constructor-arg type="java.lang.String" value="will" />
</bean>
<!-- Database stuff that we should separate out-->
<bean id="fileDAO" class="cat.edis.tmiweb.dao.FileDAOImpl">
<property name="sessionFactory">
<ref bean="TMISessionFactory" />
</property>
</bean>
<bean id="TMIDataSource" class="cat.cis.template.spring.util.TUFDataSource" destroy-method="close">
<property name="poolName" value="db2OS390GenData" />
</bean>
<bean id="TMISessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="TMIDataSource" />
<property name="mappingResources">
<list>
<!-- PUT HIBERNATE MAPPING FILES HERE -->
<value>cat/edis/tmiweb/business/File.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<map>
<entry>
<key>
<value>hibernate.show_sql</value>
</key>
<value>true</value>
</entry>
<entry>
<key>
<value>hibernate.default_schema</value>
</key>
<value>N4GK001$</value>
</entry>
<entry>
<key>
<value>hibernate.dialect</value>
</key>
<ref bean="TMIDialect" />
</entry>
</map>
</property>
</bean>
<bean id="TMIDialect" factory-bean="TMIDialectFactory" factory-method="instance" />
<bean id="TMIDialectFactory" class="cat.cis.template.spring.util.EnvironmentBeanStrategyFactory">
<property name="envKey" value="tuf.environment" />
<property name="defaultKey" value="DEV" />
<property name="target">
<map>
<entry key="DEV" value="org.hibernate.dialect.DB2390Dialect" />
<entry key="TEST" value="org.hibernate.dialect.DB2390Dialect" />
<entry key="QA" value="org.hibernate.dialect.DB2390Dialect" />
<entry key="PROD" value="org.hibernate.dialect.DB2390Dialect" />
</map>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="TMISessionFactory" />
</property>
</bean>
</beans>
文件DAO:
/*
* Created on Oct 9, 2009
*/
package cat.edis.tmiweb.dao;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import cat.edis.tmiweb.business.File;
/**
* @author dudekta
*
*/
public class FileDAOImpl extends HibernateDaoSupport implements FileDAO
/**
*
* @param id
* @return
*/
public File load(Long id)
return (File) getHibernateTemplate().get(File.class, id);
/**
*
* @param file
* @return
*/
public void save(File file)
getHibernateTemplate().save(file);
我的测试:
public void testSaveBlob()
FileDAO fileDAO =(FileDAO)SpringTestInitializer.getContext().getBean("fileDAO");
File file = new File();
file.setName("TestMe");
file.setType("txt");
file.setCreationTimeStamp(new Date());
file.setDescription("idc");
byte[] testBytes = new byte[1024];
byte byteValue = 1;
for (int i = 0; i < testBytes.length; i++)
testBytes[i] = byteValue;
file.setLength(new Long(testBytes.length));
file.setContent(testBytes);
fileDAO.save(file);
File dbFile = fileDAO.load(file.getId());
assertNotNull(file);
从 Hibernate 输出到控制台:
Initializing Spring....
Spring test context created....
Hibernate: insert into N4GK001$.FILE (gen_file_id, crte_ts, file_nm, file_typ_desc, file_desc, file_lgth, file_cntnt) values (default, ?, ?, ?, ?, ?, ?)
Hibernate: select identity_val_local() from sysibm.sysdummy1
Hibernate: update N4GK001$.FILE set crte_ts=?, file_nm=?, file_typ_desc=?, file_desc=?, file_lgth=?, file_cntnt=? where gen_file_id=?
追踪:
org.springframework.dao.DataIntegrityViolationException: 无法更新: [cat.edis.tmiweb.business.File#0]; 嵌套异常是 org.hibernate.exception.DataException: 无法更新: [cat.edis.tmiweb.business.File#0] 在 org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:639) 在 org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412) 在 org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424) 在 org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374) 在 org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:694) 在 cat.edis.tmiweb.dao.FileDAOImpl.save(FileDAOImpl.java:31) 在 cat.edis.tmiweb.dao.FileDAOImplTest.testSaveBlob(FileDAOImplTest.java:50) 在 sun.reflect.NativeMethodAccessorImpl.invoke0(Native 方法)在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:85) 在 sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:58) 在 sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60) 在 java.lang.reflect.Method.invoke(Method.java:391) 在 junit.framework.TestCase.runTest(TestCase.java:154) 在 org.jmock.core.VerifyingTestCase.runBare(VerifyingTestCase.java:39) 在 junit.framework.TestResult$1.protect(TestResult.java:106) 在 junit.framework.TestResult.runProtected(TestResult.java:124) 在 junit.framework.TestResult.run(TestResult.java:109) 在 junit.framework.TestCase.run(TestCase.java:118) 在 junit.framework.TestSuite.runTest(TestSuite.java:208) 在 junit.framework.TestSuite.run(TestSuite.java:203) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:436) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:311) 在 org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 造成的: org.hibernate.exception.DataException: 无法更新: [cat.edis.tmiweb.business.File#0] 在 org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77) 在 org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43) 在 org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2430) 在 org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2312) 在 org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2612) 在 org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:96) 在 org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279) 在 org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263) 在 org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168) 在 org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298) 在 org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27) 在 org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000) 在 org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390) 在 org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:420) ... 20 更多原因: COM.ibm.db2.jdbc.DB2Exception: [IBM][CLI 驱动程序][DB2] SQL0100W 否 为 FETCH、UPDATE 或 删除;或者查询的结果是 空表。 SQLSTATE=02000
在 COM.ibm.db2.jdbc.app.SQLExceptionGenerator.throw_SQLException(未知 来源)在 COM.ibm.db2.jdbc.app.SQLExceptionGenerator.throw_SQLException(未知 来源)在 COM.ibm.db2.jdbc.app.SQLExceptionGenerator.check_return_code(未知 来源)在 COM.ibm.db2.jdbc.app.DB2PreparedStatement.loadParameters(未知 来源)在 COM.ibm.db2.jdbc.app.DB2PreparedStatement.execute2(未知 来源)在 COM.ibm.db2.jdbc.app.DB2PreparedStatement.executeUpdate(未知 来源)在 cat.cis.tuf.server.connector.jdbc.v1.JDBCv1DBStatement.executeUpdate(JDBCv1DBStatement.java:206) 在 org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23) 在 org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2408) ... 31 更多
异常对象:
ex= DataException (id=341)
backtrace= Object[35] (id=349)
cause (NestableRuntimeException)= DB2Exception (id=325)
cause (Throwable)= DataException (id=341)
delegate= NestableDelegate (id=350)
detailMessage= "could not update: [cat.edis.tmiweb.business.File#0]"
sql= "update N4GK001$.FILE set crte_ts=?, file_nm=?, file_typ_desc=?, file_desc=?, file_lgth=?, file_cntnt=? where gen_file_id=?"
sqle= DB2Exception (id=325)
stackTrace= null
**
切换到 type 4 驱动:(仍在使用 org.hibernate.dialect.DB2390Dialect)
新错误! **\
org.springframework.orm.hibernate3.HibernateOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:672)
at org.springframework.orm.hibernate3.HibernateAccessor.convertHibernateAccessException(HibernateAccessor.java:412)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:424)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.save(HibernateTemplate.java:694)
at cat.edis.tmiweb.dao.FileDAOImpl.save(FileDAOImpl.java:31)
at cat.edis.tmiweb.dao.FileDAOImplTest.testSaveBlob(FileDAOImplTest.java:50)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:85)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:58)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:60)
at java.lang.reflect.Method.invoke(Method.java:391)
at junit.framework.TestCase.runTest(TestCase.java:154)
at org.jmock.core.VerifyingTestCase.runBare(VerifyingTestCase.java:39)
at junit.framework.TestResult$1.protect(TestResult.java:106)
at junit.framework.TestResult.runProtected(TestResult.java:124)
at junit.framework.TestResult.run(TestResult.java:109)
at junit.framework.TestCase.run(TestCase.java:118)
at junit.framework.TestSuite.runTest(TestSuite.java:208)
at junit.framework.TestSuite.run(TestSuite.java:203)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:436)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:311)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:61)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:46)
at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:24)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2408)
at org.hibernate.persister.entity.AbstractEntityPersister.updateOrInsert(AbstractEntityPersister.java:2312)
at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2612)
at org.hibernate.action.EntityUpdateAction.execute(EntityUpdateAction.java:96)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:279)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:263)
at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:168)
at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:298)
at org.hibernate.event.def.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:27)
at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1000)
at org.springframework.orm.hibernate3.HibernateAccessor.flushIfNecessary(HibernateAccessor.java:390)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:420)
... 20 more
【问题讨论】:
【参考方案1】:删除/注释掉
文件 dbFile = fileDAO.load(file.getId()); assertNotNull(文件);然后从头开始再次运行您的测试
【讨论】:
在你的 hbm 中你应该通过 java.sql.clob 引用 clob 是的,测试从未真正进入 load 语句,但唉,我试过了,但删除它并没有解决问题。错误发生在保存过程中,Hibernate 调用“select identity_val_local() from sysibm.sysdummy1”,当它应该返回对象的 id 时返回 0。 很好,很高兴知道它解决了它,如果你觉得值得然后投票(虽然我不认为你有 enuf 参考点这样做)或选择这个作为正确答案,干杯。 这没有解决。我知道它在做什么,但如何解决它是个问题。 您需要在 2 个单独的事务中进行保存和加载,如果这不能解决问题,那么这是方言引擎交互的潜在问题。但是尝试保存 1 个测试(事务),然后加载另一个测试(事务),不要将其作为一个测试运行,这会使测试运行器执行 2 个单独的测试【参考方案2】:从日志来看,hibernate 似乎插入了一个对象,然后尝试更新它,但它找不到它刚刚插入的对象。我不确定,但这可能是配置的 id 生成器有问题。为级别 org.hibernate.type 启用日志记录并检查哪些值绑定到准备好的语句 - 它会让您更好地了解如何调试它。
【讨论】:
【参考方案3】:没有解决。仍然没有确定为什么返回的 id 是 '0' ,所以当 Hibernate 运行更新 sql 时,没有 id 为 '0' 的行。但比为什么更好的是,让它正常工作的解决方案会更好。
【讨论】:
实际上查询返回null,Hibernate返回0作为生成的ID。仍然不确定如何解决此问题。【参考方案4】: 您在 File.java 中将内容作为 byte[],但尚未定义其映射 hbm 文件。要定义它的映射,您需要将属性放在下面,否则您必须从 File.java 中删除<property name="image" type="binary">
<column name="IMAGE" not-null="true" />
</property>
【讨论】:
以上是关于休眠和弹簧持久性问题。可能的身份值没有增加?的主要内容,如果未能解决你的问题,请参考以下文章
如何使用休眠将mysql与Java连接?例外:没有名为 org.hibernate.tutorial_jpa 的 EntityManager 的持久性提供程序 [关闭]
休眠:没有找到查询类的持久类:SELECT p FROM entity.Presentation p