if(!trans.wasCommitted){
trans.commit;
}
Tips and experience about developing websites with various technologies
Wednesday, November 24, 2010
Transcaction not successfully started
If the exception is coming out of a commit operation, try the following:
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:
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.
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:
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:
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:
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
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.
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.
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!
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!
Subscribe to:
Posts (Atom)