Hello,
1. No, I didn't use Oracle, I use Mysql as database.
2. The documentation Sessions and transactions are well knows for me.
I try to explain my problem in a little more detail:
I orientated my application to Cave Temptor demo application from the book Hibernate in Action. I use the same generic approach. I have the same GenericHibernateDao as interface to hibernate. Refering to the document 42.html I use a long session approach to work with the user session.
Following you will find my filter class which I include in my web.xml file.
/**
* Project: Lomis-Client
* File name: HIbernateSessionFilter.java
* Package name: com.ebn.lomis.client.filter
* @author Thomas Langhammer
* 02.04.2006 10:10:59
*
*
*/
package com.ebn.lomis.client.filter;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.apache.log4j.Logger;
import org.hibernate.HibernateException;
import org.hibernate.Session;
import com.ebn.lomis.client.actions.administration.AdministrationMenuAction;
import com.ebn.lomis.client.actions.freiekapazitaeten.FreiKapazitaetfahrzeugAction;
import com.ebn.lomis.common.exceptions.LomisDataAccessException;
import com.ebn.lomis.server.hibernate.util.HibernateUtil;
/**
* Author: Thomas Langhammer
* @hibernate.class table="HIbernateSessionFilter"
*/
public class HibernateSessionFilter implements Filter {
/**
* The logger of the class
*/
private static Logger log=Logger.getLogger(HibernateSessionFilter.class);
private static final String HTTPSESSIONKEY = "HibernateSession";
/**
* Constructor of the class
*/
public HibernateSessionFilter() {
super();
}
/* (non-Javadoc)
* @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
*/
public void init(FilterConfig arg0) throws ServletException {
log.info("Servlet filter init, now disconnecting/reconnecting a Session for each request.");
}
/* (non-Javadoc)
* @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
// Try to get a Hibernate Session from the HttpSession
HttpSession userSession =
((HttpServletRequest) request).getSession();
Session hibernateSession =
(Session) userSession.getAttribute(HTTPSESSIONKEY);
try {
if (hibernateSession != null){
HibernateUtil.reconnect(hibernateSession);
}
// If there is no Session, the first call to
// HibernateUtil.beginTransaction in application code will open
// a new Session for this thread.
// try {
chain.doFilter(request, response);
// Commit any pending database transaction.
HibernateUtil.commitTransaction();
} catch (LomisDataAccessException e){
log.error("Fehler beim Transaktions-Commit im HibernateSessionFilter");
try {
HibernateUtil.getSession().close();
} catch (HibernateException he){
log.error(he);
} catch (Exception ex) {
throw new ServletException();
}
} finally {
// TODO: The Session should be closed if a fatal exceptions occurs
// No matter what happens, disconnect the Session.
try {
hibernateSession = HibernateUtil.disconnectSession();
} catch (Exception e) {
log.error("Fehler beim Disconnect der Session in HibernateSessionFilter");
}
// and store it in the users HttpSession
userSession.setAttribute(HTTPSESSIONKEY, hibernateSession);
}
}
/* (non-Javadoc)
* @see javax.servlet.Filter#destroy()
*/
public void destroy() {
}
}
The next file is the hibernateutil class:
package com.ebn.lomis.server.hibernate.util;
import org.apache.commons.logging.*;
import org.hibernate.HibernateException;
import org.hibernate.Interceptor;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import com.ebn.lomis.common.exceptions.LomisDataAccessException;
import javax.naming.*;
/**
* Basic Hibernate helper class, handles SessionFactory, Session and Transaction.
* <p>
* Uses a static initializer for the initial SessionFactory creation
* and holds Session and Transactions in thread local variables. All
* exceptions are wrapped in an unchecked InfrastructureException.
*
* @author
christian@hibernate.org
*/
public class HibernateUtil {
private static Log log = LogFactory.getLog(HibernateUtil.class);
private static Configuration configuration;
private static SessionFactory sessionFactory;
private static final ThreadLocal threadSession = new ThreadLocal();
private static final ThreadLocal threadTransaction = new ThreadLocal();
private static final ThreadLocal threadInterceptor = new ThreadLocal();
// Create the initial SessionFactory from the default configuration files
static {
try {
configuration = new Configuration();
sessionFactory = configuration.configure().buildSessionFactory();
// We could also let Hibernate bind it to JNDI:
// configuration.configure().buildSessionFactory()
} catch (Throwable ex) {
// We have to catch Throwable, otherwise we will miss
// NoClassDefFoundError and other subclasses of Error
log.error("Building SessionFactory failed.", ex);
throw new ExceptionInInitializerError(ex);
}
}
/**
* Returns the SessionFactory used for this static class.
*
* @return SessionFactory
*/
public static SessionFactory getSessionFactory() {
/* Instead of a static variable, use JNDI:
SessionFactory sessions = null;
try {
Context ctx = new InitialContext();
String jndiName = "java:hibernate/HibernateFactory";
sessions = (SessionFactory)ctx.lookup(jndiName);
} catch (NamingException ex) {
throw new InfrastructureException(ex);
}
return sessions;
*/
return sessionFactory;
}
/**
* Returns the original Hibernate configuration.
*
* @return Configuration
*/
public static Configuration getConfiguration() {
return configuration;
}
/**
* Rebuild the SessionFactory with the static Configuration.
*
*/
public static void rebuildSessionFactory()
throws LomisDataAccessException {
synchronized(sessionFactory) {
try {
sessionFactory = getConfiguration().buildSessionFactory();
} catch (Exception ex) {
throw new LomisDataAccessException(ex);
}
}
}
/**
* Rebuild the SessionFactory with the given Hibernate Configuration.
*
* @param cfg
*/
public static void rebuildSessionFactory(Configuration cfg)
throws LomisDataAccessException {
synchronized(sessionFactory) {
try {
sessionFactory = cfg.buildSessionFactory();
configuration = cfg;
} catch (Exception ex) {
throw new LomisDataAccessException(ex);
}
}
}
/**
* Retrieves the current Session local to the thread.
* <p/>
* If no Session is open, opens a new Session for the running thread.
*
* @return Session
*/
public static Session getSession()
throws LomisDataAccessException {
Session s = (Session) threadSession.get();
try {
if (s == null) {
log.debug("Opening new Session for this thread.");
if (getInterceptor() != null) {
log.debug("Using interceptor: " + getInterceptor().getClass());
s = getSessionFactory().openSession(getInterceptor());
} else {
s = getSessionFactory().openSession();
}
threadSession.set(s);
}
} catch (HibernateException ex) {
throw new LomisDataAccessException(ex);
}
return s;
}
/**
* Closes the Session local to the thread.
*/
public static void closeSession()
throws LomisDataAccessException {
try {
Session s = (Session) threadSession.get();
threadSession.set(null);
if (s != null && s.isOpen()) {
log.debug("Closing Session of this thread.");
s.close();
}
} catch (HibernateException ex) {
throw new LomisDataAccessException(ex);
}
}
/**
* Start a new database transaction.
*/
public static void beginTransaction()
throws LomisDataAccessException {
Transaction tx = (Transaction) threadTransaction.get();
try {
if (tx == null) {
log.debug("Starting new database transaction in this thread.");
tx = getSession().beginTransaction();
threadTransaction.set(tx);
}
} catch (HibernateException ex) {
throw new LomisDataAccessException(ex);
}
}
/**
* Commit the database transaction.
*/
public static void commitTransaction()
throws LomisDataAccessException {
Transaction tx = (Transaction) threadTransaction.get();
try {
if ( tx != null && !tx.wasCommitted()
&& !tx.wasRolledBack() ) {
log.debug("Committing database transaction of this thread.");
tx.commit();
}
threadTransaction.set(null);
} catch (HibernateException ex) {
rollbackTransaction();
throw new LomisDataAccessException(ex);
}
}
/**
* Commit the database transaction.
*/
public static void rollbackTransaction()
throws LomisDataAccessException {
Transaction tx = (Transaction) threadTransaction.get();
try {
threadTransaction.set(null);
if ( tx != null && !tx.wasCommitted() && !tx.wasRolledBack() ) {
log.debug("Tyring to rollback database transaction of this thread.");
tx.rollback();
}
} catch (HibernateException ex) {
throw new LomisDataAccessException(ex);
} finally {
closeSession();
}
}
/**
* Reconnects a Hibernate Session to the current Thread.
*
* @param session The Hibernate Session to be reconnected.
*/
public static void reconnect(Session session)
throws LomisDataAccessException {
try {
session.reconnect();
threadSession.set(session);
} catch (HibernateException ex) {
throw new LomisDataAccessException(ex);
}
}
/**
* Disconnect and return Session from current Thread.
*
* @return Session the disconnected Session
*/
public static Session disconnectSession()
throws LomisDataAccessException {
Session session = getSession();
try {
threadSession.set(null);
if (session.isConnected() && session.isOpen())
session.disconnect();
} catch (HibernateException ex) {
throw new LomisDataAccessException(ex);
}
return session;
}
/**
* Register a Hibernate interceptor with the current thread.
* <p>
* Every Session opened is opened with this interceptor after
* registration. Has no effect if the current Session of the
* thread is already open, effective on next close()/getSession().
*/
public static void registerInterceptor(Interceptor interceptor) {
threadInterceptor.set(interceptor);
}
private static Interceptor getInterceptor() {
Interceptor interceptor =
(Interceptor) threadInterceptor.get();
return interceptor;
}
}
The long session concept is functioning within a single user session. My problem is situated between two or more user session. Each session becomes no notice from the update of the data from other session. My thought as I decided to use Hibernate for my project was that Hibernate do the communitation of changes to other session and that I haven't to inform other sessions about any changes. From this point of view I think that I haven't set the correct setting up to now.
Following you will find the load function in the struts action:
protected void loadFormBean(ActionContext ctx) {
BaseListForm form;
Vector<DataObject> vctDataobject= null;
ArrayList alsViewhelpers;
FilterContainer filterContainer;
ListDataModel model;
Vector<ViewHelper> vctViewhelpers = new Vector<ViewHelper>(0);
form = this.getForm(ctx);
if (form != null) {
try {
filterContainer=this.getFilterContainer(this.getSessionUser(ctx));
//filterContainer.add(this.getDeaktivFilterValue());
vctDataobject=getDao().findFiltered(filterContainer);
for (DataObject e: vctDataobject){
ViewHelper vh=getBusinessViewHelper(ctx,e);
vctViewhelpers.add(vh);
}
} catch (Exception e) {
e.printStackTrace();
ClientExceptionHandler.addGlobalError(ctx,"error.load",
e,BaseListAction.class);
}
model = new ListDataModel(vctViewhelpers);
SimpleListControl slc = new SimpleListControl();
slc.setDataModel(model);
form.setSlclist(slc);
}
System.out.println("Load form beendet");
}
With each server crossing I do a access to the database (findfiltered), create a new datamodel, create a new Listcontrol and the the list to the form. For the frontend I use Common Controls API.
Following you see the findfiltered method:
public Vector<T> findFiltered(FilterContainer cont) throws DataAccessException {
FilterContainer tmpcont;
log.info("Database request: findFiltered: \n");
List<T> list=new ArrayList<T>(0);
Vector<T> newVec=null;
Criteria crit;
if (cont==null){
tmpcont=new FilterContainer();
} else {
tmpcont=cont;
}
log.info("Database request: findFiltered: Filter:" + cont.toString()+"\n");
try {
HibernateUtil.beginTransaction();
this.session.clear();
crit = this.session.createCriteria(getPersistentClass());
for (FilterValue e : tmpcont) {
Criterion criterion=getExpression(e);
crit.add(criterion);
}
list=crit.list();
int tempsize=list.size();
log.info("Resultset size: " + tempsize + "\n");//list.size()+"\n");
} catch (Exception e) {
this.session.clear();
throw new DataAccessException(
ExceptionKeys.errorLoadData,
e,
GenericHibernateDAO.class);
}
newVec=new Vector<T>(list);
return newVec;
}
To persist the data I use following method:
public void saveOrupdate(T entity) throws LomisDataAccessException {
log.info("Database request: saveOrupdate: \n");
try {
HibernateUtil.beginTransaction();
this.session.saveOrUpdate(entity);
this.session.flush();
this.session.refresh(entity);
log.info("Objekt gespeichert: "+entity.toString());
} catch (Exception e) {
this.session.clear();
throw new DataAccessException(
ExceptionKeys.errorSaveData,
e,
GenericHibernateDAO.class);
}
}
I hope this code help for a diagnosis. I think I use Hibernate In a wrong way. There is an setting I haven't found.
The problem is on the level between the different user session and their view to their own data. Updates of other data will not become visible for these session, although the data is persitent in the database.
I hope you can locate the mistake. Otherwise I will delete all lazy loading code and program explicit loading for each subselect.
Thanks in advance Thomas