-->
These old forums are deprecated now and set to read-only. We are waiting for you on our new forums!
More modern, Discourse-based and with GitHub/Google/Twitter authentication built-in.

All times are UTC - 5 hours [ DST ]



Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 
Author Message
 Post subject: Best Practices: Howto cache instead of long transaction
PostPosted: Fri Jul 16, 2004 1:40 pm 
Newbie

Joined: Thu Jun 17, 2004 6:31 am
Posts: 5
Hi

I'd like to use Hibernate for the following UseCase: A user does some manipulations on business objects, and when he saves the work, the BOs are made persistent to the DB.

Strategy 1: At the beginning I start a transaction, and when the user saves, I commit the whole stuff and start a new transaction. The disadvantage of this is that a user might take a cup of coffee and the chances of a cuncurrent update increase.

Strategy 2: I cache the modified/create/deleted BOs and flush them during one short transaction. The bad thing about this is I have to invent caching strategies once more.

I am implementing this as a desktop application, so both strategies can be taken into account. Which one is the one recommended by you? Reasons?

Thanks for your advice
Daniel Frey


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 16, 2004 2:57 pm 
Hibernate Team
Hibernate Team

Joined: Thu Dec 18, 2003 9:55 am
Posts: 1977
Location: France
---- Session A opened beginTrans ---------
1- get objects
---- Session A closed and committed-------
---- Objects are detached -------
2- show these object in your UI
3- user modifies objects
---- Session B opened beginTrans
4- reattached objects with new session
5- do some version check
6- (flush)
---- session B closed and committed --------

this is only one solution

you can also store somewhere (httpSession?) the hibernate session and it live a long time and use disconnect/reconnect...

read reference guide, it is explained

http://www.hibernate.org/hib_docs/refer ... g-detached
http://www.hibernate.org/hib_docs/refer ... tions.html

_________________
Anthony,
Get value thanks to your skills: http://www.redhat.com/certification


Top
 Profile  
 
 Post subject:
PostPosted: Fri Jul 16, 2004 6:11 pm 
Newbie

Joined: Thu Jun 17, 2004 6:31 am
Posts: 5
Thanks, Anthony, your answer shows that I am on the right way, as this is exactly what I am doing at the moment. More precisely:

1-Session A: get objects
2-Session A: show these object in your UI
3-No Session: user modifies objects: I keep track of all modified/updated and deleted objects.
4-Session B: reattached objects with new session: I use saveOrUpdate
5-Session B: do some version check: My config contains a timestamp property
6-Session B: (flush): dito

However, I get strange exceptions, so I was doubting whether I adopted the right strategy. The exception is:

Code:
[ERROR] JDBCException: 38 could not delete collection rows: [IFEntry.parents#121]
java.sql.SQLException: Try to insert null into a non-nullable column: column: CHILD_ID table: ENTRY_ENTRY in statement [update ENTRY_ENTRY set CHILD_ID=null where CHILD_ID=? and PARENT_ID=? and CHILD_ID=?]
   at org.hsqldb.jdbc.jdbcUtil.throwError(Unknown Source)
   at org.hsqldb.jdbc.jdbcPreparedStatement.executeUpdate(Unknown Source)
   at net.sf.hibernate.impl.NonBatchingBatcher.addToBatch(NonBatchingBatcher.java:22)
   at net.sf.hibernate.collection.AbstractCollectionPersister.deleteRows(AbstractCollectionPersister.java:566)
   at net.sf.hibernate.impl.ScheduledCollectionUpdate.execute(ScheduledCollectionUpdate.java:47)
   at net.sf.hibernate.impl.SessionImpl.executeAll(SessionImpl.java:2414)
   at net.sf.hibernate.impl.SessionImpl.execute(SessionImpl.java:2370)
   at net.sf.hibernate.impl.SessionImpl.flush(SessionImpl.java:2236)
   at net.sf.hibernate.transaction.JDBCTransaction.commit(JDBCTransaction.java:61)
   at BusinessDelegate.saveAll(BusinessDelegate.java:118)
   at SaveAction.actionPerformed(SaveAction.java:32)

That happens when I am updating (updateOrSave) an existing DefaultEntry object (implements IFEntry):

Code:
DefaultEntry@107bd0d[
    work=<null>,
    timestamp=2004-07-16 21:18:43.845,
    id=121,
    children=[],
    parents=[
        EntryConnector@13dd8[
            rank=0,
            EntryConnectorId@18353cf[
                parent=188,
                child=121
            ],
            timestamp=2004-07-16 23:39:05.745
        ]
    ],
]

which has a relation to the EntryConnector (-> ENTRY_ENTRY table). Hibernate tries to update this dependent object too and wants to set one part of the primary key (CHILD_ID -> child=121) of ENTRY_ENTRY to null, which invokes the exception. I don't see why this is necessary, it should only update the DefaultEntry, not the EntryConnector. And if it updates the EntryConnector, then why setting this half-PK to null? Can I configure it to not do that?

I've got a simple two-tables ERD, representing a graph.

Code:
CREATE TABLE ENTRY (
    ID IDENTITY,
    TIMESTAMP TIMESTAMP,
    ...
);
CREATE TABLE ENTRY_ENTRY (
    PARENT_ID INTEGER,
    CHILD_ID INTEGER,
    TIMESTAMP TIMESTAMP,
    RANK INTEGER,
    PRIMARY KEY (PARENT_ID, CHILD_ID)
);

and the row being updated is of the ENTRY table. I debuged throu the process and the ENTRY row is updated ok, but the dependent collection fails (the ENTRYs are dependent on the connection table ENTRY_ENTRY). Here's the config:

Code:
<hibernate-mapping package="">
    <class name="IFEntry" table="ENTRY">
        <id name="id" type="integer" unsaved-value="null">
            <generator class="identity"/>
        </id>
        <discriminator column="discriminator"/>
        <timestamp name="timestamp"/>
        ...
        <set name="children" table="ENTRY_ENTRY" inverse="true">
            <key column="PARENT_ID"/>
            <one-to-many class="EntryConnector"/>
        </set>
        <set name="parents" table="ENTRY_ENTRY">
            <key column="CHILD_ID"/>
            <one-to-many class="EntryConnector"/>
        </set>
        <subclass name="DefaultEntry" discriminator-value="default"/>
    </class>
</hibernate-mapping>

<hibernate-mapping package="">
    <class name="EntryConnector" table="ENTRY_ENTRY">
        <composite-id name="id" class="EntryConnectorId">
            <key-many-to-one name="parent" class="IFEntry" column="parent_id"/>
            <key-many-to-one name="child" class="IFEntry" column="child_id"/>
        </composite-id>
        <timestamp name="timestamp"/>
        <property name="rank" type="integer"/>
    </class>
</hibernate-mapping>

I am using HSQLDB 1.7.2rc6 and my code in the session (B) is:

Code:
public static void saveAll() {
    try {
        final Session session = HibernateUtils.currentSession();
        final Transaction tx = session.beginTransaction();
        for (Iterator iterator = cacheToDelete.iterator(); iterator.hasNext();) {
            final Object o = iterator.next();
            System.out.println("deleting: " + o);
            session.delete(o);
        }
        for (Iterator iterator = cacheToSave.iterator(); iterator.hasNext();) {
            final Object o = iterator.next();
            System.out.println("saving  : " + o);
            session.saveOrUpdate(o);
        }
        tx.commit();
        HibernateUtils.closeSession();
    }
    catch (HibernateException e) {
        e.printStackTrace();
        throw new IllegalStateException("Error during save");
    }
}

Thanks for any idea or advice.
Daniel Frey


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 3 posts ] 

All times are UTC - 5 hours [ DST ]


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum

Search for:
© Copyright 2014, Red Hat Inc. All rights reserved. JBoss and Hibernate are registered trademarks and servicemarks of Red Hat, Inc.