设为首页 加入收藏

TOP

仅此一文让你明白事务隔离级别、脏读、不可重复读、幻读(一)
2019-09-17 18:02:39 】 浏览:64
Tags:一文 明白 事务 隔离 级别 脏读 不可 复读 幻读

网络上关于这方面的博文有些偏理论,有些通篇代码,都不能深入浅出。本文用图文并茂的方式,配上行云流水般的代码,非要摆清楚这个问题。相关代码已提交至码云(点击这里下载)。

事务是现代关系型数据库的核心之一。在多个事务并发操作数据库(多线程、网络并发等)的时候,如果没有有效的避免机制,就会出现以下几种问题:

第一类丢失更新(Lost Update)

在完全未隔离事务的情况下,两个事务更新同一条数据资源,某一事务完成,另一事务异常终止,回滚造成第一个完成的更新也同时丢失 。这个问题现代关系型数据库已经不会发生,就不在这里占用篇幅,有兴趣的可以自行百度。

脏读(Dirty Read)

A事务执行过程中,B事务读取了A事务的修改。但是由于某些原因,A事务可能没有完成提交,发生RollBack了操作,则B事务所读取的数据就会是不正确的。这个未提交数据就是脏读(Dirty Read)。脏读产生的流程如下:

微信截图_20190223000611

可以用EF Core模拟此过程:

    class TestReadUncommitted :TestBase
    {
        private AutoResetEvent _autoResetEvent;

        [Test]
        public void ReadUncommitted()
        {
            using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
            {
                var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                Console.WriteLine($"初始用户状态:【{user.Status}】");
            }

            _autoResetEvent = new AutoResetEvent(false);
            ThreadPool.QueueUserWorkItem(data =>{
                Write();  //启动线程写
            });
            ThreadPool.QueueUserWorkItem(data =>{
                Read();  //启动线程读
            });

            Thread.Sleep(5000);

            using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
            {
                var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                Console.WriteLine($"最终用户状态:【{user.Status}】");
            }
        }

        private void Read()
        {
            _autoResetEvent.WaitOne();

            var options = new TransactionOptions { IsolationLevel = IsolationLevel.ReadUncommitted };
            using (var scope = new TransactionScope(TransactionScopeOption.Required, options))
            {
                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                    Console.WriteLine($"事务B:脏读到的用户状态:【{user.Status}】--{DateTime.Now.ToString("HH:mm:ss fff")}");
                    //如果这时执行下面的判断
                    if (user.Status == 1)
                    {
                        Console.WriteLine("事务B:非正常数据,会产生意想不到的BUG");
                    }
                }
            }
        }
        private void Write()
        {
            using (var scope = new TransactionScope(TransactionScopeOption.Required,
                new TransactionOptions {IsolationLevel = IsolationLevel.ReadCommitted}))
            {
                Console.WriteLine($"事务A:修改--{DateTime.Now.ToString("HH:mm:ss fff")}");
                using (var context = _autofacServiceProvider.GetService<OpenAuthDBContext>())
                {
                    var user = context.Users.SingleOrDefault(u => u.Account == "admin");
                    user.Status = 1-user.Status;  //模拟修改
                    context.SaveChanges();
                }

                _autoResetEvent.Set();  //模拟多线程切换,这时切换到Read线程,复现脏读

                Thread.Sleep(2000);  //模拟长事务
                Console.WriteLine($"事务A:改完,但没提交--{DateTime.Now.ToString("HH:mm:ss fff")}");
            }
        }
    }
脏读示例

对应的执行结果:

捕获

不可重复读(Nonrepeatable Read)

B事务读取了两次数据,在这两次的读取过程中A事务修改了数据,B事务的这两次读取出来的数据不一样。B事务这种读取的结果,即为不可重复读(Nonrepeatable Read)。不可重复读的产生的流程如下:

微信截图_20190223004632

模拟代码如下:

public class TestReadCommitted : TestBase
    {
        private AutoResetEvent _toWriteEvent = new AutoResetEvent(false);
        private AutoResetEvent _toReadEvent = new AutoResetEvent(false);

        [Test]
        public void ReadCommitted()
        {
            ThreadPool.QueueUserWorkItem(data => {
                Read();  //启动线程读
            });
            ThreadPool.QueueUserWorkItem(data => {
                Write();  //启动线程写
            });

            Thread.Sleep(5000);

            using (var context = _autofacServiceProvider.GetService<
首页 上一页 1 2 3 4 5 下一页 尾页 1/5/5
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇ASP.NET Core 基于JWT的认证(一) 下一篇.net 多线程 Thread ThreadPool T..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目