数据库事务Transaction在EF Core中的打开方式

最近项目中遇到一个困惑,在一个事务中,如果A方法执行成功,则执行B方法,并提交事务,如果A方法执行失败,此时,需要回滚事务吗?

为了弄清楚这个问题,我们通过三个C#示例方法进行分析,它们的功能都是删除Category表和Product表中CategoryId为1的记录,但是使用了不同的方式处理事务。代码如下:

using DbContext dbContext = new ProductContext();


void Method1()//方法一
{
    using var transaction = dbContext.Database.BeginTransaction();
    {
        int row = dbContext.Database.ExecuteSql($"DELETE FROM [Category] WHERE [CategoryId]={1}");
        if (row > 0)
        {
            dbContext.Database.ExecuteSql($"DELETE FROM [Product] WHERE [CategoryId]={1}");
            transaction.Commit();
        }
    }
}


void Method2()//方法二
{
    using var transaction = dbContext.Database.BeginTransaction();
    {
        int row = dbContext.Database.ExecuteSql($"DELETE FROM [Category] WHERE [CategoryId]={1}");
        if (row > 0)
        {
            dbContext.Database.ExecuteSql($"DELETE FROM [Product] WHERE [CategoryId]={1}");
        }
        transaction.Commit();
    }
}


void Method3()//方法三
{
    using var transaction = dbContext.Database.BeginTransaction();
    {
        int row = dbContext.Database.ExecuteSql($"DELETE FROM [Category] WHERE [CategoryId]={1}");
        if (row > 0)
        {
            dbContext.Database.ExecuteSql($"DELETE FROM [Product] WHERE [CategoryId]={1}");
            transaction.Commit();
        }
        else
        {
            transaction.Rollback();
        }
    }
}

这里我们需要注意一个重要的知识点:

在EF Core中,使用using var transaction = dbContext.Database.BeginTransaction()这样的写法,在using结束时,如果没有手动提交事务,它会自动回滚事务,而不会自动提交事务。因为using语句会在结束时调用transaction对象的Dispose方法,而Dispose方法会检查事务是否已经提交或回滚,如果没有,则会调用Rollback方法回滚。

一、过程分析

接下来,我们来分别分析一下这三个方法的执行过程。点个关注吧👇

1、方法一的执行过程如下:

  • 调用dbContext.Database.BeginTransaction()方法,开始一个数据库事务,返回一个DbTransaction对象,赋值给transaction变量。

  • 调用dbContext.Database.ExecuteSql()方法,删除Category表中CategoryId为1的记录,返回受影响的行数,赋值给row变量。

  • 如果row大于0,则继续删除Product表中CategoryId为1的记录,然后调用transaction.Commit()方法,提交事务,释放transaction对象资源。

  • 否则,通过 using 块结束时自动调用 transaction.Dispose()方法,隐式地回滚事务,释放transaction对象资源。

2、方法二的执行过程如下:

  • 调用dbContext.Database.BeginTransaction()方法,开始一个数据库事务,返回一个DbTransaction对象,赋值给transaction变量。

  • 调用dbContext.Database.ExecuteSql()方法,删除Category表中CategoryId为1的记录,返回受影响的行数,赋值给row变量。

  • 如果row大于0,则继续删除Product表中CategoryId为1的记录,然后调用transaction.Commit()方法,提交事务,释放transaction对象资源。

  • 否则,调用transaction.Commit()方法,提交一个空事务,释放transaction对象资源。

3、方法三的执行过程如下:

  • 调用dbContext.Database.BeginTransaction()方法,开始一个数据库事务,返回一个DbTransaction对象,赋值给transaction变量。

  • 调用dbContext.Database.ExecuteSql()方法,删除Category表中CategoryId为1的记录,返回受影响的行数,赋值给row变量。

  • 如果row大于0,则继续删除Product表中CategoryId为1的记录,然后调用transaction.Commit()方法,提交事务,释放transaction对象资源。

  • 否则,调用transaction.Rollback()方法,回滚事务,释放transaction对象资源。

二、分析结论

通过对三个方法的分析,我们可以得出以下结论:

  • 方法一和方法三的执行结果完全相同,唯一的区别是方法三能及时地释放数据库资源,而方法一则依赖using块结束时来隐式地回滚事务。这样可能会导致数据库的资源被占用较长时间,影响其他操作的执行和性能。

  • 方法二与其它两个方法的主要不同点在于当row小于等于0的时候,方法二提交了一个空事务,这样会浪费数据库的资源和时间,影响性能和并发能力。

  • 日常的开发中推荐使用方法三来处理事务,因为它既能在成功时提交事务,也能在失败时回滚事务,并能及时释放掉数据库资源。

当然,这里讨论的时间长短是相较三个方法而言,使用 using 自动释放资源并无不妥。无论如何,我们在使用事务时要注意正确地提交或回滚事务,并及时释放资源。

参考资料:

https://learn.microsoft.com/en-us/ef/core/saving/transactions

👇感谢阅读,点赞+分享+收藏+关注👇11c39146061f779bed1ca990aa3a7012.png

文章出自猿惑豁微信公众号

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值