【问题标题】:How to have thread safe controller in spring boot如何在 Spring Boot 中使用线程安全控制器
【发布时间】:2017-06-24 19:18:24
【问题描述】:

我应该如何创建一个线程安全的控制器?

根据最佳实践,控制器是单例的。

考虑下面的代码,我通过自动连接的服务对象存储用户数据,这使我的代码有状态。 我如何使下面的代码线程安全。

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

这是我的服务实现。 我的服务中有共享变量

public class IDbServiceImpl<T> implements IDBService<T>{

@Autowired
GenericRepository<T, Serializable> genericRepository;

@Override
public T create(T object) {
    return  genericRepository.save(object);
}

}

【问题讨论】:

  • 代码是线程安全的......假设服务内部没有共享状态......
  • 我不会认为这个控制器是有状态的,除非你的 IDbService 是有状态的。
  • 如果我的服务是有状态的,那会是个问题
  • 在有状态 IDbService 的情况下遵循的最佳方法是?

标签: java spring multithreading rest spring-boot


【解决方案1】:

你的控制器默认是单例的,你的服务默认也是单例的。

因此,为了使它们成为线程安全的,您必须确保发生在服务内部的操作必须是线程安全的,以防更改服务内部对象的状态,即。一个列表。

如果使用 rdbms,则会遇到与事务相关的问题。

如果您使用 spring 和 Jpa,只要您使用 @Transactional,事务管理器就会处理您的更新。如果是普通的 jdbc 方法,那么您可以使用纯 jdbc 并自己进行事务处理,也可以使用带有 transaction manager 的 spring-jdbc。

如果您希望在写入过程中不更改数据库行,那么您必须考虑与行锁定相关的机制。 – gkatzioura 2 月 7 日 15:23

如果 JPA 使用 @Transactional 将完成这项工作。但是,根据您的应用程序,您可能必须考虑锁定。查看this关于使用 jpa 锁定的文章。

【讨论】:

  • 是的。我理解这些要点。我计划在我的服务中添加删除、更新、获取方法。那么我将如何解决与事务相关的问题。
  • 如果您使用 spring 和 Jpa,只要您使用 @Transactional,事务管理器就会处理您的更新。如果是普通的 jdbc 方法,那么您可以使用纯 jdbc 并自己进行事务处理,也可以使用带有事务管理器的 spring-jdbc。检查这些链接journaldev.com/2603/spring-transaction-management-jdbc-exampledocs.spring.io/spring-framework/docs/4.2.x/…
  • 如果您希望在写入过程中不更改数据库行,那么您必须考虑行锁定相关机制。
  • 我正在使用 jpa。
  • 然后使用@Transactional 就可以了。但是,根据您的应用程序,您可能必须考虑锁定。查看这篇关于使用 jpa 锁定的文章 vladmihalcea.com/2015/01/12/…
【解决方案2】:

控制器是singletons,因此它们应该以线程安全的方式实现。

以控制器无状态的方式设计您的应用程序。在@Repository 层中添加事务支持。

示例:

public class GenericRepository<T, Serializable> {
 @Transactional
 public void save(T object) {
  // save user
 }
}

您可以使用 Spring 声明式事务管理机制。 @Transactional 注解本身定义了单个数据库事务的范围。

【讨论】:

  • 控制器应该是应用范围的。
  • @fabfas 通常事务注释不应该应用在 Repository 层,而应该在服务层使用。好吧,这也取决于您的用例。
【解决方案3】:

您的控制器看起来是线程安全的。因为没有存储状态的实例变量。每个请求的用户对象都不同,并由 MVC 框架解析。

【讨论】:

猜你喜欢
  • 2017-06-08
  • 2016-09-18
  • 1970-01-01
  • 2012-12-18
  • 1970-01-01
  • 1970-01-01
  • 2016-06-03
  • 2022-07-29
  • 2012-08-20
相关资源
最近更新 更多