4

I need to set some context before every database operation (I have tried using Oracle's package-level variables, but due to some issues with package recompilation, I will experiment with DBMS_SESSION and/or DBMS_APPLICATION_INFO), so that we can get specific user info anywhere we need it (procedures, triggers, etc.), instead of having dozens of database connections identified as "JBoss".

I have written a Java EE interceptor that intercepts calls to a @Stateless bean. It calls an Oracle function to set some session context (look at this question for some sample code How to tell if a transaction is active in a Java EE 6 interceptor).

My first worry was connection pooling. At first I thought that the default @PersistenceContext propagation provided by Java EE would be enough to guarantee that everything runs in the same connection/transaction/EntityManager, and I only had to unset everything at the end of my interceptor (in a finally block) before the connection is returned to the pool. It seemed a little fragile, but I thought it could work.

Then I found out that Hibernate has a property called hibernate.connection.release_mode (Hibernate docs about hibernate.connection.release_mode, Red Hat docs about org.hibernate.ConnectionReleaseMode) and that the default and recommended behavior when using JTA transactions is to release the connection after every statement (although the docs say something about re-acquiring the same underlying connection, which just confused me).

Now I'm not even sure I can reliably set something in an interceptor that will be visible only to this user/operation without the risk of somebody else grabbing the same connection in the middle of my business method and making a mess with my user context. As I understand it, Oracle database session variables are kept for a connection, not for a transaction or a @PersistenceContext (the database knows nothing about the persistence context after all, and a connection can be used for multiple transactions).

I'm about to give up because this is looking more and more fragile as I learn more about the implementation details of all the technologies involved. Can this user context idea be made to work or should I try a totally different approach? And how could I test/debug my implementation to be sure there aren't any concurrency issues lurking around? I haven't found any useful event listener to monitor the framework behavior, and building a program to stress test the server is too much work to invest in something I'm not sure is supposed to work anyway.

I'm using JBoss AS 7.1, EJB 3.1, an Oracle 10g database, and JPA 2.0 (backed by Hibernate, although we do not use any Hibernate-specific API).

Community
  • 1
  • 1
marcus
  • 5,041
  • 3
  • 30
  • 36
  • I guess I will avoid this kind of thing because it's very bug-prone, but it would be nice to undersdand what happens under the hood. David Blevins ( http://stackoverflow.com/questions/269186/besides-ear-and-ejb-what-do-i-get-from-a-java-ee-app-server-that-i-dont-get-in/9199893#comment19857118_9199893 ) suggests release_mode=after_statement is just a "don't bother managing what is already managed" setting, which would explain that paragraph that says “(...)re-acquire the same underlying JDBC connection(...)” – marcus Jan 12 '13 at 22:31
  • Something that has ocurred to me now: maybe release_mode is "after_statement" by default so that the programmer can use JPA and JDBC calls in the same transaction without using two separate connections? – marcus Mar 04 '13 at 20:41
  • So I finally found out **why** release_mode=after_statement was added and needed to be the default in JTA transactions: http://www.mail-archive.com/hibernate-dev@lists.jboss.org/msg00612.html (tl;dr: because some containers could think Hibernate is leaking connections if it opens a connection in a nested EJB call and leaves it open for the caller to reuse). I'm still not completely sure it's safe to assume that nobody else will reuse the connection between JPA statements. – marcus Mar 13 '13 at 04:15

2 Answers2

2

I would personally avoid trying to set individual parameters on a JDBC connection from a pool. After all, the idea of a pool is that all connections are identical. So while your interceptor idea would work I am also worried about how fragile it would be. Any bugs in that implementation would be the nastiest sort of race conditions.

On the other hand, because you're using Oracle you might want to look at EclipseLink. It implements JPA2 and was heavily funded by Oracle so it supports all their bizarre features. You might want to look into using 'Isolated Client Sessions'. It looks to support Virtual Private Databases which require individual session set up. So that would be a solution if you need to change session context.

Mark Robinson
  • 3,135
  • 1
  • 22
  • 37
  • 1
    Thanks for your reply, it was useful since I didn't know anything about Isolated Client Sessions. For now, I will avoid doing fancy things while I'm not sure I **really** need them. Also, I'm not sure it is easy to use EclipseLink on JBoss AS: http://blog.ringerc.id.au/2012/06/most-important-lesson-in-java-ee.html (see last comment) – marcus Jan 08 '13 at 15:06
2

So I'll answer my own question with all the things I have found out lately.

In order to understand server behavior, I changed my JBoss configuration to use a pool of only 1 connection, so I could detect when somebody else is blocked waiting.

If the current operation is inside a transaction (e.g. @TransactionAttribute(REQUIRED)), the connection won't be used for anything else until the transaction finishes (other clients will have to wait). However, if you read the database without a transaction, other clients could grab the same connection while you are not using it, even before your business method finishes (I don't know how much of this behavior is standard and how much is an implementation detail).

Hibernate does release the connection after every statement by default and that's why the connection can be reused in a non-transactional method. On the other hand, JDBC and JEE have the features needed to re-acquire the same connection if you are still in the same transaction.

But why does Hibernate release a connection that it's going to re-acquire later? If Hibernate didn't release it, some JEE servers could think that Hibernate is leaking connections when it opens a connection in a nested EJB call and leaves it open for the caller to reuse. That is explained in this post:

http://www.mail-archive.com/hibernate-dev@lists.jboss.org/msg00612.html

To be safe, all data we need to save (and later present to the user) is explicitly passed as parameters, but for logging purposes we did use some data stored in the Oracle session, knowing that the connection cannot be reused by other clients as long as you use transactional business methods.

Update: It seems to be possible to do what I want using some app server specific settings related to connectors and/or custom data sources (not sure what is the best answer here: https://developer.jboss.org/thread/250132)

marcus
  • 5,041
  • 3
  • 30
  • 36
  • Something like that would be very useful for DBAs. When using connection pools many fancy Oracle investigation tools are useless. DBAs can no more tell "Who, how and why is killing performance of DB server". But some of performance counters are also booked on MODULE account, so "we" would be able to tell which application's part is the most problematic. It would be also nice if it was possible to turn on session tracing (on Oracle side) for a particular transaction. – ibre5041 Dec 06 '13 at 13:13
  • We've got it working, but there's yet another gotcha: nested EJB calls. If one EJB calls another EJB and both use the same interceptor, you must ensure that the **last** finally resets the context, not the first (as it would happen in a simplistic implementation). I used the TransactionSynchronizationRegistry to store a counter that's incremented on every call and decremented in the finally block. – marcus Dec 29 '13 at 00:31