9

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);
}

}

jones j alapat
  • 931
  • 3
  • 13
  • 26

3 Answers3

11

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.

Vlad Mihalcea
  • 142,745
  • 71
  • 566
  • 911
gkatzioura
  • 2,655
  • 2
  • 26
  • 39
  • yes.I understand these points.I plan to add delete,update,get methods in my service.so how would i resolve the transaction related problem. – jones j alapat Feb 07 '17 at 15:12
  • 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. Check those links http://www.journaldev.com/2603/spring-transaction-management-jdbc-example http://docs.spring.io/spring-framework/docs/4.2.x/spring-framework-reference/html/transaction.html – gkatzioura Feb 07 '17 at 15:16
  • 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 07 '17 at 15:23
  • I am using jpa. – jones j alapat Feb 07 '17 at 15:24
  • 1
    Then using @Transactional will do the work. However depending on your application you might have to consider locking. Check this article on locking with jpa https://vladmihalcea.com/2015/01/12/a-beginners-guide-to-java-persistence-locking/ – gkatzioura Feb 07 '17 at 15:30
1

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.

fabfas
  • 2,200
  • 1
  • 21
  • 21
0

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.

Mrinal N
  • 93
  • 1
  • 5
  • iDBService is shared – jones j alapat Feb 07 '17 at 14:37
  • 2
    iDBService is shared but it doesn't have any shared state or has any instance variables storing values that can be modified by other threads.Refer [http://stackoverflow.com/questions/11508405/are-spring-mvc-controllers-singletons] & [http://stackoverflow.com/questions/11485486/regarding-thread-safety-of-servlet] – Mrinal N Feb 07 '17 at 14:51