Spring transactions and their interaction with the synchronized keyword - java

I have a DAO class that uses Spring JDBC to access an SQLite database. I have declared transactions on the DAO methods themselves since my service layer never combines queries in a transaction.
Since I use a few worker threads in parallel but only one thread can update an SQLite DB at the same time, I use synchronized to serialize access to the DAO.
At first, I synchronized externally from my service class, for example:
synchronized (dao) {
dao.update(...);
}
Then, I figured I might as well get rid of the external synchronization and put synchronized on the DAO method itself:
public synchronized void update(...) {
// Spring JDBC calls here
}
The strange thing is: my queries now take twice the time they used to!
Why?

Well, one difference is obvious:
synchronized (dao) {
// here you are synchronizing on the transactional proxy
}
public synchronized void update(...) {
// and here you are synchronizing on the target class, *inside* the proxy
}
What the implications of this are depends on your other code, but that's the obvious difference.

My guess is your update method or entire class is annotated with Transactional or wrapped by transactional proxy through other means. This means whenever you call dao's method, the transactional proxy retrieves db connection from the pool, opens a transaction and then calls the real method.
In your first scenario you synchronize before even reaching the proxy, thus no connection and transaction magic happens. In the second scenario you do the waiting call after that.
If there are multiple threads trying to perform simultaneous updates there will be only one doing the update and the rest will be first opening new connections and then waiting for dao access. As a consequence instead of one connection being constantly reused you will have multiple connections in use. I can only guess how this really affects the performance but you can experiment with different pool size starting with one.

Related

Does Spring #Transactional annotated on method ensure the flush of data exactly when the method ends?

I have this simplified escenario in a Spring application with Java and Hibernate for persistence provider:
#Transactional
void method1() { // some savings}
#Transactional
void method2() { // some savings}
When I run a parent method (not annotated as transactional)
void parentMethod() {
method1();
method2();
}
Can I make sure that when the method finishes the changes are impacted in the database immediately before the method is called?
Or that changes could be flush to database later, with some delay?
I'm interested on other applications seeing the changes made in database immediately when method1 finishes (and before method2 be called)
Update
My parent method is not defined in the same class, and the class and firm of the my parent method has not #Transactional annotation
Thanks!
To your question ... ensure the flush of data exactly when the method ends? No, not exactly when the method ends, but latest when the method ends.
Within transaction you can flush the current state as many times as you wish. Flushing means that you synchronize your JPA session with database. See Hibernate doc regarding this. Flushing does not mean your changes are durable; if transaction rolls back later on, these changes will be automatically reverted. The commit operation performs different steps, one of them is to ensure that the JPA (e.g. Hibernate) session is synchronized with DB, and, if needed, calls flush. If the session is already synchronized, flush will be skipped.
In the comments you wrote that the class and the method parentMethod are not transactional and that method1() and method2() are defined in a separate class. In such case when the method1() is called, a new transaction will be started. When this method ends, this transaction will be committed. Any changes in the database done by this method will be durable, i.e. no matter what happens later on (exceptions, roll backs in other methods) these changes will remain in the database.
Some information relevant to your case can be found here because following is important:
If these methods are in the same class or not and
If you use Spring own AOP or AspectJ. Besides it depends on the class where your parentMethod is defined. If it is transactional, then these 2 calls will run within the existing transaction and there will be no commit after the 1st one is committed.

Preventing concurrent access to a method in servlet

I have a method in servlet that inserts tutoring bookings in database. This method has a business rule that checks if the tutor of this session is already busy in that date and hour. The code looks something like this :
class BookingService {
public void insert(Booking t) {
if(available(t.getTutor(), t.getDate(), t.getTime())) {
bookingDao.insert(t);
} else {
// reject
}
}
}
The problem is that multiple users may simultaneously try to book the same tutor on the same date and time, and there is nothing that prevents them both to pass the test and insert their bookings. I've tried making insert() synchronized and using locks, but it doesn't work. How can I prevent concurrent access to this method?
Using synchronized is an inadequate way to try to solve this problem:
First, you will have coded your application so that only one instance can be deployed at a time. This isn’t just about scaling in the cloud. It is normal for an IT department to want to stand up more than one instance of an application so that it is not a single point of failure (so that in case the box hosting one instance goes down the application is still available). Using static synchronized means that the lock doesn’t extend beyond one application classloader so multiple instances can still interleave their work in an error prone way.
If you should leave the project at some point, later maintainers may not be aware of this issue and may try to deploy the application in a way you did not intend. Using synchronized means you will have left a land mine for them to stumble into.
Second, using the synchronized block is impeding the concurrency of your application since only one thread can progress at a time.
So you have introduced a bottleneck, and at the same time cut off operations’ ability to work around the bottleneck by deploying a second instance. Not a good solution.
Since the posted code shows no signs of where transactions are, I’m guessing either each DAO creates its own transaction, or you’re connecting in autocommit mode. Databases provide transactions to help with this problem, and since the functionality is implemented in the database, it will work regardless of how many application instances are running.
An easy way to fix the problem which would avoid the above drawbacks would be to put the transaction at the service layer so that all the DAO calls would execute within the same transaction. You could have the service layer retrieve the database connection from a pool, start the transaction, pass the connection to each DAO method call, commit the transaction, then return the connection to the pool.
One way you could solve the problem is by using a synchronized block. There are many things you could choose as your locking object - for the moment this should be fine:
class BookingService {
public void insert(Booking t) {
synchronized(this) {
if(available(t.getTutor(), t.getDate(), t.getTime())) {
bookingDao.insert(t);
} else {
// reject
}
}
}
}
If you have more than one instance of the servlet, then you should use a static object as a lock.

Spring #Transaction and #Async usage for database operations

In a spring application when we receive message #Service persist bean is calling the database operation to insert in to database & parallel #Service to parse & process message. In this case persist is using #Transactional. In order to make the flow in parallel, is it advised to add #Async for persist.
Additionally there is #Aspect on each save method called by persist service for logging & audit.
Is #Async advisable for database operations?
Does #Async create table locks?
All that #Async does is cause the methods of the annotated component to be executed on another thread, where it gets the thread from a pool (which can be specified, so you can choose for some operations to have a dedicated pool).
#Async itself doesn’t do anything to lock database tables, or anything else database-related. If you want database-level locking you will have to implement that through some other means. If you want the call to use a transaction you have to use the #Transactional annotation on the component being called asynchronously. The transaction will be separate from the caller's transaction. Of course the transaction can possibly cause database locking depending on the isolation level and database implementation.
It’s tricky to use #Async with database work. One pitfall occurs with jpa persistent entities passed across threads, when they have a lazy property that gets realized in the new thread (where the proxy is now invalid because it can’t get to the entityManager from the old thread). It’s safer if the things passed between threads are immutable.
#Async adds complexity and is hard to reason about. There are opportunities for race conditions and deadlocks where if you don’t get it exactly right then bad things can happen, and you can’t count on testing to uncover the issues. It’s working without a net, if you want any infrastructure to help with exception handling, retries, or other recovery you will have to provide it yourself.
So no, I wouldn’t necessarily call it advisable. It's a good capability to have in your toolbox that might be helpful for a few isolated cases, but pervasive usage would seem like a bad thing. There are alternatives if you’re looking for ways to persist data without blocking.

Transaction in Spring

I am new to Spring and have a question about transactions.
I know that for each http request there is a servlet thread which has its own stack. As far I know all the local variables and method reside on the stack. So if I have a method public void A(); then both the servlet thread A and thread B have a copy of a function in their stack.
Now If I annotated a method with #Transactional(propagation=Propagation.REQUIRED ,timeout=1,isolation=Isolation.READ_COMMITTED) then I would like to know the following points:
Does each thread A and thread B have their own stack and work independently?
If thread A is updating something and B is reading something because of in different stack is Isolation will work? or B will read the data with out any information about the thread A?
I want to know this by the diagram so that I can understand how end to end things work?
Each thread has its own stack, you're right here. But they don't have copies of methods. Method is just a series of operations. But they have copies of variables inside this method (local variables).
Speaking about isolation level, actually it has nothing to do with threads and stacks. It refers to a database isolation level notion. Spring asks your database for that level to be used for database transaction. PostreSQL has a great doc page explaining transaction isolation.
So it's not quite right here to ask how threads see each other, because in the sense of data they see what they get from the database. And the database returns data accordingly to current transaction isolation level. Each thread starts its own transaction, i.e. it creates a new connection to the database and tells it to start a new transaction.
Example
To feel what's going on under the hood, here is an example. Suppose you have such method:
#Transactional
public Person getPerson(int id) {
Person person = em.find(Person.class, id);
return person;
}
Here is what's going on under the Spring's hood per each line:
#Transactional
public Person getPerson(int id) {
// SQL sent to the database:
// Begin transaction
Person person = em.find(Person.class, id);
// SQL sent to the database:
// select p from person p where p.id = id
// the data from the database then gets converted to Java Person class
return person;
}
// after end of the method Spring automatically commits the transaction (not always, it depends on the `propagation` setting)
// SQL sent to the database:
// commit
Please, read PostgreSQL docs that explains transaction isolation in depth. Java threads only receive data accordingly to it.
Thread B will only see modifications in the database done by Thread A after the transaction of thread A completes.
It is still possible that thread B reads something from the database, then thread A updates something in the database and commits, and then thread B overwrites what thread A wrote.
To avoid that, you need to use some type of locking on the database, or use a stricter isolation level (but that carries high performance penalties, as often the database needs to perform a lot of locking to implement the stricter isolation level)
Brifely:
yes
B will read data with out any information about the thread A
Now Why this? in a servlet enviroment you have tipicaly one or more servlet and all dataat the class level and for this reason outside the doHttp methods share same data, servlet aren't thread safe.
But of course data inside a method are thread safe because each method callis a call function and will have a your thread for serving the method request and it has its own stack.
However if you have two concurrent method call and for this reason in two separated thread the the transaction will be not the same because the thrad local aren't the same and don't share the same immage of the db it is natural if you think about JPA the persistanceContext is a first level cache that is stored in the threadlocal. the my advice is use a higer level of transaction isolation for mitigate possible problem
I hope that it can help you

Java EE - Singleton EJB with Concurrent Access to Synchronized Method

I have an EJB as below. This has been created solely for test purposes - I'm "sleeping" the thread as I want to simulate the case where the query is scheduled again before the synchronized method has finished executing.
The observed behaviour is as expected - but is this the correct way to poll the database for, for example, rows that have been inserted so that some processing can be performed, before they are updated? I want the method to be synchronized as I don't want another call to modify the database state while processing those from a previous method call
#Singleton
public class MyResource {
#PersistenceContext(unitName="MyMonitor")
private EntityManager em;
#Schedule(second="*", minute="*", hour="*")
public synchronized void checkDb() throws SQLException, InterruptedException {
List<ReferenceNames> l =
em.createQuery("from Clients cs", Clients.class).getResultList();
Thread.sleep(2000);
System.out.println(l.size());
}
}
You should not implement a single point of database access yourself, just to make sure, that records are not changed during an update. For that, you want to use database locking. In Java EE / JPA 2.0 you have several locking modes at hand, check out for example this Oracle blog or this wikibook article. Concerning the other components trying to write during the locking, you have to react to the lock exception and implement some sort of retry mechanism.

Categories

Resources