What does "proxied" state means for a Hibernate Session - java

I came across this line regarding Hibernate Documentation on Jboss site.
Because Hibernate can't bind the "current session" to a transaction,
as it does in a JTA environment, it binds it to the current Java thread
when i do transction demarcation with plain JDBC.
It is opened when getCurrentSession() is called for the first time,
but in a "proxied" state that doesn't allow you to do anything except
start a transaction.
So, what exactly does the author mean by "proxied state" here. And what link they have, if any, to proxy objects?

Without JTA, the transaction management is done through the commit/rollback methods of a JDBC Connection.
This means you have to bind one JDBC Connection to the current running Hibernate Session and to the current logical transaction.
Because passing a JDBC Connection to all Hibernate Session methods would be a terrible design solution, you have to use a Thread-local storage instead.
Hibernate has a flexible CurrentSessionContext, offering the following alternatives:
JTASessionContext
ManagedSessionContext
ThreadLocalSessionContext
So if you choose the ThreadLocaSessionContext, then the underlying JDBC connection will be bound to a Thread local storage and make it available to the current Thread running Session.
If you use Spring, you shouldn't rely on the Hibernate TreadLocal context, but use the Spring specific Transaction Management support, which is implemented by:
SpringJtaSessionContext
SpringSessionContext
As for the proxy state, the Hibernate TreadLocalContext uses a proxy for the Hibernate Session:
protected Session wrap(Session session) {
final TransactionProtectionWrapper wrapper = new TransactionProtectionWrapper( session );
final Session wrapped = (Session) Proxy.newProxyInstance(
Session.class.getClassLoader(),
SESSION_PROXY_INTERFACES,
wrapper
);
wrapper.setWrapped( wrapped );
return wrapped;
}
allowing the current Session to unbind itself form the TreadLocal storage when the Session.close() method is called.
// If close() is called, guarantee unbind()
if ( "close".equals( methodName ) ) {
unbind( realSession.getSessionFactory() );
}

Related

How to get exclusive access to some session entry?

Due to remote invocation nature of REST services, they are in constant situation to run into race condition with each other. One of the everyday resources to race for is session. In order to be practical, you need to be able to put a lock over the resource at the beginning of your process and lift it up whenever you are done with it.
Now my question is, does Spring Session have any feature to deal with race condition over the session entries?
Or any other library / framework in Java!!!
If you're using Spring Controllers, then you can use
RequestMappingHandlerAdapter.setSynchronizeOnSession-boolean-
This will make every Controller method synchronized in presence of a session.
HttpSession.setAttribute is thread safe. However getAttribute followed by setAttribute has to be manually made tread safe.
synchronized(session) {
session.setAttribute("foo", "bar");
session.getAttribute("foo");
}
Same can be done in case of spring session beans.
synchronized(session) {
//do something with the session bean
}
#Edit
In case of multiple containers with normal spring session beans you would have to use sticky sessions. That would ensure that one session state is stored on one container and that container is accessed every single time the same session is requested. This has to be done on the load balancer with the help of something like BigIP cookies. Rest would would work the same way as for a single session there exists a single container, so locking session would suffice.
If you would like to use session sharing across instances there are supports on the containers like Tomcat and Jetty
These approaches use a back-end database or some other persistence mechanism to store state.
For the same purpose you can try using Spring Session. Which is trivial to configure with the Redis. Since Redis is single threaded, it ensures that one instance of an entry is accessed atomically.
Above approaches are non invasive. Both the database and Redis based approaches support transactions.
However if you want more control over the distributed state and locking you can try using the distributed data grids like Hazelcast and Gemfire.
I have personally worked with the Hazelcast and it does provide methods to lock entries made in the map.
#Edit2
Though I believe that handling transactions should suffice with Spring Session and Redis, to make sure you would need distributed locking. Lock object would have to be acquired from the Redis itself. Since Redis is single threaded a personal implementation would also work by using something like INCR
Algorithm would go something like below
//lock_num is the semaphore/lock object
lock_count = INCR lock_num
while(true) {
if(lock_count != 1) {
DECR lock_num
} else {
break
}
wait(wait_time_period)
}
//do processing in critical section
DECR lock_num
However, thankfully Spring already provides this distributed lock implementation via RedisLockRegistry. More documentation on usage is here.
If you decide to use plain Jedis without spring then here is a distributed lock as for Jedis : Jedis Lock.
//from https://github.com/abelaska/jedis-lock
Jedis jedis = new Jedis("localhost");
JedisLock lock = new JedisLock(jedis, "lockname", 10000, 30000);
lock.acquire();
try {
// do some stuff
}
finally {
lock.release();
}
Both of these should work exactly like Hazelcast locking.
As a previous answer stated. If you are using Spring Session and you are concerned for thread safety on concurrent access of a Session, you should set:
RequestMappingHandlerAdapter.setSynchronizeOnSession(true);
One example can be found here EnableSynchronizeOnSessionPostProcessor :
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter;
public class EnableSynchronizeOnSessionPostProcessor implements BeanPostProcessor {
private static final Logger logger = LoggerFactory
.getLogger(EnableSynchronizeOnSessionPostProcessor.class);
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// NO-OP
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof RequestMappingHandlerAdapter) {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) bean;
logger.info("enable synchronizeOnSession => {}", adapter);
adapter.setSynchronizeOnSession(true);
}
return bean;
}
}
Sticky Sessions and Session Replication
With regards to a clustered application and Sessions, there is a very good post here on SO, that discusses this topic: Sticky Sessions and Session Replication
In my experience, you would want both Sticky Session and Session replication.
You use sticky session to eliminate the concurrent Session access across nodes, because sticky session will pin a session to a single node and each subsequent request for the same session will always be directed to that node. This eliminates the cross-node session access concern.
Replicated sessions are helpful mainly in case a node goes down. By replicating sessions, when a node goes down, future requests for existing sessions will be directed to another node that will have a copy of the original session and makes the fail over transparent to the user.
There are many frameworks that support session replication. The one I use for large projects is the open-source Hazelcast.
In response to your comments made on #11thdimension post:
I think you are in a bit of a challenging area. Basically, you want to enforce all session operations to be atomic across nodes in a cluster. This leads me to lean towards a common session store across nodes, where access is synchronized (or something similar).
Multiple Session store / replication frameworks surely support an external store concept and I am sure Reddis does. I am most familiar with Hazelcast and will use that as an example.
Hazelcast allows to configure the session persistence to use a common database.
If you look at Map Persistence section, it shows an example and a description of options.
The description for the concept states:
Hazelcast allows you to load and store the distributed map entries from/to a persistent data store such as a relational database. To do this, you can use Hazelcast's MapStore and MapLoader interfaces.
Data store needs to be a centralized system that is accessible from all Hazelcast Nodes. Persistence to local file system is not supporte
Hazelcast supports read-through, write-through, and write-behind persistence modes which are explained in below subsections.
The interesting mode is write-through:
Write-Through
MapStore can be configured to be write-through by setting the write-delay-seconds property to 0. This means the entries will be put to the data store synchronously.
In this mode, when the map.put(key,value) call returns:
MapStore.store(key,value) is successfully called so the entry is persisted.
In-Memory entry is updated.
In-Memory backup copies are successfully created on other JVMs (if backup-count is greater than 0).
The same behavior goes for a map.remove(key) call. The only difference is that MapStore.delete(key) is called when the entry will be deleted.
I think, using this concept, plus setting up your database tables for the store properly to lock entries on insert/update/deletes, you can accomplish what you want.
Good Luck!

What will happen if we begin transaction in hibernate but do not commit it?

What will happen if we begin transaction in hibernate, then do some transaction but do not commit it?
Will it save tempervoraly or it will rollback immediately?
Thanks
Chetan
Look at the following code, which accesses the database with transaction boundaries without use of commit:
Session session = sessionFactory.openSession();
session.beginTransaction();
session.get(Item.class, 123l);
session.close();
By default, in a Java SE environment with a JDBC configuration, this is what happens if you execute this snippet:
A new Session is opened. It doesn’t obtain a database connection at
this point.
If a new underlying transaction is required, begin the transaction.
Otherwise continue the new work in the context of the existing
underlying transaction
The call to get() triggers an SQL SELECT. The Session now obtains a
JDBC Connection from the connection pool. Hibernate, by default,
immediately turns off the autocommit mode on this connection with
setAutoCommit(false). This effectively starts a JDBC transaction!
The SELECT is executed inside this JDBC transaction. The Session is
closed, and the connection is returned to the pool and released by
Hibernate — Hibernate calls close() on the JDBC Connection.
What happens to the uncommitted transaction?
The answer to that question is, “It depends!” The JDBC specification doesn’t say anything about pending transactions when close() is called on a connection. What happens depends on how the vendors implement the specification. With Oracle JDBC drivers, for example, the call to close() commits the transaction! Most other JDBC vendors take the sane route and roll back any pending transaction when the JDBC Connection object is closed and the resource is returned to the pool.
Obviously, this won’t be a problem for the SELECT you’ve executed, but look at this variation:
Session session = getSessionFactory().openSession();
session.beginTransaction();
Long generatedId = session.save(item);
session.close();
This code results in an INSERT statement, executed inside a transaction that is never committed or rolled back. On Oracle, this piece of code inserts data permanently; in other databases, it may not. (This situation is slightly more complicated: The INSERT is executed only if the identifier generator requires it. For example, an identifier value can be obtained from a sequence without an INSERT. The persistent entity is then queued until flush-time insertion — which never happens in this code. An identity strategy requires an immediate INSERT for the value to be generated.)
Its depend on hibernate-config and the connection pool config.
When try to close a session with an open transaction hibernate by default will not call to close on connection proxy (if you want to change this you need to define - hibernate.ejb.discard_pc_on_close true)
public void close() {
if ( !open ) {
throw new IllegalStateException( "EntityManager is closed" );
}
if ( !discardOnClose && isTransactionInProgress() ) {
Now , suppose that you defined discard_pc_on_close than in this case hibernate will call to close on the connection proxy (connection pool wrap connections), so now we depend on how the connection pool implement this.
You can see c3p0 implementation in : NewPooledConnection.
You will see that its depend on this flag - FORCE_IGNORE_UNRESOLVED_TXNS (default is false), so by default it will reset the transaction.
static void resetTxnState( Connection pCon,
boolean forceIgnoreUnresolvedTransactions,
boolean autoCommitOnClose,
boolean txnKnownResolved ) throws SQLException
{
if ( !forceIgnoreUnresolvedTransactions && !pCon.getAutoCommit() )

Get Hibernate Session from Interceptor

I'm writing a hibernate interceptor and I need to access the hibernate session object. Is their a direct way to access the hibernate session using the interceptor?
What I'm trying to do is to find out what database hibernate has connected to. For various reasons, this is going to be impractical to store as thread local data.
Yes, there is a way... just pass session to Interceptor after creation:
Session session = factory.openSession(interceptor);
interceptor.setSession(session);
And you have session inside interceptor! Just remember that:
Interceptor can't access session it's running in, so don't use it directly to change / add objects.
You can open temporary session on the same JDBC connection
Transaction will be the same for both sessions
try {
Connection connection = mySession.connection();
Session tempSession = HibernateUtil.getSessionFactory().openSession(connection);
// do something
tempSession.flush();
}
finally {
tempSession.close();
}
There seems no "official" way of getting hold of the session object neither through o.h.Interceptor neither through o.h.EmptyInterceptor. Moreover, Interceptor's Javadoc says:
There might be a single instance of Interceptor for a SessionFactory,
or a new instance might be specified for each Session. Whichever
approach is used, the interceptor must be serializable if the Session
is to be serializable. This means that SessionFactory-scoped
interceptors should implement readResolve().
The Session may not be invoked from a callback (nor may a callback
cause a collection or proxy to be lazily initialized).
The only way to get this information seems to be by using reflection and has been answered here.

Hibernate error "database is locked". How do i correctly close session?

In my application I open session, create criteria but dont close it. Then in other method I open session again, update object and receive database is locked on tr.commit().
If I put session.close() in first instance I receive
could not initialize proxy - no Session.
How do I close and open sessions correctly? Or do I need to copy proxy objects to those created by me and then close()?
Session session = HibernateUtil.getSessionFactory().openSession();
Transaction tr=session.beginTransaction();
Criteria criteria = session.createCriteria(MyDocument.class);
criteria.add(Expression.like("isMainDoc", 1));
List docs = criteria.list();
tr.commit();
session.close();
I am a complete begginer. i use sqlite. Any help would be appreciated. Thanks in advance.
Hibernate Session is generally tied to a thread.
So, perhaps you should restructure your code to get a session at the beginning of your processing (e.g. in ServletFilter instance of a web-app).
And then in each method, you can use the same session object, to start a new transaction (and then of course, end the transaction also.
public void doWork(){
Transaction tx = null;
try{
tx = session.beginTransaction();
}catch(){
} finally {
// if tx != null then.. close transaction, or rollback?
}
}
EDIT: And then ofcouse, close the session when the processing is done (in web-app, that could be also in the same ServletFilter)
Google: "Open Session In View" pattern.
Cause
You might be getting the error when you are trying to access properties of the MyDocument class instances returned by the query.
Hibernate is lazy by default. It returns you a proxy for an object instead of hitting the database whenever a reference property is accessed. This behavior can be overwritten whenever required.
Always remember that could not initialize proxy - no Session is recieved when the code tries to access a proxy properties (by hitting the database) and finds that the session is not available ( Session is needed as Hibernate accesses database using this interface)
Solution
Make sure that your session is open whenever Hibernate tries to load object which have not been loaded yet. How do you do that?
(In simple words) There are two schools of thoughts in Hibernate:
Fetch all the data that you might access before you close the Session OR
keep the Session open for the entire duration of time you work on the objects.
I would like you brush up topics such as the unit of work in Hibernate. Hibernate provides a wonderful interface to define boundaries on database access. Data must be accessed (read/written) between these boundaries. Check Here
hibernate.current_session_context_class in the hibernate configuration which can take the values jta | thread | managed | custom.Class. This variable defines the unit of work for your Session.
Last but most importantly try using Contextual Sessions (you must have come across .getCurrentSession()
which helps you to get the same session which is open everytime anywhere in your code. Hibernate handles everything behind the scenes.
Hope this answer serves as a guide for you for taking the correct path in using Hibernate rather than just solving this particular problem.
Follow the below steps when you are using hibernate transactions Read the API here.
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
//Or any other operation.
session.save(a);
tx.commit();
session.close();

ThreadLocal + java.sql.Connection + servlet filter = 2009?

I am writing some servlets with plain old mostly-JDBC patterns. I realized that I have several objects that would like to share a single transaction, and I'd like to enforce that one HTTP transaction = one database transaction.
I think I can do this via passing a Connection around in a ThreadLocal variable, and then having a servlet filter handling the creation/commit/rollback of said Connection.
Is there an existing framework that does this that I'm not privy to, or is this a reasonable late-00's way to do things?
Spring transaction management does exactly what you describe, it might be a little over whelming at first glance but all you will be needing (for the simplest case) is:
org.springframework.jdbc.datasource.DataSourceTransactionManager
org.springframework.jdbc.datasource.TransactionAwareDataSourceProxy
org.springframework.transaction.support.TransactionTemplate
Wire up your existing DataSource and wrap it in the TransctionAwareDataSourceProxy then create a DataSourceTransactionManager with the wrapped data source, keep these in your ServletContext. Then for each transaction create a TransactionTemplate passing in the transaction manager and call the execute(TransactionCallback) method to run your code. eg:
new TransactionTemplate(transactionManager).execute(new TransactionCallback(){
public void doInTransaction(TransactionStatus ts){
// run your code here...use the dataSource to get a connection and run stuff
Connection c = dataSourceProxy.getConnection();
// to rollback ... throw a RuntimeException out of this method or call
st.setRollbackOnly();
}
});
The connection will be bound to a thread local so as long as you always get the connection form the same datasource i.e. the wrapped one, you'll get the same connection in the same transaction.
Note this is the simplest possible spring transaction setup ... not nessarly the best or recommended one, for that have a look at the spring reference doc's or read spring in action.
... so I guess as a direct answer, yes it is a reasonable thing to be doing, it's what the spring framework has been doing for a long time.
Most appServer todays support JTA (Java Transaction Api): A transaction that spans over multiple open/close jdbc connections. It does the "threadLocal" stuff for you and it's J2EE compliant.
You use it like this in your filter:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
UserTransaction transaction = null;
try {
transaction = (UserTransaction)new InitialContext().lookup("java:comp/UserTransaction");
transaction.begin();
chain.doFilter(request, response);
transaction.commit();
} catch (final Exception errorInServlet) {
try {
transaction.rollback();
} catch (final Exception rollbackFailed) {
log("No ! Transaction failed !",rollbackFailed);
}
throw new ServletException(errorInServlet);
}
}
On the app-server, declare a Datasource with a jndi name, and use it in your code to retrieve a connection (do NOT make cx.commit(), cx.rollback() or cx.setAutocommit() stuff, it will interfere with JTA). You can open and close your connection several times in the same HTTP transaction, JTA will take care of it:
public void doingDatabaseStuff() throws Exception {
DataSource datasource = (DataSource)new InitialContext().lookup("/path/to/datasource");
Connection connection = datasource.getConnection();
try {
// doing stuff
} finally {
connection.close();
}
}
It is generally better to pass object with "Parameterisation from Above", the sleazing through with ThreadLocal. In the case of ServletFilter, an attribute of the ServletRequest would be an obvious place. The interface to non-servlet dependent code can extract the Connection to meaningful context.
If you cannot rely on a "real" app server and you want to avoid the not-so-lightweightness of Spring, using a filter to provide a connection, keep it on the thread and close it at the end of the request is indeed a practical and reasonable solution.
You would need some (essentially static) accessor class that allows to get() a connection and a setRollbackOnly().
Upon end of the request, from the filter's perspective, make sure to catch exceptions (upon which you should log and set to rollback only) and commit/rollback, close the transaction accordingly.
In most applications and web containers (and JTA usually makes similar assumptions) a request will be processed by exactly one thread and associating the one database connection with the thread for re-use between layers during the request is just the right thing to do.
Having a filter manage the transaction is a good approach to rolling your own transaction management.
The Java EE specification provides for transaction management, and alternative frameworks like Spring provide similar support (though that's not an endorsement; Spring doesn't necessarily do this well).
However, use of a ThreadLocal can create problems. For example, there are no guarantees that a single thread is used throughout a request, anything can access the Connection through the global variable, and testing can become more difficult if you are depending on some global state to be set up. I'd consider using a dependency injection container to explicitly pass a Connection to objects that need one.

Categories

Resources