SQL Zone is brought to you in partnership with:

Yongjun Jiao (yongjun.jiao@sungard.com) has been a professional software developer for the past 10 years. His expertise covers Java SE, Java EE, Oracle, application tuning and high performance and low latency computing. He is a technical manager with SunGard Global Services. Yongjun has posted 3 posts at DZone. View Full User Profile

Asynchronous (non-blocking) Execution in JDBC, Hibernate or Spring?

10.15.2010
| 23619 views |
  • submit to reddit

There is no so-called asynchronous execution support in JDBC mainly because most of the time you want to wait for the result of your DML or DDL, or because there is too much complexity involved between the back-end database and the front end JDBC driver. 
Some database vendors do provide such support in their native drives. For example Oracle supports non-blocking calls in its native OCI driver. Unfortunately it is based on polling instead of callback or interrupt.
Neither Hibernate or Spring supports this feature.

But sometimes you do need such a feature. For example some business logic is still implemented using legacy Oracle PL/SQL stored procedures and they run pretty long. The front-end UI doesn't want to wait for its finish and it just needs to check the running result later in a database logging table into which the store procedure will write the execution status.
In other cases your front-end application really cares about low latency and doesn't care too much about how individual DML is executed. So you just fire a DML into the database and forget the running status.

Nothing can stop you from making asynchronous DB calls using multi-threading in your application. (Actually even Oracle recommends to use multi-thread instead of polling OCI for efficiency).
However you must think about how to handle transaction and connection (or Hibernate Session) in threads.
Before continuing, let's assume we are only handling local transaction instead of JTA.

1. JDBC
It is straightforward. You just create another thread (DB thread hereafter) from the calling thread to make the actual JDBC call.
If such a call is frequent, you call use ThreadPoolExecutor to reduce thread's creation and destroy overhead.

2. Hibernate
You usually use session context policy "thread" for Hibernate to automatically handle your session and transaction.
With this policy, you get one session and transaction per thread. When you commit the transaction, Hibernate automatically closes the session.
Again you need to create a DB thread for the actual stored procedure call.

Some developer may be wondering whether the new DB thread inherits its parent calling thread's session and transaction.
This is an important question. First of all, you usually don't want to share the same transaction between the calling thread and its spawned DB thread because you want to return immediately from the calling thread and if both threads share the same session and transaction, the calling thread can't commit the transaction and long running transaction should be avoided.
Secondly Hibernate's "thread" policy doesn't support such inheritance because if you look at Hibernate's corresponding ThreadLocalSessionContext, it is using ThreadLocal class instead of InheritableThreadLocal.

Here is a sample code in the DB thread:

// Non-managed environment and "thread" policy is in place
// gets a session first
Session sess = factory.getCurrentSession();
Transaction tx = null;
try {
  tx = sess.beginTransaction();

  // call the long running DB stored procedure

  //Hibernate automatically closes the session 
  tx.commit();
}
catch (RuntimeException e) {
  if (tx != null) tx.rollback();
  throw e;
}


3.Spring's Declarative Transaction

Let's suppose your stored procedure call is included in method:

  @Transactional(readOnly=false)
  public void callDBStoredProcedure();


The calling thread has the following method to call the above method asynchronously using Spring's TaskExecutor:

  @Transactional(readOnly=false)
  public void asynchCallDBStoredProcedure() {
        //creates a DB thread pool
        this.taskExecutor.execute(new Runnable() {
            @Override
            public void run() {
                //call callDBStoredProcedure()
            }
        });
  }

You usually configure Spring's HibernateTransactionManager and the default proxy mode (aspectj is another mode) for declarative transactions. This class binds a transaction and a Hibernate session to each thread and doesn't Inheritance either just like Hibernate's "thread" policy.

Where you put the above method callDBStoredProcedure() makes a huge difference.If you put the method in the same class as the calling thread, the declared transaction for callDBStoredProcedure() doesn't take place because in the proxy mode only external or remote method calls coming in through the AOP proxy (an object created by the AOP framework in order to implement the transaction aspect. This object supports your calling thread's class by composing an instance of your calling thread class) will be intercepted. This meas that "self-invocation", i.e. a method within the target object (the composed instance of your calling thread class in the AOP proxy) calling some other method of the target object, won't lead to an actual transaction at runtime even if the invoked method is marked with @Transactional!

So you must put callDBStoredProcedure() in a different class as a Spring's bean so that the DB thread in method asynchCallDBStoredProcedure() can load that bean's AOP proxy and call callDBStoredProcedure() through that proxy.

About The Author

Yongjun Jiao is a technical manager with SunGard Consulting Services. He has been a professional software developer for the past 10 years. His expertise covers Java SE, Java EE, Oracle, application tuning and high performance and low latency computing. 
 
0
Your rating: None
Published at DZone with permission of its author, Yongjun Jiao.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Sachin Badoni replied on Fri, 2010/10/15 - 6:23am

I am not sure, but will it not lead to Thread issue under heavy load?

 

Yongjun Jiao replied on Fri, 2010/10/15 - 8:35am in response to: Sachin Badoni

A reasonable concern. So it is recommended to use Java's Executor where you can specify the number of Core and Max threads, inactivity period etc.

Another solution for non-blocking is to use your client's side non-blocking feather if it support. In case of Swing, you can use SwingWorker to actually call the backend long-runing method. However in this case the connection between the front-end and back-end will be held for long.

joshua long replied on Fri, 2010/10/15 - 4:31pm in response to: Yongjun Jiao

You could also use Spring's @Async annotation and simply return Future<?>.

Henk De Boer replied on Fri, 2010/10/15 - 5:00pm

You could also use Java EE's @Asynchronous annotation which returns a Future. In this case too, the asynchronous execution uses a new transaction.

In the majority of the cases this is what you want, but it's not always the case. If you want to parallelize a number of updates for performance reasons (to take advantage of your parallel IO capabilities and multiple cores), than you actually do want to share the TX and PU between threads.

Liam Knox replied on Sat, 2010/10/16 - 7:17pm

Well for one thing your Spring @Transactional example is not going to behave as you expect as you are annotating the call that queues the asynchronous work and not the call that will be performed on the thread doing the db work i.e. the run method.

Also your AOP contentions are flawed as the self reference concern is purely dependent on whether your are using byte-code based weaving(AspectJ for example) or proxy based interception (Java Proxys/CGLib).

Yongjun Jiao replied on Mon, 2010/10/18 - 9:38am

For the last comment, the code in section 3 did annotate the following method with @transactional in a separate bean:

public void callDBStoredProcedure();

 So the calling thread (in the TaskExecutor) will call the above method through an AOP CGLib proxy which was generated by the default "proxy" mode.

The code also mentioned "aspectj" as another mode. What is not obvious is that it didn't explicitly tell readers the "aspectj" mode supports self - invocation calls. Sorry for that.

 

Liezel Jane Jandayan replied on Mon, 2011/08/22 - 9:05pm

The most significant aspect of asynchronous communications is variable bit rate, or that the transmitter and receiver clock generators do not have to be exactly synchronized. Asynchronous communication is communication taking place at different times or over a certain period of time. The term has acquired wide currency in online learning, where exchanges between teachers and students are frequently enacted asynchronously rather than in simultaneous or face-to-face conversations.Yochanan Berkowitz

 

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.