/// <summary> /// 更新事务分表状态 /// </summary> /// <param name="id">事务分表的主键</param> /// <param name="status">更新状态</param> public void UpdateTransPartsStatus(long?id, byte status) { using (DbContext dbContext = CreateDbContext()) { DistributedTransactionPart updateBefore = new DistributedTransactionPart { Id = id }; dbContext.Set <DistributedTransactionPart>().Attach(updateBefore); updateBefore.TransactionStatus = status; dbContext.SaveChanges(); } }
/// <summary> /// 分布式删除数据的逆操作,当事务失败时调用 /// </summary> /// <param name="entity">实体对象</param> public void DistributedInsertInverse(DistributedTransactionPart distributedTransactionPart) { using (BaseDbContext dbContext = CreateDbContext()) { TEntity entity = JsonConvert.DeserializeObject <TEntity>(CompressHelper.GZipDecompressString(distributedTransactionPart.InverseOper)); dbContext.Entry(entity).State = EntityState.Added; DistributedTransactionPart beforePart = new DistributedTransactionPart { Id = distributedTransactionPart.Id }; dbContext.Set <DistributedTransactionPart>().Attach(beforePart); beforePart.TransactionStatus = 2; dbContext.SaveChanges(); } }
/// <summary> /// 分布式插入数据的反操作。当事务失败时调用 /// </summary> /// <param name="distributedTransactionPart">分表对象</param> public abstract void DistributedDeleteInverse(DistributedTransactionPart distributedTransactionPart);
/// <summary> /// 分布式数据操作拦截,会对更新、删除、插入数据进行记录, /// 用于异步确定、异步回滚 /// </summary> /// <param name="invocation"></param> public void Intercept(IInvocation invocation) { string MethodName = invocation.Method.Name; long? transId = DistributedTransactionScan.TransactionIds.Value; if (transId != null && MethodNames.Contains(MethodName)) { dynamic target = invocation.InvocationTarget; using (TransactionScope tx = new TransactionScope()) { using (BaseDbContext baseDbContext = target.CreateDbContext()) { if (invocation.Arguments[0] is IEntity) { IEntity entity = (IEntity)invocation.Arguments[0]; if (entity != null) { DistributedTransactionPart distributedTransactionPart = new DistributedTransactionPart { Id = AllStatic.IdWorker.NextId(), DistributedTransactionMainId = (long)DistributedTransactionScan.TransactionIds.Value, TransTableName = entity.TableName(), TransPrimaryKeyVal = entity.Key, TransactionStatus = 0, CreateDate = DateTime.Now, }; if (MethodName == "Insert") { RecordDistribute(baseDbContext.Database.Connection.ConnectionString, entity.TableName()); distributedTransactionPart.InverseOperType = "d"; baseDbContext.Entry(distributedTransactionPart).State = EntityState.Added; } else if (MethodName == "Delete") { var beforeData = target.FindEntity(entity.Key); if (beforeData != null) { RecordDistribute(baseDbContext.Database.Connection.ConnectionString, entity.TableName()); distributedTransactionPart.InverseOper = CompressHelper.GZipCompressString(JsonConvert.SerializeObject(beforeData, AllStatic.TimeConverter)); distributedTransactionPart.InverseOperType = "i"; baseDbContext.Entry(distributedTransactionPart).State = EntityState.Added; } } else if (MethodName == "UpdateAll" || MethodName == "UpdateChange") { var beforeData = target.FindEntity(entity.Key); if (beforeData != null) { RecordDistribute(baseDbContext.Database.Connection.ConnectionString, entity.TableName()); distributedTransactionPart.InverseOper = CompressHelper.GZipCompressString(JsonConvert.SerializeObject(beforeData, AllStatic.TimeConverter)); distributedTransactionPart.InverseOperType = "u"; baseDbContext.Entry(distributedTransactionPart).State = EntityState.Added; } } } } else if (invocation.Arguments[0] is IList) { foreach (IEntity entity in (IList)invocation.Arguments[0]) { if (entity != null) { DistributedTransactionPart distributedTransactionPart = new DistributedTransactionPart { Id = AllStatic.IdWorker.NextId(), DistributedTransactionMainId = (long)DistributedTransactionScan.TransactionIds.Value, TransTableName = entity.TableName(), TransPrimaryKeyVal = entity.Key, TransactionStatus = 0, CreateDate = DateTime.Now, }; if (MethodName == "Insert") { RecordDistribute(baseDbContext.Database.Connection.ConnectionString, entity.TableName()); distributedTransactionPart.InverseOper = Convert.ToString(entity.Key); distributedTransactionPart.InverseOperType = "D"; baseDbContext.Entry(distributedTransactionPart).State = EntityState.Added; } else if (MethodName == "Delete") { var beforeData = target.FindEntity(entity.Key); if (beforeData != null) { RecordDistribute(baseDbContext.Database.Connection.ConnectionString, entity.TableName()); distributedTransactionPart.InverseOper = CompressHelper.GZipCompressString(JsonConvert.SerializeObject(beforeData, AllStatic.TimeConverter)); distributedTransactionPart.InverseOperType = "I"; baseDbContext.Entry(distributedTransactionPart).State = EntityState.Added; } } else if (MethodName == "UpdateAll" || MethodName == "UpdateChange") { var beforeData = target.FindEntity(entity.Key); if (beforeData != null) { RecordDistribute(baseDbContext.Database.Connection.ConnectionString, entity.TableName()); distributedTransactionPart.InverseOper = CompressHelper.GZipCompressString(JsonConvert.SerializeObject(beforeData, AllStatic.TimeConverter)); distributedTransactionPart.InverseOperType = "U"; baseDbContext.Entry(distributedTransactionPart).State = EntityState.Added; } } } } } baseDbContext.SaveChanges(); } invocation.Proceed(); tx.Complete(); } } else { invocation.Proceed(); } }
/// <summary> /// 检查分布式事务是否为成功提交,只有提交成功才能继续操作,提交失败则无法继续操作 /// </summary> /// <param name="primaryKeyVal">主键的值</param> /// <param name="transTableName">事务操作的表名称</param> public void CheckTransactionFinish(long?primaryKeyVal, string transTableName) { using (DbContext dbContext = CreateDbContext()) { var query = dbContext.Set <DistributedTransactionPart>().AsNoTracking().AsQueryable().Where(a => a.TransTableName == transTableName && a.TransPrimaryKeyVal == primaryKeyVal && a.TransactionStatus == 0); if (query.Any()) { DistributedTransactionPart distributedTransactionPart = query.FirstOrDefault(); var result = ReadOnlyMainDbContext.DistributedTransactionMains.AsNoTracking().AsQueryable().Where(a => a.Id == distributedTransactionPart.DistributedTransactionMainId && a.TransactionStatus == 1).Any(); List <DistributedTransactionMainDetail> mainDetails = ReadOnlyMainDbContext.DistributedTransactionMainDetails.AsNoTracking().AsQueryable().Where(a => a.DistributedTransactionMainId == distributedTransactionPart.DistributedTransactionMainId).ToList(); if (mainDetails.Count == 0) { InverseRepository <TEntity> inverseRepository = CurrentInverse(); if (result) { inverseRepository.UpdateTransPartsStatus(distributedTransactionPart.Id, 1); } else { if (distributedTransactionPart.InverseOperType == "D" || distributedTransactionPart.InverseOperType == "d") { inverseRepository.DistributedDeleteInverse(distributedTransactionPart); } else if (distributedTransactionPart.InverseOperType == "I" || distributedTransactionPart.InverseOperType == "i") { inverseRepository.DistributedInsertInverse(distributedTransactionPart); } else if (distributedTransactionPart.InverseOperType == "U" || distributedTransactionPart.InverseOperType == "u") { inverseRepository.DistributedUpdateInverse(distributedTransactionPart); } } } else { foreach (DistributedTransactionMainDetail mainDetail in mainDetails) { var inverseRepository = AllStatic.InverseRepositoryMap[mainDetail.TransactionDataSource][mainDetail.TransactionTable]; List <DistributedTransactionPart> distributedTransactionPartList = inverseRepository.FindTransPartsById(distributedTransactionPart.DistributedTransactionMainId); if (result) { inverseRepository.UpdateTransPartsStatus(distributedTransactionPartList.Select(a => a.Id).ToList(), 1); } else { //批量插入的逆操作 List <DistributedTransactionPart> dparts = new List <DistributedTransactionPart>(); //批量删除的逆操作 List <DistributedTransactionPart> iparts = new List <DistributedTransactionPart>(); //批量更新的逆操作 List <DistributedTransactionPart> uparts = new List <DistributedTransactionPart>(); foreach (DistributedTransactionPart part in distributedTransactionPartList) { if (part.InverseOperType == "D") { dparts.Add(part); } else if (part.InverseOperType == "d") { inverseRepository.DistributedDeleteInverse(part); } else if (part.InverseOperType == "I") { iparts.Add(part); } else if (part.InverseOperType == "i") { inverseRepository.DistributedInsertInverse(part); } else if (part.InverseOperType == "U") { uparts.Add(part); } else if (part.InverseOperType == "u") { inverseRepository.DistributedUpdateInverse(part); } inverseRepository.DistributedDeleteInverse(dparts); inverseRepository.DistributedInsertInverse(iparts); inverseRepository.DistributedUpdateInverse(uparts); } } } } } } }