Wednesday, November 24, 2010

Transcaction not successfully started

If the exception is coming out of a commit operation, try the following:

if(!trans.wasCommitted){

trans.commit;
}

Tuesday, November 23, 2010

OpenSessionInViewFilter singleSession=false, Illegal attempt to associate a collection with two open sessions

In previous configurations I've been setting the singleSession=true in the OpenSessionInViewFilter provided by spring. This parameter binds a Hibernate session to the request. However, this proved to be problematic in our scenario because we were caching the POJO entities in a cache store that lives outside of Hibernate's caching mechanisms. Why we are having another caching mechanism is irrelevant, but for sanity sake, I'll just say that we have different datasources that are combined into a single entity, which makes caching important for performance reasons.

Since this cache store is accessible by all incoming requests, POJO's that were added to the cache by previous requests, were still associated with the session bound to the previous request (that were lazily loaded). In an asynchronous environment, this led to the following Hibernate exception: Illegal attempt to associate a collection with two open sessions

To resolve this issue, I needed a way for multiple requests to share the same object loaded from the cache store. That is, I needed a way to unbound the session to the request and allow for multiple sessions within a single request. To do this, I changed the singleSession=true for the OpenSessionInViewFilter.

The thing to be aware of is now all data accesses should be wrapped in Transactions. To do this I used spring's annotations:


@Transactional(propagation=Propagation.REQUIRED, readOnly=false)public class FedoraPoddObjectDAOImpl extends AbstractFedoraDAOImpl<PoddObject> implements PoddObjectDAO

Monday, November 22, 2010

Caching Hibernate Proxied Objects

Generally, caching objects that have loaded from database helps to improve performance when retrieved several times. However, there is something to be aware of when lazily loading objects from hibernate and putting them into the cache store.

If you're like me, and you're using spring's OpenSessionInViewFilter and a cache store to store objects, you might encounter the dreaded LazyInitializationException.

Here's why:

Say you access the same object over several web requests:

Request #1: 
 1) OpenSessionInViewFilter opens a new session
 2) You load the object from hibernate but never actually retrieve it's lazily loaded proxied associations. 
 3) The object along with its proxed associations, gets stored in the cache
 4) OpenSessionInViewFilter closes the session. The proxy object no longer has it's session opened.


Request #2:
1) OpenSessionInViewFilter opens a new session
2) You attempt to load the same object from the cache. A match is found and the cached object is returned.
3) You attempt to load associated objects that are proxied.


Step 3, is where it fails with LazyInitializationException because, the session was already closed.


Solution:


Reattach the cached object to the session.


    @Override
    public void reattach(T entity) {
        Session session = getSession();
        try {
            if (PoddObject.class.isAssignableFrom(entity.getClass())) {
                PoddObject po = (PoddObject) entity;
                Long id = po.getId();
                if (id != null) {
                    try {
                        session.buildLockRequest(LockOptions.NONE).lock(entity);                    } catch (NonUniqueObjectException e) {
                        LOGGER.info("Merging entity instead of locking");
                        session.merge(entity);
                    }
                }
            } 
        } catch(HibernateException e) {            
            LOGGER.warn(e);
        } finally {
            releaseSession(session);            
        }
        
    }


Hibernate Lazy proxied objects and instanceof operation, type casting

Lazy loading of associations in Hibernate will help improve load time and keep performance reasonable. But there are some things to be aware of when lazily loading objects. The one I'm going to talk about today is the issue of using the instanceof operator and casting on a proxied object.

Say we have an inhertiance strategy where class Person is the super class, and class Student is a sublcass of Person.



If we configure hibernate to lazily load objects of class type Person, then Hibernate will create a proxied object that extends from class Person and not class Student even if the true class type of the object is a Student.

Then the following code will not work:

Person person = lazyLoadFromHibernate(id); // The proxied object from hibernateif (person instanceof Student) { // Fails on proxied object
    Student student = (Student) person; // Fails on proxied object
}

This becomes a real pain, when you already have this type of code everywhere in your application. The easy fix would be to set lazy="false" and enforce no proxied objects, but then your performance would take a hit.
So I implemented a solution that would always load the true object by replacing the proxied object with a fully initialized object and maintaining performance as follows:

    public static <T> T initializeAndUnproxy(T var) {
        if (var == null) {
            return null;
        }

        Hibernate.initialize(var);
        if (var instanceof HibernateProxy) {
            var = (T) ((HibernateProxy) var).getHibernateLazyInitializer().getImplementation();
        }
        return var;
    }

But I didn't want my application code at the business layer to be aware of Hibernate, so I implemented a Tuplizer and overrided the afterInitialize(). For example, if a Person object is associated with a Student object via a "classmate" relationship then I would override the Tuplizer method as follows:




    public void afterInitialize(Object entity, boolean lazyPropertiesAreUnfetched, SessionImplementor session) {
        super.afterInitialize(entity, lazyPropertiesAreUnfetched, session);
        // Check to see if the entity is a person 
        if (Person.class.isAssignableFrom(entity.getClass())) {    
            
            // Always provide the true implementation and replace the proxied object
            Person person = (Person) entity;
            Person classMate = (Person) entity.getClassMate();
            if ( classMate != null) {
                classMate = initializeAndUnproxy(classMate); // Fully Initialize the proxy
                person.setClassMate(class); // replace proxy
            }
        }
        
    }



References:

http://techscouting.wordpress.com/2010/09/24/instanceof-fails-with-hibernate-lazy-loading-and-entity-class-hierarchy/

http://stackoverflow.com/questions/2959475/hibernate-lazy-loading-proxy-incompatable-w-other-frameworks

Tuesday, November 9, 2010

SocketException Connection reset on windows 7

While trying to recreate a development environment for a Java Web application on my new laptop with Windows 7, I encountered the dreaded SocketException Connection reset exceptions.

I spent hours overlooking my configuration for the application ensuring that everything was the same as my existing development environment at work but I couldn't find any reasons for the error.

After much investigation and research, I stumbled upon an article where somebody else had experienced similar problems on the Windows 7 OS here:

http://stackoverflow.com/questions/2370388/socketexception-address-incompatible-with-requested-protocol

This gave me the idea that I should probably try disabling support for IPV6
http://support.microsoft.com/kb/929852

After disabling it, I no longer encountered the errors!!

I must admit, so far using windows 7 hasn't had many issues until now. But this has caused me much grief and I'm just relieved to have finally worked it out.

Thursday, November 4, 2010

Hibernate testing for Transient entity

            try {
                Serializable id = session.getIdentifier(entity);
                if (id != null)
                    session.buildLockRequest(LockOptions.NONE).lock(entity);
            } catch (TransientObjectException e) {
                // Entity is a new object, nothing to reattach
            }

Tuesday, November 2, 2010

hibernate constrainviolationexception foreign key constraint

This was due to some test cases creating their own hibrenate sessions and transactions and attempting to save across multiple sessions and multiple transactions.

The fix was to ensure only one session is used across DAO calls.

Monday, November 1, 2010

org.hibernate.LazyInitializationException

 I had configured the OpenSessionInViewFilter as expected and yet I was still encountering this error.
After much debugging and code tracing in hibernate and in spring, it boiled down to the spring class

SessionFactoryUtils requiring the the sessionFactory instance be the same in the DAOs and in the filter.
After dumping out the identity of the session factories using System.identityHashCode() method, I discovered that they were in fact different instances hence the:

"no session or session closed" error message!

Why do I have multiple session factories?
It's because in the web.xml and the spring XML configuration it was read twice!

See the following link for more details

http://forum.springsource.org/showthread.php?t=85782

Once I reconfigured spring to only load each configuration file only once, the error message went away!

ThreadLocal is cool

http://javaboutique.internet.com/tutorials/localdata/