How should I create a controller which is thread safe?
As per the best practice controllers are singleton.
Consider the below code in which im storing user data through a autowired service Object ,which makes my code stateful.
How would i make the below code thread safe.
#RestController
class ApiController {
#Autowired
IDbService< User > iDBService;
#RequestMapping(value = "/api/adduser", method = RequestMethod.POST)
public ResponseEntity<User> createUser(#RequestBody User user){
User savedUser=iDBService.create(user);
return new ResponseEntity<User>(savedUser, HttpStatus.CREATED);
}
Here is my Service implementation.
I have shared variable in my service
public class IDbServiceImpl<T> implements IDBService<T>{
#Autowired
GenericRepository<T, Serializable> genericRepository;
#Override
public T create(T object) {
return genericRepository.save(object);
}
}
Your controller is a singleton by default and your service is singleton by default too.
Therefore in order to make them thread safe you have to make sure that the operations that take place inside the service must be thread safe, in case of changing the state of an object inside the service ie. a list.
In case of using a rdbms then you have a transaction related problem.
If you use spring and Jpa, the transaction manager will take care for your updates provided that you use #Transactional. In case of plain jdbc method then you can either use pure jdbc and do the transaction handling on your own or use spring-jdbc that comes with a transaction manager.
If you want the database rows not to be changed in case of a write in progress then you have to take into consideration row-locking related mechanisms. – gkatzioura Feb 7 at 15:23
In case of JPA using #Transactional will do the work. However depending on your application you might have to consider locking. Check this article on locking with jpa.
Controllers are singletons, therefore they should be implemented in a thread safe manner.
Design your application in a way that controllers are stateless. Add transactional support in your #Repository layer.
Example:
public class GenericRepository<T, Serializable> {
#Transactional
public void save(T object) {
// save user
}
}
You could use Spring declarative transaction management mechanism. The #Transactional annotation itself defines the scope of a single database transaction.
Your controller looks thread safe. As there is no instance variable storing the state. User object will be different for each request and will be resolved by the MVC framework.
Related
If I have a standard CrudRepository and a Controller like below, is this thread safe? I know that this class is treated as a singleton, but wasn't sure if Spring handles repositories in a special way that allows for no handling on my side.
#Controller
public class TestController {
#Autowired
private TestRepository testRepository;
#RequestMapping(path = "/test")
public void addTest() {
TestObj o = new TestObj();
testRepository.save(o);
}
}
public interface TestRepository extends CrudRepository<TestObj, Integer> {
}
The standard CrudRepository is not threadSafe.But i think that you ask about how the data concurrent access are handling?
first you should to know that there are several phenomes that may occur when using transaction simultaneously and can affect the integrity of data such as: lost update, dirty read, unrepeatable read, last commit wins and phantom read.
For managing these phenomes according to your requirement spring offer the possibility to specify the desired isolation level inside #Transactional annotation.
for more information :
https://www.baeldung.com/spring-transactional-propagation-isolation
https://docs.spring.io/spring-data/data-jpa/docs/current/reference/html/#jpa.bootstrap-mode
I'm working on spring boot and I need to clarify something regarding to transaction management.
For example, I do have 2 classes that run two separate jobs (the first job is to create profile on database and the second job is to call restful application also profile creation but on different system).
This 2 jobs must be in transactional. Both success needed. It should not create any profile on any data store if one of the job is fails)
Since I'm really new in this Spring. I hope to get suggestion and need to know what is the best practice for this scenario.
There is a facade pattern. I suggest to make a facade service to join the logic of two services. Services must be separate, because working with profiles and communicating with other system are different parts of business logic.
For example, there are ProfileService and OuterService to work with profiles and to outer communication. You can write SomeFacadeService to join two methods and wrap it in one transaction. Default propagation of #Transactional is REQUIRED. So transaction will be created on method SomeFacadeService.doComplexJob and methods profileService.createProfile and outerService.doOuterJob will join the current transaction. If exception occurs in one of them whole SomeFacadeService.doComplexJob will be rolled back.
#Controller
public class SomeController {
#Autowired
SomeFacadeService someFacadeService ;
#RequestMapping("/someMapping")
public void doSomeJob() {
someFacadeService.doComplexJob();
}
}
#Service
public class SomeFacadeService {
#Autowired
ProfileService profileService;
#Autowired
OuterService outerService;
#Transactional
public void doComplexJob() {
profileService.createProfile();
outerService.doOuterJob();
}
}
#Service
public class ProfileService {
#Transactional
public void createProfile() {
// create profile logic
}
}
I am using spring and hibernate. i am using spring for transaction management. i have below class.
#Service
#Transactional(readOnly = true)
public class Sample implements SampleInterface{
#Override
public List<Some> getData(){
//gets data after that it updates something
setStatus(someId);
}
#Override
#Transactional
public void setStatus(Long someId){
//sets status
}
}
If i dont keep #Transactional for getData() then i get below exception.
Caused by: org.springframework.dao.InvalidDataAccessApiUsageException: Write operations are not allowed in read-only mode (FlushMode.MANUAL): Turn your Session into FlushMode
if i keep #Transactional for getData() then it will save properly. what is an issue here? any how i have #Transactional for setStatus(). Still do i need to keep #Transactional for getData() as it is calling a public method which will set the status?
Thanks!
The problem is a bit complex and is caused by calling setStatus() inside getData(). When you are calling getData() from outside, you are actually calling a Java proxy created for you by Spring framework. This proxy applies transaction behaviour (starts read-only transaction) and delegates to your actual service class. This works fine.
However, when you call setStatus(), you are bypassing the transactional proxy and calling your service directly. In other words the request to setStatus() is not intercepted, and #Transactional is ignored.
There is no easy way to deal with this problem and ejb has the same issue. You just have to be extra careful when calling public methods inside the same class.
See also
8.6.1 Understanding AOP proxies - official documentation
Spring pitfalls: proxying - my blog
When you call getData (without #Transactional on the method) Spring will start a read only transaction as that is the default for your class and when getData calls setStatus Spring will use the existing rad only transaction instead of creating a new one. That's the reason you are getting the exception.
The default transaction propagation is PROPAGATION REQUIRED. Read more on the topic at http://static.springsource.org/spring/docs/3.0.x/reference/transaction.html#tx-propagation
I'm trying to get the clear picture of how this works:
-What is the advantage of using DAO class with DAO interface?
-How to handle Hibernate exceptions i.e
public String doSomething(){
Session session = sessionFactory.getCurrentSession();
session.beginTransaction();
Query query = session.createQuery("");
Object o = query.uniqueResult();
session.close();
return "success";
}
I'm not "forced" to try/catch, so how do I catch/intercept any exceptions that may occur?
-Is opening session everytime for new DAO method more expensive than getting the current session? Should I close the session if I use get?
Question Update:
I have #Service annotation in my service classes and for each method using dao interface I've got #Transactional above. Also I've added #Repository to all my DAO classes
Update II:
I'm considering opening bounty for this questions because I want to know more details and this time I'll provide some.
Spring context
Controller
Service Interface
Service Implementation
DAO interface
DAO implementation
So I want to utilize spring MVC as much as possible, how do I make session opening/closing handled by #Transactional?
How do I catch the exceptions(i.e. non existing record or database failed) if any.
What I'm doing wrong? Can anyone suggest some improvements?
A few things on the hibernate session side...
1.) I would take a look a integrating Spring's transaction management into your project. This way you don't have to worry about opening and closing your session's because Spring will handle this for you with intercepts using the #Transactional annotation.
2.) If spring is handling your transactions you won't have to worry about doing the finally calls to make sure everything is closed or rolled back.
3.) If you decide not to use Spring to manage the sessions you should not keep it open for any extended period of time but again, if you use Spring you don't have to worry about it.
As far as the interface on the DAO classes i offer this...
1.) It is considered a good design practice to code to interfaces (see comments left below) and here are a few good reasons why.
lets say you have a...
public interface ShoppingCartService{
public void doStuff(Object obj);
}
You could expose this service as a servlet and deal with the just the 'contract' your interface creates or even hide the fact your using Hibnerate, JDBC or anything else...
#Service
public class PetShopShoppingCartService implements ShoppingCartService{
#Transactional(propagation=Propagation.REQUIRED)
public void doStuff(Object obj){
//The Pet Shop service impl uses hibernate!;
}
}
or...
public class DrugStoreShoppingCartService implements ShoppingCartService{
public void doStuff(Object obj){
//The Drug Store service uses JDBC;
}
}
Or even...
public class NextBigThingShoppingCartService implements ShoppingCartService{
public void doStuff(Object obj){
//do stuff with next big thing;
}
}
I think you get the picture. If you developing public api's or exposing services this becomes pretty important.
Lastly, another good reason to have the interfaces is with working in a team of more than a couple developers. You can quickly stub out an interface, check-in and tell everyone else that this is how it's going to look. This allows them to see what's important and even mock their own impl if they need to (ThingServiceMockDataImpl)
Just because you're not forced to catch exceptions when using Spring's HibernateTemplate doesn't mean that they will not get thrown. They will just be RuntimeExceptions instead of checked exceptions. Also, getCurrentSession() does not open a new session each time you call it, it returns the local Thread's Session.
There are lots of advantages, including lack of code coupling, encapsulation, and transaction demarcation for using the DAO strategy instead of putting your data access code directly into your controller. See http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html for more info.
Considering there is no #PersistenceContext available to inject the EntityManager, plus you need to manually manage Transactions, what is the best way to design such an application?
For the EntityManagerFactory/EntityManager, as far as I can see, you must have each DAO accepting an EntityManager in the costructor e.g.
public class DAOImpl implements DAO
{
private EntityManager em;
DAOImpl(EntityManager em){
this.em = em;
}
//all CRUD operations follow
}
The first question that rises is when do you call EntityManager#close()?
Point A: The way I see it, you are better off doing this in a Filter at the end of the request cycle, which implies that you associate the EntityManager with the current thread (using ThreadLocal?)
Second question is, how and when do you inject the EntityManager?
Considering there is a ServletContextListener where we create and close the EntityManagerFactory, we could have a static method as follows
public static EntityManager createEntityManager(){
return entityManagerFactory.createEntityManager(PERSISTENT_NAME);
}
but since we want to encapsulate creating the DAO, we could use a factory e.g.
public class DAOFactory
{
public static DAO dao(){
//return a new DAO
}
}
As per Point A we should use a ThreadLocal to create the DAO using the EntityManager for the current Thread.
For managing Transactions.
The best way I can think of (which mimics the JPA spec) is to create your own Transaction annotation and use reflection to inject the begin/commit/rollback operations.
You should then return a Proxy from the DAOFactory which handles the transactions
I wouldn't do all that. Why try to recreate the whole JPA spec yourself? You just need to be able to use JPA without a container.
Spring can help you with this. Try it.