在实现MVC项目时,我通常添加服务层来执行实际工作。但实际上有时候1个Web请求应该用几个AppService方法来完成。然后,工作单元(UoW)的位置可能会影响编码处理。不管在C#EF/Java Spring中,服务层方法中都有事务注释,所以事务是基于每个服务的(即服务层上的UoW)。让我们的Java版本为例这里:在服务层而不是控制器上应用工作单元的好处
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
Public class UserAppService{
public UserDTO createUser() {
// Do sth to create a new user
userRepository.save(userBean);
// Convert userBean to userDTO
return userDTO;
}
public xxx DoSth() {
// Break the operation here
throw new Exception("Whatever");
// (never execute actually)
sthRepository.save(someBean);
}
}
然后在控制器:
Public class SomeController : Controller {
Public xxx DoSth(){
UserAppService Service = new UserAppService();
Service.CreateUser(); // DB committed
Service.DoSth(); //Exception thrown
}
}
通过这种结构,如果有扔在2号服务方法调用的任何异常,第一服务方法还承诺用户DB。如果我想要“全有或全无”处理,除非将这些服务方法调用包装为另一个包含单事务的包装服务调用,否则此结构不起作用。但这是额外的工作。
另一个版本是在Controller动作级别上使用事务(即Controller Action上的UoW)。我们以C#代码为例:
备注:此处的代码版本2中的AppService使用控制器中定义的DbContext(类似于事务),并且不会在内部进行任何提交。
Public class SomeController : Controller {
Public ActionResult DoSth(){
using (var DB = new DbContext()){
Var UserAppService = new UserAppService(DB);
var userEntity = userAppService.GetUser(userId);
UserAppService.DoSth(userEntity);
Var AnotherAppService = new AnotherAppService(DB);
AnotherAppService.DoSthElse(userEntity);
// Throw exception here
throw new Exception("Whatever");
DB.Save(); // commit
}
}
}
在这个例子中,将不会有局部提交到DB。
在服务层上应用UoW真的更好吗?
如果遵循UoW on Service模式,给定一个常见的情况:1个HTTP POST调用(即1个控制器动作)需要在带有数据库更改的2+服务方法上完成,如何防止“部分提交”而不会破坏UoW on Service模式? –
嗨,检查我的更新答案 – Javasharp