我应该如何创建一个线程安全的控制器?
根据最佳实践,控制器是单身。
考虑以下代码,其中通过自动装配的服务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);
}
}
答案 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框架解析。