is there any parameter i can set in hibernate so that temporary not allow persist anything but only allow read only (temporary) ? can i set in applicationcontext.xml?
You can mark your transaction as readOnly:
@Transactional(readOnly=true)
One side-effect I've observed when one forgets to make a method transactional is that no inserts or updates happen, only selects. You can try omitting the transaction declaration completely.
You can also try:
<prop key="org.hibernate.FlushMode">NEVER</prop>
(or session.setFlushMode(FlushMode.NEVER)
)
If that doesn't work, you can wrap your DAO calls with spring AOP, and proceed to the persist
method only in case a custom configuration property is set.
Hibernate has a method Session.setReadOnly(Object persited, boolean readOnly)
that allows you to mark a persisted object as read-only.
Hibernate 3.5 has also Session.setDefaultReadOnly(boolean)
that can be used to set all objects retrieved by a session to read only.
The challenge then is to find a way of setting this property on the Session
instances created by the SessionFactory
. I imagine AOP can be used to proxy the LocalSessionFactoryBean to intercept the created SessionFacotory
instances, delegating most methods to the original instance, but intercepting theopenSession(...)
methods. But I'm not that familiar with spring AOP, and IMO it can quickly become quite hard to understand. Here's a direct approach:
First, wrap your LocalSessionFactoryBean
in custom implementation:
<bean name="sessionFactory" class="ReadOnlySessionFactoryBean">
<constructor-arg>
<bean class="LocalSessionFactoryBean">
<!-- your existing session factory bean,
all your existing hibernate mappings, properties etc. -->
</bean>
</constructor-arg>
</bean>
Then add this class to your codebase. (Even with AOP, you will need to introduce some custom code.)
public class ReadOnlySessionFactoryBean extends AbstractFactoryBean
{
private AbstractSessionFactoryBean sessionFactoryBean;
public ReadOnlySessionFactoryBean(AbstractSessionFactoryBean sessionFactoryBean)
{
this.sessionFactoryBean = sessionFactoryBean;
}
@Override
public Class getObjectType()
{
return sessionFactoryBean.getObjectType();
}
@Override
protected Object createInstance() throws Exception
{
SessionFactory factory = sessionFactoryBean.getObject();
return new WrapSessionFactory(factory);
}
static class WrapSessionFactory implements SessionFactory
{
private Sessionfactory delegate;
WrapSessionFactory(SessionFactory delegate)
{
this.delegate = delegate;
}
// delegate most methods to the delegate SessionFactory
// override all the openSession(...) methods
public Session openSession()
{
Session session = delegate.openSession();
session.setDefaultReadOnly(true);
return session;
}
}
}
With just this change, the remainder of your code can run unmodified, and each time will get a read-only SessionFactory. If you wanted to be absolutely sure no writes are being done to the database, you could override the methods that write to the db, e.g. saveOrUpdate
, update
, although I'm not sure that is really necessary.
I would handle that at the database level and configure the application to use a user with read-only permissions during demos (either use a specific user for the demo or change the permissions of the currently used). Simple, effective and guaranteed to work with minimal efforts.