使用PetaPoco结合注入实现业务级事务
PetaPoco是一个轻量级ORM,我的MVC项目中使用它结合Repository模式,依靠Unity的生命周期管理对象,保证请求/线程级别的数据上下文单例,并使用锁和计数实现业务级事务。下文代码依个人理解实现,谬误请不吝指正。
例行IUnitOfWork:
public interface IUnitOfWork { void Begin(); void Commit(); void Rollback(); }
仓库上下文核心:
1 public class PetaPocoUnitOfWork : IUnitOfWork 2 { 3 private const String _dbName = "Northwind"; 4 private Boolean _requireAbort = false; 5 private Int32 _transactionDepth = 0; 6 private Object _transactionLock = new Object(); 7 8 public Database DBContext { get; protected set; } 9 10 public Guid Id { get; private set; } 11 12 public PetaPocoUnitOfWork() 13 { 14 Id = Guid.NewGuid(); 15 DBContext = new Database(_dbName); 16 } 17 18 public void Begin() 19 { 20 lock (_transactionLock) 21 { 22 if (_transactionDepth == 0) 23 { 24 DBContext.BeginTransaction(); 25 } 26 _transactionDepth++; 27 } 28 29 } 30 31 public void Commit() 32 { 33 lock (_transactionLock) 34 { 35 _transactionDepth--; 36 if (_transactionDepth == 0) 37 { 38 try 39 { 40 DBContext.CompleteTransaction(); 41 } 42 catch 43 { 44 _transactionDepth++; 45 _requireAbort = true; 46 throw; 47 } 48 } 49 } 50 } 51 52 public void Rollback() 53 { 54 lock (_transactionLock) 55 { 56 _transactionDepth--; 57 if (_transactionDepth == 0) 58 { 59 DBContext.AbortTransaction(); 60 _requireAbort = false; 61 } 62 } 63 } 64 65 public void Dispose() 66 { 67 if (_requireAbort) 68 { 69 DBContext.AbortTransaction(); 70 } 71 DBContext.Dispose(); 72 } 73 }
在应用层对Unity注入的IUnitOfWork调用Begin()即开启事务,对于嵌套事务变量_transactionDepth++记录事务深度,Commit()与Rollback()时_transactionDepth--,保证业务中事务只开启与提交一次。如有应用层ITradeService及实现:
1 public abstract class ApplicationService { 2 public IUnitOfWork Context { get; private set; } 3 4 public ApplicationService(IUnitOfWork context) { 5 Context = context; 6 } 7 } 8 9 public interface ITradeService { 10 void SubmitOrder(Order model); 11 } 12 13 public class TradeService : ApplicationService, ITradeService { 14 private readonly IOrderRepository _orderRepository; 15 private readonly IOrderDetailRepository _orderDetailRepository; 16 17 public TradeService( 18 IUnitOfWork context, 19 IOrderRepository orderRepository, 20 IOrderDetailRepository orderDetailRepository) 21 : base(context) { 22 _orderRepository = orderRepository; 23 _orderDetailRepository = orderDetailRepository; 24 } 25 26 void SubmitOrder(OrderDTO model){ 27 //do something, like null reference check etc.. 28 29 Order order = //... some logic 30 OrderDetail orderDetail = //as above 31 32 try { 33 Context.Begin(); 34 35 _orderRepository.Update(order); 36 _orderDetailRepository.Update(orderDetail); 37 //could be more complex 38 39 Context.Commit(); 40 } 41 catch { 42 Context.Rollback(); 43 throw; 44 } 45 } 46 }
当顾客提交订单时,Context.Begin()开启一个事务锁,由于Unity的生命周期管理,当前线程内的数据上下文实例是同一个对象,故能够保证事务。当事务发生嵌套时,事务深度的解决方法发生作用,比如以可测试性的提高截取部分代码示例:
[TestClass] public class AccountServiceTest { [TestMethod] public void TradeServiceTest_SubmitOrder() { IUnitOfWork context = ... //some initialize logic OrderDTO model = ... //as above TradeService service = //as above context.Begin(); service.SubmitOrder(); context.Rollback(); ///... etc } }