Results 1 to 5 of 5

Thread: Spring, Hibernate, PostgreSQL - id generator

  1. #1
    Join Date
    Sep 2004
    Posts
    3

    Default Spring, Hibernate, PostgreSQL - id generator

    Problem Description
    ****************
    During a transaction that rollbacks, all NEW OBJECTs that had been persisted in it, mantain the Key that has been assigned to then by the GENERATOR. So, the next time i try to saveOrUpdate thats NEW OBJECTs, Hibernate manages its as if they where PERSISTED OBJECTS, generating a new exception.

    Ambient Details
    ************

    Application
    -------------
    Spring (release 1.0.2)
    Hibernate (2.1.0)
    Java (jdk 1.4.1_02-b06)

    Application Configuration
    -----------------------------
    * transactionManager: org.springframework.orm.hibernate.HibernateTransac tionManager
    * transactionInterceptor: org.springframework.transaction.interceptor.Transa ctionInterceptor
    * hibernate.dialect: net.sf.hibernate.dialect.PostgreSQLDialect
    * GENERATOR: "sequence"

    DB
    ----
    postgreSQL 7.4.3
    Linux Red Hat 9

    Analisys Realized and More Details
    ****************************

    Analisys Realized
    ---------------------
    1) PersonService.savePerson(IPerson person) is invoked by a client
    2) PersonDAO.savePerson(IPerson person) is then invoked by PersonService.savePerson(IPerson person)
    3) Before the inserts in the DB, the session uses GENERATOR to generate the unique Key (eg: 1421) that identifies the person.
    4) Suppose that, while inserting in the DB, a constrain is violated and an error is raise. The transactionManager inits the rollback process and finish it successfully.
    5) Unfortunately, after that process, the person mantains a relation to that generated Key (1421), but it does not exists in the DB after the rollback.
    6) So, the next time i try to saveOrUpdate that person, Hibernate manages its as if it where an already PERSISTED person, generating, calling the Session.doUpdate( ... ) method, generating an Hibernate exception.

    database
    -----------
    create table person
    (
    id serial,
    firstname varchar(20),
    lastname varchar(20),
    sex varchar(1) not null
    );

    person.hbm
    --------------
    <class name="Person" table="person">
    <id column="id" name="id" type="java.lang.Long">
    <generator class="sequence">
    <param name="sequence">elector_id_seq</param>
    </generator>
    </id>
    <property column="apellido" name="fistname" not-null="false" type="string" />
    <property column="apellido" name="lastname" not-null="false" type="string" />
    <property column="sex" name="lastname" not-null="true" type="string" />
    </class>

    conf_hibernate.xml
    -----------------------
    <bean id="transactionManager" class="org.springframework.orm.hibernate.Hibernate TransactionManager">
    <property name="sessionFactory">
    <ref bean="mySessionFactory"/>
    </property>
    </bean>

    <bean id="transactionInterceptor" class="org.springframework.transaction.interceptor .TransactionInterceptor">
    <property name="transactionManager">
    <ref bean="transactionManager"/>
    </property>
    <property name="transactionAttributeSource">
    <value>test.Interfaces.IPersonService.save*=PROPAG ATION_REQUIRED,-DataAccessException</value>
    </property>
    </bean>

    <bean id="person" class="test.BO.Person">
    <property name="sessionFactory">
    <ref bean="mySessionFactory"/>
    </property>
    </bean>

    <bean id="personDao" class="test.logica.PersonDAO">
    <property name="sessionFactory">
    <ref local="mySessionFactory"/>
    </property>
    </bean>

    <bean id="personServiceTarget" class="test.BO.PersonService">
    <property name="personDao">
    <ref bean="personDao"/>
    </property>
    </bean>

    <bean id="personService" class="org.springframework.aop.framework.ProxyFact oryBean">
    <property name="proxyInterfaces">
    <value>test.Interfaces.IPersonService</value>
    </property>
    <property name="interceptorNames">
    <value>transactionInterceptor,personServiceTarge t</value>
    </property>
    </bean>

    class
    -------
    PersonService class contains a savePerson(IPerson) methods that is intercepted for transactional reasons:

    public void savePerson(IPerson person) throws DataAccessException {
    this.personDao.savePerson(person);
    }

    PersonDAO class contains the next method:
    public void savePerson(IPerson person) throws DataAccessException {

    Session session = SessionFactoryUtils.getSession(getSessionFactory() , false);
    try{
    session.saveOrUpdate(person);
    }
    catch (...){
    ...
    }
    }

  2. #2
    Join Date
    Aug 2004
    Location
    Montréal, Canada
    Posts
    845

    Default

    During a transaction that rollbacks, all NEW OBJECTs that had been persisted in it, mantain the Key that has been assigned to then by the GENERATOR.
    This is how Hibernate behaves. Transaction management does not rollback your transient objects to their original state. It is the developer responsibility to do this. You can also provide a "fresh" POJO each time you call save.
    Omar Irbouh

    Spring Modules Team
    http://irbouh.blogspot.com/

  3. #3
    Join Date
    Sep 2004
    Posts
    3

    Default

    Quote Originally Posted by irbouho
    During a transaction that rollbacks, all NEW OBJECTs that had been persisted in it, mantain the Key that has been assigned to then by the GENERATOR.
    This is how Hibernate behaves. Transaction management does not rollback your transient objects to their original state. It is the developer responsibility to do this. You can also provide a "fresh" POJO each time you call save.
    Omar:

    I'm not sure about that. If you use (for example) a the "identity" generator, all behaves as if you haven't persist that objects. Unfortunatelly, identities generators doesn't work with Postgres DB.

    See below the fragment of SessionImpl.doSave(Object ) method:
    .
    .
    .

    if (useIdentityColumn) {
    // if the id is generated by the database, we assign the key later
    key = null;
    }
    else {
    key = new Key(id, persister);
    .
    .
    .
    }

    In the last case, key isn't set to null during rollbacks, keeping the
    new Key(id, persister) value.

  4. #4
    Join Date
    Aug 2004
    Location
    Montréal, Canada
    Posts
    845

    Default

    luciano, there is a difference how Hibernate (and plain JDBC if you like) process identity and sequences:

    1. identity:
    1. hibernate execute an insert to create the new record
    2. the underlying rdbms get a new value for the identity
    3. the rdbms creates the table row
    4. hibernate execute a "select @@identity" (or equivalent) to get the identity value used
    5. hibernate sets the entity id using the returned value

    so if the insert statement fails (step 3), your entity id is not set yet

    1. sequence:
    1. hibernate execute a select query to get the sequence next value "select nextval(seq)" (or equivalent)
    2. hibernate sets the entity id using the returned value
    3. hibernate executes an insert to create the new record
    4. the rdbms creates the table row

    in this case, if step 4 fails, your entity id is already set.

    I hope this makes things a bit clear.
    Omar Irbouh

    Spring Modules Team
    http://irbouh.blogspot.com/

  5. #5
    Join Date
    Sep 2004
    Posts
    3

    Default

    Thank you Omar.

    One more thing, do you know some patch (implemented or in progress) that have similar behaviour to "identity" in PostgreSQL.

Similar Threads

  1. Replies: 5
    Last Post: Feb 3rd, 2009, 05:19 AM
  2. Replies: 3
    Last Post: Aug 16th, 2007, 12:10 PM
  3. Spring + Hibernate ORA-00936: missing expression
    By Hugh_la_Main in forum Data
    Replies: 1
    Last Post: Jun 28th, 2005, 08:48 AM
  4. Replies: 14
    Last Post: Feb 21st, 2005, 05:41 PM
  5. Replies: 7
    Last Post: Aug 21st, 2004, 03:42 AM

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •