C# TransactionScope「建议收藏」

C# TransactionScope「建议收藏」TransactionScopeTransactionScope事务处理经常用到,老是用了又忘,做点记录。TransactionScope的定义跟使用介绍。TransactionScopeOptionTransactionScopeOption枚举型用来决定一个TransactionScope是用已有的事务,还是定义TransactionScope的新做一个事务,还是完全不用事务。默认是Required,Required表示如果已有事务,就加入该事务,否则新建一个事务。TransactionOp

大家好,又见面了,我是你们的朋友全栈君。

TransactionScope

TransactionScope事务处理经常用到,老是用了又忘,做点记录。
TransactionScope的定义使用介绍


TransactionScopeOption

TransactionScopeOption枚举型用来决定一个TransactionScope是用已有的事务,还是定义TransactionScope的新做一个事务,还是完全不用事务。默认是Required,Required表示如果已有事务,就加入该事务,否则新建一个事务。

TransactionOptions

TransactionOptions 结构体用来设置TransactionScope所用到事务的隔离级别超时时间
隔离级别参考这篇博文。(乐观锁


实践

做两张表

USE [Learning]
GO
CREATE TABLE [dbo].[Foo](
	[Id] [bigint] IDENTITY(1,1) NOT NULL,
	[Value] [nvarchar](50) NULL,
 CONSTRAINT [PK_Foo] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[Bar](
	[Id] [bigint] IDENTITY(1,1) NOT NULL,
	[Value] [nvarchar](50) NULL,
 CONSTRAINT [PK_Bar] PRIMARY KEY CLUSTERED 
(
	[Id] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
) ON [PRIMARY]
GO

准备测试类
用了EntityFrameWorkCore的库,两个DbContext连同一个数据库。(本地测试的时候,连两个不同的数据库报错:EntityFrameWorkCore不支持分布式事务。。)

using Microsoft.EntityFrameworkCore;
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
using System.Transactions;

namespace LocalAppTest
{ 
   
    public class FooDbContext : DbContext
    { 
   
        public FooDbContext(DbContextOptions<FooDbContext> options) : base(options) { 
    }

        public DbSet<Foo> Foo { 
    get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        { 
   

        }
    }

    [Table("Foo")]
    public class Foo
    { 
   
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { 
    get; set; }

        [StringLength(50)]
        public string Value { 
    get; set; }
            
    }


    public class BarDbContext : DbContext
    { 
   
        public BarDbContext(DbContextOptions<BarDbContext> options) : base(options) { 
    }

        public DbSet<Bar> Bar { 
    get; set; }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        { 
   

        }
    }

    [Table("Bar")]
    public class Bar
    { 
   
        [Key]
        [DatabaseGenerated(DatabaseGeneratedOption.Identity)]
        public long Id { 
    get; set; }

        [StringLength(50)]
        public string Value { 
    get; set; }

    }
    
    public class TransactionScopeTest
    { 
   
        public DbContextOptions<FooDbContext> FooOptions;
        public DbContextOptions<BarDbContext> BarOptions;

        public TransactionScopeTest()
        { 
   
            FooOptions = (new DbContextOptionsBuilder<FooDbContext>()).UseSqlServer("server=localhost;database=Learning;integrated security=true;").Options;
            BarOptions = (new DbContextOptionsBuilder<BarDbContext>()).UseSqlServer("server=localhost;database=Learning;integrated security=true;").Options;
        }

        public void Test()
        { 
   
            using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { 
    IsolationLevel = IsolationLevel.ReadCommitted }))
            { 
   
                using (var fooContext = new FooDbContext(FooOptions))
                { 
   
                    var foo = new Foo { 
    Value = "Hi" };
                    fooContext.Add(foo);
                    fooContext.SaveChanges();

                    using (var barContext = new BarDbContext(BarOptions))
                    { 
   
                        var bar = new Bar { 
    Value = "Loser" };
                        barContext.Add(bar);
                        barContext.SaveChanges();
                    }

                    scope.Dispose();
                }
            }
        }

    }
}

调用测试代码

new TransactionScopeTest().Test();

以上,

  • 用了常用的 ReadCommitted 隔离级别。
  • 上述代码走到第一个 SaveChanges 方法的时候,Foo 表锁住,其他查询语句会等待;走到第二个 SaveChanges 方法的时候,Bar 表锁住,其他查询语句会等待。
  • Dispose 之后,表数据未更新,Foo 跟 Bar 两张表的其他查询语句正常执行。

再做个测试

using Microsoft.EntityFrameworkCore;
using System.Transactions;
using System.Linq;
using System;
using System.Threading.Tasks;
using System.Collections.Generic;

namespace LocalAppTest
{ 
   
    public class TransactionScopeTest
    { 
   
        public DbContextOptions<FooDbContext> FooOptions;
        public DbContextOptions<BarDbContext> BarOptions;

        public TransactionScopeTest()
        { 
   
            FooOptions = (new DbContextOptionsBuilder<FooDbContext>()).UseSqlServer("server=localhost;database=Learning;integrated security=true;").Options;
            BarOptions = (new DbContextOptionsBuilder<BarDbContext>()).UseSqlServer("server=localhost;database=Learning;integrated security=true;").Options;
        }       
        public void Test2()
        { 
   
            var tasks = new List<Task>();

            int i = 0;
            while (i < 100)
            { 
   
                tasks.Add(Task.Run(() =>
                { 
   
                    using (var scope = new TransactionScope(TransactionScopeOption.Required, new TransactionOptions { 
    IsolationLevel = IsolationLevel.ReadCommitted }))
                    { 
   
                        using (var fooContext = new FooDbContext(FooOptions))
                        { 
   
                            var records = fooContext.Foo.ToList();

                            var foo = new Foo { 
    Value = Guid.NewGuid().ToString() };
                            fooContext.Add(foo);
                            fooContext.SaveChanges();

                            scope.Complete();
                        }
                    }
                }));

                i++;
            }

            Task.WaitAll(tasks.ToArray());
        }

    }
}

调用测试代码

new TransactionScopeTest().Test2();

Test2方法里面启用了100个线程,每个线程做两件事情:1.查询Foo表的数据;2.新增一条数据。执行下来,ReadCommitted 隔离级别下,没有发生死锁的现象。
把上述隔离级别改成 Serializable 后,再次执行,当某个线程占用资源的时候,其他线程会抛出异常,不再执行。

先记录到这。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/161946.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • keil4 进行 S3C2440裸机开发

    keil4 进行 S3C2440裸机开发用Keil-MDK开发TQ2440裸机程序入门教程——LED流水灯实现觉得此编文章很详实,故转载之,来自http://www.amobbs.com/thread-5281512-1-1.html开发板也差不多买了半年了,以前照着教程用的是软件是ADS,在win7下老是崩溃,后来才知道ADS早就不提供支持了,ADS的公司怎样怎样了…(此处省略300..)然后我就捣鼓

    2022年5月4日
    83
  • accessors 作用_EasyExcel与@Accessors(chain = true)不兼容分析

    accessors 作用_EasyExcel与@Accessors(chain = true)不兼容分析EasyExcelEasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel.github地址:https://github.com/alibaba/easyexcelAccessors@Accessors注解用来配置lombok如何产生和显示getters和setters的方法。public@interfaceAcce…

    2025年6月16日
    2
  • AIRFLow_overflow百度百科

    AIRFLow_overflow百度百科1、什么是AirflowAirflow是一个Airbnb的Workflow开源项目,使用Python编写实现的任务管理、调度、监控工作流平台。Airflow是基于DAG(有向无环图)的任务管理系统,可以简单理解为是高级版的crontab,但是它解决了crontab无法解决的任务依赖问题。与crontab相比Airflow可以方便查看任务的执行状况(执行是否成功、执行时间、执行依赖等),可追踪任务历史执行情况,任务执行失败时可以收到邮件通知,查看错误日志。2、Airflow与同类产品的

    2025年8月6日
    3
  • GB50174-2008电子信息系统机房设计规范_根据电子信息系统机房设计规范

    GB50174-2008电子信息系统机房设计规范_根据电子信息系统机房设计规范GB50174-2008《电子信息系统机房设计规范》 转载于:https://blog.51cto.com/56421/475664

    2022年9月27日
    2
  • 5g端到端网络切片技术_5G网络切片的特征

    5g端到端网络切片技术_5G网络切片的特征1、网络切片的一些概念网络切片(Slice):基于客户化需求,可以被设计、部署、维护的逻辑网络,旨在满足特定的客户、业务、商业场景的业务特点及商业模式。网络切片实例(E2ESliceInstance-ESI):网络切片实例(Instance)是一个临时逻辑网络,跨多个技术域,包含:(1)组网络:”功能”(Function)即虚拟网元(终端、接入网、回传网、核心网、业务网络)及网管系统对应的资源;(2)存储、运算;(3)连接关系。2、网络切片原因:未来业务需求差异

    2022年9月27日
    2
  • SpringMVC面试题及答案

    SpringMVC面试题及答案SpringMVC面试题及答案1、简单介绍下你对springMVC的理解?SpringMVC是一个实现了MVC设计模式的轻量级Web框架,其核心是Model,View,Controller,把复杂的web应用分成逻辑清晰的几部分,简化开发。2、SpringMVC执行流程是什么?1、用户发送请求至前端控制器DispatcherServlet。2、前端控制器收到请求调用处理器映射器HandlerMapping。3、处理器映射器找到具体的处理器,生成处理器对象及处理器拦截器并返回给前端控制器。4

    2022年6月19日
    30

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号