使用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 } }
标签:
.Net
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
· 零经验选手,Compose 一天开发一款小游戏!