如何在弹簧启动中使用线程安全控制器

时间:2017-02-07 13:55:38

标签: java spring multithreading rest spring-boot

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

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

考虑以下代码,其中通过自动装配的服务Object存储用户数据,这使我的代码有状态。 我如何使下面的代码线程安全。

db.users.aggregate([
    { "$match": { "UserName": "administrator" } },
    { 
        "$lookup": { 
            "from": 'companies', 
            "localField": 'CompanyID', 
            "foreignField": 'CompanyID', 
            "as": 'Company' 
        } 
    },
    {
        "$addFields": {
            "Company": {
                "$arrayElemAt": [
                    {
                        "$filter": {
                            "input": "$Company",
                            "as": "comp",
                            "cond": {
                                "$eq": [ "$$comp.CompanyName", "edt5" ]
                            }
                        }
                    }, 0
                ]
            }
        }
    }
])

这是我的服务实施。 我在服务中共享变量

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

}

3 个答案:

答案 0 :(得分:5)

默认情况下,您的控制器是单件,默认情况下您的服务也是单件。

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

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

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

如果您希望在正在进行写入时不更改数据库行,则必须考虑与行锁定相关的机制。 - gkatzioura 2月7日15:23

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

答案 1 :(得分:1)

控制器为singletons,因此以线程安全的方式实现。

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

<强> 实施例

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

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

答案 2 :(得分:0)

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