2
votes

I am using hibernate 3.2.6, and spring 2.5.6 The database Im connecting to is: DB2 for Z OS 390 V8.1

When I run my testcase (below) I save the test file object. Hibernate DOES Save the object to the database, but my test blows out after the save, where it's trying to update the object with the correct id. I think that it's not getting the correct id (it looks like it's getting a '0' for the id), or Im not even sure why its trying to update the object that is already persisted. I dont know if this is a spring, hibernate, mapping, dialect, or etc issue.

My config:

The business object:

<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>

The pojo:

/*
 * 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;
    }
}

The application context:

<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>

FileDAO:

/*
 * 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);
    }

}

My Test:

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

Output to console from 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=?

Trace:

org.springframework.dao.DataIntegrityViolationException: could not update: [cat.edis.tmiweb.business.File#0]; nested exception is org.hibernate.exception.DataException: could not update: [cat.edis.tmiweb.business.File#0] at org.springframework.orm.hibernate3.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:639) 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.exception.DataException: could not update: [cat.edis.tmiweb.business.File#0] at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:77) at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:43) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2430) 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 Caused by: COM.ibm.db2.jdbc.DB2Exception: [IBM][CLI Driver][DB2] SQL0100W No row was found for FETCH, UPDATE or DELETE; or the result of a query is an empty table. SQLSTATE=02000

at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.throw_SQLException(Unknown Source) at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.throw_SQLException(Unknown Source) at COM.ibm.db2.jdbc.app.SQLExceptionGenerator.check_return_code(Unknown Source) at COM.ibm.db2.jdbc.app.DB2PreparedStatement.loadParameters(Unknown Source) at COM.ibm.db2.jdbc.app.DB2PreparedStatement.execute2(Unknown Source) at COM.ibm.db2.jdbc.app.DB2PreparedStatement.executeUpdate(Unknown Source) at cat.cis.tuf.server.connector.jdbc.v1.JDBCv1DBStatement.executeUpdate(JDBCv1DBStatement.java:206) at org.hibernate.jdbc.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:23) at org.hibernate.persister.entity.AbstractEntityPersister.update(AbstractEntityPersister.java:2408) ... 31 more

The exception object:

 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

**

Switched to type 4 driver: (still using org.hibernate.dialect.DB2390Dialect)

NEW error! **\

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
4

4 Answers

0
votes

Remove/comment out

 
        File dbFile = fileDAO.load(file.getId());
        assertNotNull(file);

And run your test again from scratch

0
votes

From the logs, it looks like hibernate inserts an object, then tries to update it, but it cannot find the object it just inserted. I am not sure, but it might be a problem with the id generator configured. Enable logging for level org.hibernate.type and check what values are bound to the prepared statement - it would give you a better idea on how to debug this.

0
votes

It is not solved. Still haven't nailed down why the id returned is '0' , so when Hibernate runs the update sql, there isn't a row with the id of '0'. But even better than why, a solution to make it work correctly would be better.

0
votes
  • You took content as byte[] in File.java, but you haven't define its mapping hbm file. To define its mapping you need to put below property else you must remove from File.java

<property name="image" type="binary"> <column name="IMAGE" not-null="true" /> </property>

  • You specified contentBlob as a blob in hbm file, but you haven't specified in File.java. So, you must add its mapping setter-getter in its related POJO(File.java) or remove from hbm file.