Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Bean Hangs on Method with @Transactional

Just a little background , I'm a new developer who has recently taken over a major project after the senior developer left the company before I could develop a full understanding of how he structured this. I'll try to explain my issue the best I can.

This application creates several MessageListner threads to read objects from JMS queues. Once the object is received the data is manipulated based on some business logic and then mapped to a persistence object to be saved to an oracle database using a hibernate EntityManager.

Up until a few weeks ago there hasn't been any major issues with this configuration in the last year or so since I joined the project. But for one of the queues (the issue is isolated to this particular queue), the spring managed bean that processes the received object hangs at the method below. My debugging has led me to conclude that it has completed everything within the method but hangs upon completion. After weeks of trying to resolve this I'm at end of my rope with this issue. Any help with this would be greatly appreciated.

Since each MessageListner gets its own processor, this hanging method only affects the incoming data on one queue.

@Transactional(propagation = Propagation.REQUIRES_NEW , timeout = 180)
 public void update(UserRelatedData userData, User user,Company company,...)
 { 
   ...
   ....
   //business logic performed on user object
   ....
   ......
   entityMgr.persist(user);

   //business logic performed on userData object
   ...
   ....
   entityMgr.persist(userData);

   ...
   ....

   entityMgr.flush();

}

I inserted debug statements just to walk through the method and it completes everything including entityMgr.flush.().

like image 954
Rhouujin Avatar asked Nov 17 '11 07:11

Rhouujin


People also ask

How does Spring @transactional really work?

At a high level, Spring creates proxies for all the classes annotated with @Transactional, either on the class or on any of the methods. The proxy allows the framework to inject transactional logic before and after the running method, mainly for starting and committing the transaction.

Does @transactional works on private method?

In Spring, nothing happens if you put @Transactional on a private method because @Transactional only causes transactions to take place when the method is invoked from another object. The only exception (haven't tested this to see if it works) might be on an inner class.

Why @transactional annotation is used in Spring?

So when you annotate a method with @Transactional , Spring dynamically creates a proxy that implements the same interface(s) as the class you're annotating. And when clients make calls into your object, the calls are intercepted and the behaviors injected via the proxy mechanism.

Does @transactional close session?

@Transactional helps you to extend scope of Session . Session is open first time when getCurrentSession() is executed and it is closed when transaction ends and it is flushed before transaction commits.


4 Answers

REQUIRES_NEW may hang in test context because the transaction manager used in unit testing doesn't support nested transactions... From the Javadoc of JpaTransactionManager:

* <p>This transaction manager supports nested transactions via JDBC 3.0 Savepoints.
 * The {@link #setNestedTransactionAllowed "nestedTransactionAllowed"} flag defaults
 * to {@code false} though, since nested transactions will just apply to the JDBC
 * Connection, not to the JPA EntityManager and its cached entity objects and related
 * context. You can manually set the flag to {@code true} if you want to use nested
 * transactions for JDBC access code which participates in JPA transactions (provided
 * that your JDBC driver supports Savepoints). <i>Note that JPA itself does not support
 * nested transactions! Hence, do not expect JPA access code to semantically
 * participate in a nested transaction.</i>

So clearly if you don't call (@Java config) or set the equivalent flag in your XML config:

txManager.setNestedTransactionAllowed(true);

or if your driver doesn't support Savepoints, it's "normal" to get problem with REQUIRES_NEW... (Some may prefer an exception "nested transactions not supported")

like image 71
p3consulting Avatar answered Oct 06 '22 05:10

p3consulting


This kind of problems can show up when underlying database has locks from uncommitted changes.

What I would suspect is some other code made inserts/deletes on userData table(s) outside transaction or in a transaction which takes very long time to execute since it's a batch job or similar. You should analyze all the code referring to these tables and look for missing @Transactional.

like image 23
mrembisz Avatar answered Oct 06 '22 03:10

mrembisz


Beside this answer, you may also check for the isolation level of your transaction — perhaps it's too restrictive.

Does the update() method hang forever, or does it throw an exception when the timeout elapses?

like image 45
MaDa Avatar answered Oct 06 '22 03:10

MaDa


Unfortunately I have the same problem with Propagation.REQUIRES_NEW. Removing it resolves the problem. The debugger shows me that the commit method is hanging (invoked from @Transactional aspect implementation).

The problem appears only in the test spring context, when the application is deployed to the application server it works fine.

like image 29
Vladimir Balandin Avatar answered Oct 06 '22 03:10

Vladimir Balandin