【优化】仓储单个数据查询增加悲观锁等待模式。

【优化】通过优惠券编码领取优惠券增加事务处理。
This commit is contained in:
jianweie code
2023-05-08 00:05:27 +08:00
parent 8cb980063e
commit 514c63da60
7 changed files with 89 additions and 91 deletions

View File

@@ -246,8 +246,10 @@ namespace CoreCms.Net.IRepository
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue); Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait);
/// <summary> /// <summary>
/// 根据条件查询数据 /// 根据条件查询数据
@@ -271,23 +273,10 @@ namespace CoreCms.Net.IRepository
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait);
OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue);
/// <summary>
/// 根据条件查询数据(悲观锁等待模式)
/// </summary>
/// <param name="predicate">条件表达式树</param>
/// <param name="orderByPredicate">排序字段</param>
/// <param name="orderByType">排序顺序</param>
/// <param name="blUseTranLock">是否使用TranLock</param>
/// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param>
/// <returns></returns>
Task<T> QueryByClauseWithTranLockAsync(Expression<Func<T, bool>> predicate,
Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseTranLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue);
#endregion #endregion

View File

@@ -247,8 +247,10 @@ namespace CoreCms.Net.IServices
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue); Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait);
/// <summary> /// <summary>
/// 根据条件查询数据 /// 根据条件查询数据
@@ -272,24 +274,12 @@ namespace CoreCms.Net.IServices
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait);
OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue);
/// <summary>
/// 根据条件查询数据(悲观锁等待模式)
/// </summary>
/// <param name="predicate">条件表达式树</param>
/// <param name="orderByPredicate">排序字段</param>
/// <param name="orderByType">排序顺序</param>
/// <param name="blUseTranLock">是否使用TranLock</param>
/// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param>
/// <returns></returns>
Task<T> QueryByClauseWithTranLockAsync(Expression<Func<T, bool>> predicate,
Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseTranLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue);
#endregion #endregion
#region #region

View File

@@ -364,13 +364,12 @@ namespace CoreCms.Net.Repository
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue) public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait)
{ {
return await DbBaseClient.Queryable<T>() return await DbBaseClient.Queryable<T>().WithNoLockOrNot(blUseNoLock).WithUseTranLockOrNot(blUseTranLock, dbLockType).WithCacheIF(isDataCache, cacheTimes).FirstAsync(predicate);
.WithNoLockOrNot(blUseNoLock)
.WithCacheIF(isDataCache, cacheTimes)
.FirstAsync(predicate);
} }
/// <summary> /// <summary>
@@ -397,27 +396,14 @@ namespace CoreCms.Net.Repository
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue) public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait)
{ {
return await DbBaseClient.Queryable<T>().OrderBy(orderByPredicate, orderByType).WithNoLockOrNot(blUseNoLock).WithCacheIF(isDataCache, cacheTimes).FirstAsync(predicate); return await DbBaseClient.Queryable<T>().OrderBy(orderByPredicate, orderByType).WithNoLockOrNot(blUseNoLock).WithUseTranLockOrNot(blUseTranLock, dbLockType).WithCacheIF(isDataCache, cacheTimes).FirstAsync(predicate);
} }
/// <summary>
/// 根据条件查询数据(悲观锁等待模式)
/// </summary>
/// <param name="predicate">条件表达式树</param>
/// <param name="orderByPredicate">排序字段</param>
/// <param name="orderByType">排序顺序</param>
/// <param name="blUseTranLock">是否使用TranLock</param>
/// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param>
/// <returns></returns>
public async Task<T> QueryByClauseWithTranLockAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseTranLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue)
{
return await DbBaseClient.Queryable<T>().TranLock(DbLockType.Wait).OrderBy(orderByPredicate, orderByType).WithCacheIF(isDataCache, cacheTimes).FirstAsync(predicate);
}
#endregion #endregion
#region #region

View File

@@ -14,6 +14,23 @@ namespace CoreCms.Net.Repository
return query; return query;
} }
/// <summary>
/// 是否启用锁
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="query"></param>
/// <param name="lock"></param>
/// <param name="dbLockType"></param>
/// <returns></returns>
internal static ISugarQueryable<T> WithUseTranLockOrNot<T>(this ISugarQueryable<T> query, bool @lock = false, DbLockType dbLockType = DbLockType.Wait)
{
if (@lock)
{
query = query.TranLock(dbLockType);
}
return query;
}
} }
} }

View File

@@ -298,10 +298,12 @@ namespace CoreCms.Net.Services
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue) public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait)
{ {
return await BaseDal.QueryByClauseAsync(predicate, blUseNoLock, isDataCache, cacheTimes); return await BaseDal.QueryByClauseAsync(predicate, blUseNoLock, isDataCache, cacheTimes, blUseTranLock, dbLockType);
} }
/// <summary> /// <summary>
@@ -329,28 +331,15 @@ namespace CoreCms.Net.Services
/// <param name="blUseNoLock">是否使用WITH(NoLock)</param> /// <param name="blUseNoLock">是否使用WITH(NoLock)</param>
/// <param name="isDataCache">是否启用缓存</param> /// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param> /// <param name="cacheTimes">缓存时长(分钟)</param>
/// <param name="blUseTranLock">是否使用锁</param>
/// <param name="dbLockType">数据锁类型</param>
/// <returns></returns> /// <returns></returns>
public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue) public async Task<T> QueryByClauseAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseNoLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue, bool blUseTranLock = false, DbLockType dbLockType = DbLockType.Wait)
{ {
return await BaseDal.QueryByClauseAsync(predicate, orderByPredicate, orderByType, blUseNoLock, isDataCache, cacheTimes); return await BaseDal.QueryByClauseAsync(predicate, orderByPredicate, orderByType, blUseNoLock, isDataCache, cacheTimes, blUseTranLock, dbLockType);
} }
/// <summary>
/// 根据条件查询数据(悲观锁等待模式)
/// </summary>
/// <param name="predicate">条件表达式树</param>
/// <param name="orderByPredicate">排序字段</param>
/// <param name="orderByType">排序顺序</param>
/// <param name="blUseTranLock">是否使用TranLock</param>
/// <param name="isDataCache">是否启用缓存</param>
/// <param name="cacheTimes">缓存时长(分钟)</param>
/// <returns></returns>
public async Task<T> QueryByClauseWithTranLockAsync(Expression<Func<T, bool>> predicate, Expression<Func<T, object>> orderByPredicate, OrderByType orderByType, bool blUseTranLock = false, bool isDataCache = false, int cacheTimes = int.MaxValue)
{
return await BaseDal.QueryByClauseWithTranLockAsync(predicate, orderByPredicate, orderByType, blUseTranLock, isDataCache, cacheTimes);
}
#endregion #endregion
#region #region

View File

@@ -694,7 +694,7 @@ namespace CoreCms.Net.Services
where = where.And(p => p.isDel == false); //是否被删除 where = where.And(p => p.isDel == false); //是否被删除
var info = await _dal.QueryByClauseAsync(where); var info = await _dal.QueryByClauseAsync(where, false, true);
if (info != null) if (info != null)
{ {
jm.data = info; jm.data = info;

View File

@@ -14,6 +14,7 @@ using System.Threading.Tasks;
using CoreCms.Net.Auth.HttpContextUser; using CoreCms.Net.Auth.HttpContextUser;
using CoreCms.Net.Caching.AutoMate.RedisCache; using CoreCms.Net.Caching.AutoMate.RedisCache;
using CoreCms.Net.Configuration; using CoreCms.Net.Configuration;
using CoreCms.Net.IRepository.UnitOfWork;
using CoreCms.Net.IServices; using CoreCms.Net.IServices;
using CoreCms.Net.Model.Entities; using CoreCms.Net.Model.Entities;
using CoreCms.Net.Model.FromBody; using CoreCms.Net.Model.FromBody;
@@ -35,18 +36,19 @@ namespace CoreCms.Net.Web.WebApi.Controllers
private readonly ICoreCmsCouponServices _couponServices; private readonly ICoreCmsCouponServices _couponServices;
private readonly ICoreCmsPromotionServices _promotionServices; private readonly ICoreCmsPromotionServices _promotionServices;
private readonly IRedisOperationRepository _redisOperationRepository; private readonly IRedisOperationRepository _redisOperationRepository;
private readonly IUnitOfWork _unionOfWork;
/// <summary> /// <summary>
/// 构造函数 /// 构造函数
/// </summary> /// </summary>
public CouponController(IHttpContextUser user public CouponController(IHttpContextUser user
, ICoreCmsCouponServices couponServices, ICoreCmsPromotionServices promotionServices, IRedisOperationRepository redisOperationRepository) , ICoreCmsCouponServices couponServices, ICoreCmsPromotionServices promotionServices, IRedisOperationRepository redisOperationRepository, IUnitOfWork unionOfWork)
{ {
_user = user; _user = user;
_couponServices = couponServices; _couponServices = couponServices;
_promotionServices = promotionServices; _promotionServices = promotionServices;
_redisOperationRepository = redisOperationRepository; _redisOperationRepository = redisOperationRepository;
_unionOfWork = unionOfWork;
} }
//公共接口==================================================================================================== //公共接口====================================================================================================
@@ -225,26 +227,51 @@ namespace CoreCms.Net.Web.WebApi.Controllers
return jm; return jm;
} }
try
{
_unionOfWork.BeginTran();
//判断优惠券是否可以领取? //判断优惠券是否可以领取?
var promotionModel = await _promotionServices.ReceiveCoupon(coupon.promotionId); var promotionModel = await _promotionServices.ReceiveCoupon(coupon.promotionId);
if (promotionModel.status == false) if (promotionModel.status == false)
{ {
_unionOfWork.RollbackTran();
return promotionModel; return promotionModel;
} }
//判断用户是否已领取?
if (promotionModel.data is CoreCmsPromotion { maxNums: > 0 } info) var promotion = (CoreCmsPromotion)promotionModel.data;
if (promotion == null)
{
_unionOfWork.RollbackTran();
jm.msg = GlobalErrorCodeVars.Code15019;
return jm;
}
if (promotion.maxNums > 0)
{ {
//判断用户是否已领取?领取次数 //判断用户是否已领取?领取次数
var couponResult = await _couponServices.GetMyCoupon(_user.ID, coupon.promotionId, "all", 1, 9999); var couponResult = await _couponServices.GetMyCoupon(_user.ID, coupon.promotionId, "all", 1, 9999);
if (couponResult.status && couponResult.code > info.maxNums) if (couponResult.status && couponResult.code >= promotion.maxNums)
{ {
_unionOfWork.RollbackTran();
jm.msg = GlobalErrorCodeVars.Code15018; jm.msg = GlobalErrorCodeVars.Code15018;
return jm; return jm;
} }
} }
//
jm = await _couponServices.ReceiveCoupon(_user.ID, entity.key); jm = await _couponServices.ReceiveCoupon(_user.ID, entity.key);
_unionOfWork.CommitTran();
jm.otherData = promotionModel;
}
catch (Exception e)
{
_unionOfWork.RollbackTran();
jm.msg = GlobalErrorCodeVars.Code10000;
jm.data = e;
}
return jm; return jm;
} }
#endregion #endregion