Hi! I'm trying to use Hibernate in my data access layer in combination with Spring MVC for the web layer. When I launch my test cases to test DAOs they work perfectly, but trying to invoke the same use cases from the web layer, they fail.
First I'll show some relevant information about my configuration:
Hibernate version:
Hibernate 3.2.5.ga
Hibernate Annotations 3.3.0.ga
application-Context.xml snippets[b]
Code:
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
...
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.PostgreSQLDialect
</prop>
<prop key="hibernate.c3p0.min_size">5</prop>
<prop key="hibernate.c3p0.max_size">20</prop>
<prop key="hibernate.c3p0.timeout">2000</prop>
<prop key="hibernate.c3p0.max_statements">50</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
</props>
</property>
...
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean name="openSessionInViewInterceptor"
class="org.springframework.orm.hibernate3.support.OpenSessionInViewInterceptor">
<property name="sessionFactory" >
<ref bean="sessionFactory" />
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
Not relevant information is omitted, but for this example the annotated entity to use will be Link (its attributes aren't important).
In the web layer, invoking NewLink.do we can write the corresponding attributes of this entity in a form, and when the form is submitted, the controller do this:
Code:
linkService.createLink(link);
with linkService the facade which invokes link DAO. Trying to do this, the stacktrace given is :
Code:
HTTP ERROR: 500
Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.NEVER/MANUAL): Turn your Session into FlushMode.COMMIT/AUTO or remove 'readOnly' marker from transaction definition.
at org.springframework.orm.hibernate3.HibernateTemplate.checkWriteOperationAllowed(HibernateTemplate.java:1182)
at org.springframework.orm.hibernate3.HibernateTemplate$21.doInHibernate(HibernateTemplate.java:802)
at org.springframework.orm.hibernate3.HibernateTemplate.doExecute(HibernateTemplate.java:419)
at org.springframework.orm.hibernate3.HibernateTemplate.executeWithNativeSession(HibernateTemplate.java:374)
at org.springframework.orm.hibernate3.HibernateTemplate.persist(HibernateTemplate.java:800)
at es.udc.pojo.modelutil.dao.GenericDaoHibernate.create(GenericDaoHibernate.java:57)
at es.udc.lbd.portal.model.services.link.service.LinkServiceImpl.createLink(LinkServiceImpl.java:28)
at es.udc.lbd.portal.http.controller.other.NewLinkController.processSubmit(NewLinkController.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.doInvokeMethod(HandlerMethodInvoker.java:413)
at org.springframework.web.bind.annotation.support.HandlerMethodInvoker.invokeHandlerMethod(HandlerMethodInvoker.java:134)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.invokeHandlerMethod(AnnotationMethodHandlerAdapter.java:310)
at org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter.handle(AnnotationMethodHandlerAdapter.java:297)
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:809)
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:523)
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:463)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:727)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:487)
at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:362)
at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:139)
at org.mortbay.jetty.Server.handle(Server.java:324)
at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:842)
at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:648)
at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
at org.mortbay.thread.BoundedThreadPool$PoolThread.run(BoundedThreadPool.java:450)
Now, I'll show the DAO implementation. To perfom the usage of Hibernate, and as shown in the documentation, I use an abstract class GenericDao implementing an interface GenericDaoHibernate:
[b] Interface GenericDao - Snippet Code:
public interface GenericDao <E, PK extends Serializable>{
void create(E entity);
...
}
Abstract class GenericDaoHibernate - Snippet Code:
public class GenericDaoHibernate<E, PK extends Serializable>
extends HibernateDaoSupport
implements GenericDao<E, PK>
private Class<E> entityClass;
@SuppressWarnings("unchecked")
public GenericDaoHibernate()
{
this.entityClass = (Class<E>) ((ParameterizedType) getClass().
getGenericSuperclass()).getActualTypeArguments()[0];
}
public void create(E entity)
{
getHibernateTemplate().persist(entity);
}
...
}
Link DAO Code:
public class LinkDAOHibernate
extends GenericDaoHibernate<Link, String> implements LinkDAO
{
@Autowired
public LinkDAOHibernate(SessionFactory sessionFactory)
{
super.setSessionFactory(sessionFactory);
}
}
Using
getHibernateTemplate() and the OpenSessionInView the session management will be transparent, but not really... With data retrying methods (not dml), all work perfect, but in data manipulation methods this error occurs. Trying to solve this problem, I set the flushmode to the session in the create method, but this way was wrong.
¿Any way to solve this problem?
Also, I want to comment that one friend have the similar problem and the way he found to solve it was removing the extension of
HibernateDaoSupport and doing something like this:
Code:
sessionFactory.getCurrentSession().persist(entity);
Using Hibernate Session Core, with the OpenSessionInViewFilter (he uses the filter, not the interceptor), the queries works perfectly, but the DML operations (insert, delete or update) fail. Removing the filter, nothing works (
No Hibernate Session bound to thread... ).
Thanks.