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.  [ 4 posts ] 
Author Message
 Post subject: Optimistic locking and multiple session use
PostPosted: Mon Dec 19, 2005 8:17 am 
Newbie

Joined: Mon Aug 01, 2005 7:33 am
Posts: 18
Location: UK
Hibernate version: 3

Mapping documents:<class name="Subscriber" table="CSSM_SUBSCRIBER" lazy="false">
<id name="ID" column="SUBSCRIBER_ID" type="string" length="64" />
<version name="version" />
<property name="publishedNumber" type="string" length="7" />
<property name="cli" type="string" length="32" />
<property name="accessRights" type="string" length="32" />
<many-to-one name="diallingElement" column="dialling_element_id"
class="DiallingElement" cascade="none" />

<!-- the many to many with subscriberGroupScheme -->
<set name="subscriberGroupScheme"
table="CSSM_SUBSCRIBER_TO_GROUP" cascade="save-update">
<key column="SUBSCRIBER_ID" />
<many-to-many column="SCHEME_ID"
class="SubscriberGroupScheme" />
</set>
<!-- Many to one with SubcriberProfile -->
<many-to-one name="subscriberProfile" column="PROFILE_ID" lazy="false"
class="SubscriberProfile" cascade="none" />

<!-- One to one with subscriber group scheme -->
<many-to-one name="currentGroupScheme" column="CURRENTGROUPSCHEME" />

</class>


Code between sessionFactory.openSession() and session.close():/*
* Title: $Id$
* Classification: Restricted-Commercial
* Copyright: Copyright (c) 2005
* Company: EADS-DS UK
* Author: bakers
* Modified: $Author$: $Date$
* Version: $Revision$
*
* Package: HibernateUtil
* Classes: com.cogent.infrastructure.hibernate.util;
*/

package com.cogent.infrastructure.hibernate.util;

import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.transaction.HeuristicMixedException;
import javax.transaction.HeuristicRollbackException;
import javax.transaction.NotSupportedException;
import javax.transaction.RollbackException;
import javax.transaction.SystemException;
import javax.transaction.UserTransaction;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.StaleObjectStateException;

import com.cogent.cormorant.hibernate.exception.HibernateUtilException;

/**
* This class is non thread safe class designed purely to
* encapsulate the Hibernate Session / SessionFactory knowledge.
* Also gets the session and transaction from JNDI. Designed to be used one per
* command/unit of work as it is not otherwise thread safe. DO NOT SHARE instances of
* this class as will cause side effects and transactional lack of integrity!
*
* @author warnettm
*/
public class HibernateUtil {

private SessionFactory sessionFactory;
private static String jndiSessionFactory = "java:/hibernate/SessionFactory";
private static String jndiTransaction = "UserTransaction";
private final static String BLANK_STRING = "";
private UserTransaction tx = null;

/**
* Gets a new transaction from JNDI and starts it.
* Also gets the <code>SessionFactory</code> from JNDI.
* @throws NamingException <code>NamingException</code>
* @throws SystemException <code>SystemException</code>
* @throws NotSupportedException <code>NotSupportedException</code>
*
*/
public void startTransaction() throws NamingException,
NotSupportedException, SystemException {

InitialContext ctx = new InitialContext();
this.tx = (UserTransaction) ctx.lookup(HibernateUtil.jndiTransaction);
this.tx.begin();
this.sessionFactory = (SessionFactory) ctx.lookup(HibernateUtil.jndiSessionFactory);

}

/**
* Returns current hibernate session.
* @return <code>Session</code> the Hibernate Session
* @throws NamingException <code>NamingException</code>
*/
public Session currentSession() throws NamingException {
if (this.sessionFactory == null) {
InitialContext ctx = new InitialContext();
this.sessionFactory = (SessionFactory) ctx.lookup(HibernateUtil.jndiSessionFactory);
}
return this.sessionFactory.getCurrentSession();
}

/**
* Gets the current transaction for this session.
* Can be null or throw an exception if used.
* @return tx <code>UserTransaction</code>
*/
public UserTransaction getCurrentTransaction() {
return this.tx;
}

/**
* This commits the transaction and explicitly catches any exceptions and wraps them in a
* <code>HibernateUtilException</code> - which could then be used to customise the user output etc.
* @throws HibernateUtilException <code>HibernateUtilException</code> wrapping any exceptions.
*/
public void commitTranscation() throws HibernateUtilException {
if (this.tx != null) {
try {
this.tx.commit();
} catch (SystemException e) { //TODO maybe put all the messages in?
throw new HibernateUtilException(HibernateUtil.BLANK_STRING, e);
} catch (SecurityException se) {
throw new HibernateUtilException(HibernateUtil.BLANK_STRING, se);
} catch (IllegalStateException ie) {
throw new HibernateUtilException(HibernateUtil.BLANK_STRING, ie);
} catch (RollbackException re) {
Throwable cause = re.getCause();
String message = HibernateUtil.BLANK_STRING;
if (cause instanceof StaleObjectStateException) {
message = "Current record has been deleted or updated in another transaction.";
}
throw new HibernateUtilException(message, re);
} catch (HeuristicMixedException hme) {
throw new HibernateUtilException(HibernateUtil.BLANK_STRING, hme);
} catch (HeuristicRollbackException hre) {
throw new HibernateUtilException(HibernateUtil.BLANK_STRING, hre);
}
}
}

/**
* Gets a session factory.
* @return <code>SessionFactory</code>
* @throws NamingException <code>NamingException</code>
*/
public SessionFactory getSessionFactory() throws NamingException {
if (this.sessionFactory == null) {
InitialContext ctx = new InitialContext();
this.sessionFactory = (SessionFactory) ctx.lookup(HibernateUtil.jndiSessionFactory);
}
return this.sessionFactory;
}
}


Full stack trace of any exception that occurs:None

Name and version of the database you are usingOracle 8i:

The generated SQL (show_sql=true):

Debug level Hibernate log excerpt:

Hi basically we have a thick Java client that for performace reasons we cannot send detached hibernate objects to/from the server side. To get around this we have factories that create ValueObjects and Composites of ValueObjects as copies of the persistent data to send to the client. However we are having issues with mutiple users and optimistic locking. If a client has some 'old' data in it and performs an update (version is older than that in the database/cache) we do not get a StaleObjectException as we would expect. It happily udates the persistent object even if we explicitly try and set the version attribute of the persistent object to the 'old' value. After reading the docs I am even more confused since the docs suggest using a single session for the whole application to get over this - however it also suggests that you never share a session among multiple transactions?
Is this not contradcitory? Since to share a session you would pass it to more than one transaction?
We are using JBoss 4.03 Release 1 and JTA transactions as transaction demarkations?
We use saveOrUpdate on persistent objects in order to persist them (not merge).
Could anyone suggest a better way of doing what we need? Should we be using one singleton session or multiples? What are we doing wrong?

regards

Shaun


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 19, 2005 9:10 am 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Try "Application version checking" or use database trigger to mainatain this stuff (trivial stored procedure)


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 19, 2005 9:25 am 
Newbie

Joined: Mon Aug 01, 2005 7:33 am
Posts: 18
Location: UK
baliukas wrote:
Try "Application version checking" or use database trigger to mainatain this stuff (trivial stored procedure)


We are considering - it is simply that the guides specify that it is highly inefficient. However this may be the only solution right now. Thanks anyway - will probably have to I guess. Cheers for the assitance and prompt reply. If it gets too monstrous I wil post again maybe.

Thanks (do you want the credit for this?)

Regards

Shaun


Top
 Profile  
 
 Post subject:
PostPosted: Mon Dec 19, 2005 1:26 pm 
CGLIB Developer
CGLIB Developer

Joined: Thu Aug 28, 2003 1:44 pm
Posts: 1217
Location: Vilnius, Lithuania
Yes, it inefficient to maintain this stuff in application code. Workflow engine is a good way to manage this stuff (JBPM is well integrated with hibernate), but it can be too heavy weight if your "process" is very simple. I think trigger is a good way, probably it is possible to use hibernate interceptor or event listeners for this stuff too, but it is not as fast as trigger ( +1 select statement)


Top
 Profile  
 
Display posts from previous:  Sort by  
Forum locked This topic is locked, you cannot edit posts or make further replies.  [ 4 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.