Reputation: 6802
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
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:
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