Sqlsugar事务简单用法

1.配置UnitOfWork

// 定义一个名为 UnitOfWork 的公共类,并实现 IDisposable 接口
// IDisposable 接口用于释放非托管资源(在这里主要是数据库连接和事务)
public class UnitOfWork : IDisposable
{
    // 1. 属性定义
    // ILogger: 用于记录日志的接口,方便调试和追踪 UnitOfWork 的状态变化
    public ILogger Logger { get; set; }
    // ISqlSugarClient: SqlSugar ORM 的数据库客户端接口,用于执行数据库操作
    public ISqlSugarClient Db { get; internal set; }
    // ITenant: SqlSugar 的多租户接口,用于管理数据库事务
    public ITenant Tenant { get; internal set; }
    // IsTran: 布尔值,指示当前是否处于一个数据库事务中
    public bool IsTran { get; internal set; }
    // IsCommit: 布尔值,指示事务是否已经被提交
    public bool IsCommit { get; internal set; }
    // IsClose: 布尔值,指示数据库连接是否已经被关闭
    public bool IsClose { get; internal set; }

    // 2. Dispose 方法 (实现 IDisposable 接口)
    // 当 UnitOfWork 对象被释放时(例如,使用 using 语句块结束时),会自动调用此方法
    public void Dispose()
    {
        // a. 检查是否需要回滚事务
        // 如果当前处于事务中 (IsTran 为 true) 但事务尚未提交 (IsCommit 为 false)
        if (IsTran && !IsCommit)
        {
            // 记录调试日志,表明将要回滚事务
            Logger.LogDebug("UnitOfWork RollbackTran");
            // 调用 Tenant 的 RollbackTran 方法来回滚事务,撤销所有未提交的更改
            Tenant.RollbackTran();
        }

        // b. 检查是否需要关闭数据库连接
        // 如果数据库连接上仍有未完成的事务 或者 连接已经被标记为关闭
        if (Db.Ado.Transaction != null || IsClose)
            // 则不执行关闭操作,直接返回
            return;
        // 如果没有未完成的事务且连接未被标记关闭,则关闭数据库连接
        Db.Close();
    }

    // 3. Commit 方法
    // 用于显式提交事务
    public bool Commit()
    {
        // a. 检查并提交事务
        // 如果当前处于事务中 (IsTran 为 true) 但事务尚未提交 (IsCommit 为 false)
        if (IsTran && !IsCommit)
        {
            // 记录调试日志,表明将要提交事务
            Logger.LogDebug("UnitOfWork CommitTran");
            // 调用 Tenant 的 CommitTran 方法来提交事务,将所有更改持久化到数据库
            Tenant.CommitTran();
            // 将 IsCommit 标记为 true,表示事务已提交
            IsCommit = true;
        }

        // b. 检查并关闭数据库连接
        // 如果数据库连接上没有未完成的事务 且 连接尚未被标记为关闭
        if (Db.Ado.Transaction == null && !IsClose)
        {
            // 关闭数据库连接
            Db.Close();
            // 将 IsClose 标记为 true,表示连接已关闭
            IsClose = true;
        }

        // 返回事务是否已提交的状态
        return IsCommit;
    }
}

2.配置IUnitOfWorkManage

public interface IUnitOfWorkManage
    {
        SqlSugarScope GetDbClient();
        void BeginTran();
        void CommitTran();
        void RollbackTran();
        UnitOfWork CreateUnitOfWork();
    }

3.配置UnitOfWorkManage 实现IUnitOfWorkManage

// 定义一个公共类 UnitOfWorkManage,它实现了 IUnitOfWorkManage 接口
public class UnitOfWorkManage : IUnitOfWorkManage
{
    // 1. 私有只读字段
    // _logger: 用于记录日志,类型为 ILogger<UnitOfWorkManage>,表示这是专门给 UnitOfWorkManage 类使用的日志记录器
    private readonly ILogger<UnitOfWorkManage> _logger;
    // _sqlSugarClient: 注入的 SqlSugar 数据库客户端接口,用于执行数据库操作
    private readonly ISqlSugarClient _sqlSugarClient;
    // TranStack: 一个线程安全的栈,用于存储事务相关的标识符(例如事务ID)
    // 这可能用于更复杂的嵌套事务或事务跟踪场景
    public readonly ConcurrentStack<string> TranStack = new();

    // 2. 构造函数
    // 通过依赖注入获取所需的 ISqlSugarClient 和 ILogger 实例
    public UnitOfWorkManage(ISqlSugarClient sqlSugarClient, ILogger<UnitOfWorkManage> logger)
    {
        _sqlSugarClient = sqlSugarClient;
        _logger = logger;
    }

    /// <summary>
    /// 获取DB,保证唯一性
    /// </summary>
    /// <returns></returns>
    // 3. 获取数据库客户端实例的方法
    public SqlSugarScope GetDbClient()
    {
        // 将注入的 _sqlSugarClient 强制转换为 SqlSugarScope 类型并返回
        // 注释提示这很重要,因为后续可能需要使用 SqlSugarScope 特有的功能(如切换数据库)
        // 假设注入的 _sqlSugarClient 实际上就是 SqlSugarScope 的实例
        return _sqlSugarClient as SqlSugarScope;
    }

    // 4. 开始事务的方法
    public void BeginTran()
    {
        // 使用 lock 关键字确保在同一时间只有一个线程可以执行此代码块
        // 这是为了保证事务操作的线程安全
        lock (this)
        {
            // 调用 GetDbClient() 获取 SqlSugarScope 实例,然后调用其 BeginTran() 方法开始一个新事务
            GetDbClient().BeginTran();
        }
    }

    // 5. 提交事务的方法
    public void CommitTran()
    {
        // 同样使用 lock 确保线程安全
        lock (this)
        {
            // 调用 GetDbClient() 获取 SqlSugarScope 实例,然后调用其 CommitTran() 方法提交当前事务
            GetDbClient().CommitTran();
        }
    }

    // 6. 回滚事务的方法
    public void RollbackTran()
    {
        // 同样使用 lock 确保线程安全
        lock (this)
        {
            // 调用 GetDbClient() 获取 SqlSugarScope 实例,然后调用其 RollbackTran() 方法回滚当前事务
            GetDbClient().RollbackTran();
        }
    }

    // 7. 创建 UnitOfWork 实例的方法
    public UnitOfWork CreateUnitOfWork()
    {
        // a. 创建一个新的 UnitOfWork 对象
        UnitOfWork uow = new()
        {
            // 将注入的 logger 赋值给 UnitOfWork 的 Logger 属性
            Logger = _logger,
            // 将注入的数据库客户端赋值给 UnitOfWork 的 Db 属性
            Db = _sqlSugarClient,
            // 将数据库客户端强制转换为 ITenant 接口并赋值给 UnitOfWork 的 Tenant 属性
            // ITenant 接口通常包含事务管理方法 (BeginTran, CommitTran, RollbackTran)
            Tenant = (ITenant)_sqlSugarClient,
            // 将 IsTran 属性设置为 true,表示这个 UnitOfWork 关联的操作将在事务中进行
            IsTran = true
        };

        // b. 打开数据库连接
        uow.Db.Open();
        // c. 通过 Tenant 接口开始一个事务
        uow.Tenant.BeginTran();
        // d. 记录调试日志,表明一个新的 UnitOfWork 已经开始
        _logger.LogDebug("UnitOfWork Begin");
        // e. 返回创建好的 UnitOfWork 实例
        return uow;
    }
}

4.在AutofacModuleRegister注册IUnitOfWorkManage及其实现类的服务
image

// 注册sqlsugar事务服务
builder.RegisterType(typeof(UnitOfWorkManage)).As(typeof(IUnitOfWorkManage)).InstancePerDependency();

5.在IBaseRepository及其实现类BaseRepository添加方法
image

/// <summary>
/// 添加一个
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
Task<long> Add(TEntity entity);

image

 public async Task<long> Add(TEntity entity)
 {
     var insert = _dbBaset.Insertable(entity);
     return await insert.ExecuteReturnSnowflakeIdAsync();
 }

6.在IBaseService及其实现类BaseService添加方法
image

/// <summary>
/// 添加一个
/// </summary>
/// <param name="entity"></param>
/// <returns></returns>
Task<long> Add(TEntity entity);

image

public async Task<long> Add(TEntity entity)
{
    return await _baseRepository.Add(entity);
}

7.创建控制器TransactionController

[Route("api/[controller]/[action]")]
[ApiController]
public class TransactionController : ControllerBase
{
    private readonly IBaseService<Role, RoleVo> _roleService;
    private readonly IUnitOfWorkManage _unitOfWorkManage;

    public TransactionController(IBaseService<Role, RoleVo> roleService, IUnitOfWorkManage unitOfWorkManage)
    {
        _roleService = roleService;
        _unitOfWorkManage = unitOfWorkManage;
    }

    [HttpGet]
    public async Task<object> Get()
    {
        try
        {
            Console.WriteLine($"Begin Transaction");

            //_unitOfWorkManage.BeginTran();
            using var uow = _unitOfWorkManage.CreateUnitOfWork();
            var roles = await _roleService.Query();
            Console.WriteLine($"1 first time : the count of role is :{roles.Count}");


            Console.WriteLine($"insert a data into the table role now.");
            TimeSpan timeSpan = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
            var insertPassword = await _roleService.Add(new Role()
            {
                Id = timeSpan.TotalSeconds.ObjToLong(),
                IsDeleted = false,
                Name = "role name",
            });

            var roles2 = await _roleService.Query();
            Console.WriteLine($"2 second time : the count of role is :{roles2.Count}");


            int ex = 0;
            Console.WriteLine($"There's an exception!!");
            Console.WriteLine($" ");
            int throwEx = 1 / ex;

            uow.Commit();
            //_unitOfWorkManage.CommitTran();
        }
        catch (Exception)
        {
            //_unitOfWorkManage.RollbackTran();

            var roles3 = await _roleService.Query();
            Console.WriteLine($"3 third time : the count of role is :{roles3.Count}");
        }

        return "ok";
    }
}

image

posted @ 2025-08-19 11:29  一切为了尚媛小姐  阅读(53)  评论(0)    收藏  举报