【发布时间】:2017-08-08 03:56:14
【问题描述】:
在实现 MVC 项目时,我通常会添加服务层来执行实际工作。但实际上有时 1 个 Web 请求应该使用几个 AppService 方法来完成。那么工作单元(UoW)的位置可能会影响编码处理。
无论在 C# EF/Java Spring 中,Service Layer 方法中都有 Transaction 注解,所以事务是基于 Per-Service 的(即 Service 层上的 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
}
}
使用这种结构,如果在第二个服务方法调用中抛出任何异常,第一个服务方法仍然会将用户提交到数据库。如果我想要“全有或全无”处理,除非我将这些服务方法调用包装到具有单个事务的另一个包装服务调用中,否则此结构将不起作用。但这是一项额外的工作。
另一个版本是在控制器操作级别上使用事务(即控制器操作上的 UoW)。我们以 C# 代码为例:
备注:此处代码版本 2 中的 AppService 使用控制器中定义的 DbContext (sth like transaction),内部不做任何提交。
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
}
}
}
在此示例中,不会对数据库进行部分提交。
在服务层应用 UoW 真的更好吗?
【问题讨论】:
标签: entity-framework model-view-controller transactions unit-of-work