gabriel119435
gabriel119435

Reputation: 6802

How to correctly deal with concurrency?

I'm building an REST API with javaEE. I'm using TomEE as application server. I have a Singleton JPA DAO to deal with Postgres database and Stateless service to provide methods to my RESTfull class, which has GET,POST and DELETE methods. Until now, I'm using rest assured to test my url routes. Everything is working fine, but I wanted to stress my system, so I did this:

  Runnable r1 = () -> {
        for (int i = 0; i < 10; i++) {
            RegisterAndLogService service = new RegisterAndLogService();
            //lots of service calls
        }
    };

    Runnable r2 = () -> {
        for (int i = 0; i < 10; i++) {
            RegisterAndLogService service2 = new RegisterAndLogService();
            //lots of service calls
        }
    };
    Thread t1 = new Thread(r1);
    Thread t2 = new Thread(r2);
    t1.start();
    t2.start();

But when second iteration on one of my threads would begin, I got this:

java.lang.IllegalStateException: Transaction already active

How can I pile up dao resquests and deal with them properly one at a time waiting current transaction to finish? Can EJB/JPA somehow be involved into this? Into saving asked requests and dealing with them asap?

Upvotes: 0

Views: 123

Answers (1)

Stephen C
Stephen C

Reputation: 718856

It is difficult to understand what you are doing here, and whether the problem you are asking about is in the test code or the API under test ... or the stuff behind the API.

But if you are getting a "Transaction already active" that means that something is doing something like:

  • trying to use a single JPA transaction manager with multiple threads (don't),
  • trying to do multiple simultaneous transactions on the same thread (don't), or
  • not cleaning up (committing or rolling back) transactions.

In the last case, look for cases where you can "escape" from a code region responsible for a transaction via an exception without rolling it back.

I would advise that you review the documentation on JPA that you have been using to make sure that you understand the relationships between transactions, transaction managers and threads.


I believe my case is the first one - trying to use a single JPA transaction manager with multiple threads. Is there any design pattern or good practice about keeping a single JPA transaction manager while have lots of instances of stateless beans being requested?

The only way that works is for each thread to have its own transaction manager. Either each thread must create (and release) its own TM programatically, or you rely on the framework to do this; e.g. as instructed by various annotations.

TM objects are designed to be light-weight (i.e. cheap to instantiate) and non-thread-safe. You shouldn't share them across threads1 and you shouldn't need to recycle them.


1 - ... unless you have a single JPA transaction that needs to span multiple threads. For that, there are "ways to do it".

Upvotes: 1

Related Questions