观锁和乐观锁——《POJOs in Action》

1        事务隔离

事务隔离是数据库提供的功能。

SQL Server通过SET TRANSACTION ISOLATION LEVEL语句设置事务隔离级别:

SET TRANSACTION ISOLATION LEVEL

    { READ UNCOMMITTED

    | READ COMMITTED

    | REPEATABLE READ

    | SNAPSHOT

    | SERIALIZABLE

    }

[ ; ]

Read Committed是SQL Server的预设隔离等级。

1.1         READ UNCOMMITTED

Read UnCommitted事务可以读取事务已修改,但未提交的的记录。

Read UnCommitted事务会产生脏读(Dirty Read)。

Read UnCommitted事务与select语句加nolock的效果一样,它是所有隔离级别中限制最少的。

1.2         READ COMMITTED

Read Committed事务不能读取事务已修改,但未提交的记录。

Read Committed是SQL Server的预设隔离等级。

1.3         REPEATABLE READ

Repeatable Read事务不能读取交易已修改,但未提交的记录,并且在事务完成之前,任何其它事务都不能修改目前事务已读取的记录。

其它事务仍可以插入新记录,但必须符合当前事务的搜索条件——这意味着当前事务重新查询记录时,会产生幻读(Phantom Read)。

1.4         SNAPSHOT

Snapshot事务中任何语句所读取的记录,都是事务启动时的数据。

这相当于事务启动时,数据库为事务生成了一份专用“快照”。

在当前事务中看到不其它事务在当前事务启动之后所进行的数据修改。

Snapshot事务不会读取记录时要求锁定,读取记录的Snapshot事务不会锁住其它事务写入记录,写入记录的事务也不会锁住Snapshot事务读取数据。

1.5         SERIALIZABLE

Serializable事务会产生以下效果:

1.语句无法读取其它事务已修改但未提交的记录。

2.在当前事务完成之前,其它事务不能修改目前事务已读取的记录。

3.在当前事务完成之前,其它事务所插入的新记录,其索引键值不能在当前事务的任何语句所读取的索引键范围中。

Serializable事务与select语句加holdlock的效果一样。

2        READ COMMITTED 和 REPEATABLE READ

Read Committed 和 Repeatable Read 是最常用的两种事务。

Read Committed 是 SQL Server的默认级别;而 Repeatable Read 比Read Committed 更能保证数据一致性。

2.1         特点

Read Committed会阻塞其它事务中的update,但不会阻塞select。

Repeatable Read不但会阻塞其它事务中的update,还会阻塞select。

 

Read Committed 和 Repeatable Read 的相同点是:都会阻塞其它事务的update语句。

Read Committed 和 Repeatable Read 的不同点是:Read Committed 不会阻塞其它事务的select语句,但Repeatable Read阻塞。

 

注意,Read Committed 和 Repeatable Read 都是行级锁,它们只会锁住与自己相关的记录。当事务提交之后,阻塞的语句就会继续执行。

2.2         理解

2.2.1     READ COMMITTED

Read Committed 事务的含义是我select出来的记录,别人只能看,不能改(只阻塞别的事务的update)。

 

Read Committed 的缺点是:无法防止读取不一致和修改丢失。

读取不一致是因为Read Committed 不锁住读取的记录;修改丢失是因为别的事务也能读取当前事务的记录,虽然会阻塞别的事务的update,但在当前事务提交之后,别的事务的update语句会继续执行,进而覆盖上一次事务的结果,导致上一次的修改丢失。

2.2.2     REPEATABLE READ

Repeatable Read 事务的含义是我select出来的记录,不允许别人看,也不允许别人改(阻塞别的事务select、update),这就意味着我可以在事务中多次select数据,而不用担心出现“脏读”——这就是“可重复读取”的意思。

 

Repeatable Read 虽然解决了Read Committed 事务的读取不一致和修改丢失的缺点,但它也有缺点(尽管这个缺点Read Committed 也有):

Repeatable Read 不会阻塞insert和delete,所以会出现“幻读”——两次select的结果不一样。还有,Repeatable Read 占用的资源比Read Committed 大。

3        在应用程序中设置事务隔离级别

READ COMMITTED 是 Microsoft SQL Server Database Engine 的预设隔离等级。

 

已指定隔离等级时,在 SQL Server 工作阶段中,所有查询和数据操作语言 (DML) 陈述式的锁定行为都会在此隔离等级运作。此隔离等级会维持有效,直到工作阶段结束或隔离等级设为另一个等级为止。

 

如果应用程序必须在不同隔离等级操作,可以使用下列方法来设定隔离等级:

 

l           执行 SET TRANSACTION ISOLATION LEVEL Transact-SQL 陈述式。

 

l           如果 ADO.NET 应用程序使用 System.Data.SqlClient 管理的命名空间,可以使用 SqlConnection.BeginTransaction 方法来指定 IsolationLevel 选项。

 

l           使用 ADO 的应用程序可以设定 Autocommit Isolation Levels 属性。

 

l           当启动交易时,使用 OLE DB 的应用程序可以将 isoLevel 设为所要的交易隔离等级,以呼叫 ITransactionLocal::StartTransaction。当在自动认可模式中指定隔离等级时,使用 OLE DB 的应用程序可以将 DBPROPSET_SESSION 属性 DBPROP_SESS_AUTOCOMMITISOLEVELS 设为所要的交易隔离等级。

 

l           使用 ODBC 的应用程序可以使用 SQLSetConnectAttr 来设定 SQL_COPT_SS_TXN_ISOLATION 属性。

4        悲观锁

悲观锁是指假设并发更新冲突会发生,所以不管冲突是否真的发生,都会使用锁机制。

 

悲观锁会完成以下功能:锁住读取的记录,防止其它事务读取和更新这些记录。其它事务会一直阻塞,直到这个事务结束。

 

悲观锁是在使用了数据库的事务隔离功能的基础上,独享占用的资源,以此保证读取数据一致性,避免修改丢失。

 

悲观锁可以使用Repeatable Read事务,它完全满足悲观锁的要求。

5        乐观锁

乐观锁不会锁住任何东西,也就是说,它不依赖数据库的事务机制,乐观锁完全是应用系统层面的东西。

如果使用乐观锁,那么数据库就必须加版本字段,否则就只能比较所有字段,但因为浮点类型不能比较,所以实际上没有版本字段是不可行的。

6        死锁

当二或多个工作各自具有某个资源的锁定,但其它工作尝试要锁定此资源,而造成工作永久封锁彼此时,会发生死锁。例如:

  1. 事务 A 取得数据列 1 的共享锁定。
  2. 事务B 取得数据列 2 的共享锁定。
  3. 事务A 现在要求数据列 2 的独占锁定,但会被封锁直到事务B 完成并释出对数据列 2 的共享锁定为止。
  4. 事务B 现在要求数据列 1 的独占锁定,但会被封锁直到事务A 完成并释出对数据列 1 的共享锁定为止。

等到事务B 完成后,事务A 才能完成,但事务B 被事务A 封锁了。这个状况也称为「循环相依性」(Cyclic Dependency)。事务A 相依于事务B,并且事务B 也因为相依于事务A 而封闭了这个循环。

 

例如以下操作就会产生死锁,两个连接互相阻塞对方的update。

 

连接1:

begin tran

select * from customers

update customers set CompanyName = CompanyName

 

waitfor delay '00:00:05'

 

select * from Employees

–因为Employees被连接2锁住了,所以这里会阻塞。

update Employees set LastName = LastName

commit tran

 

连接2:

begin tran

select * from Employees

update Employees set LastName = LastName

 

waitfor delay '00:00:05'

 

select * from customers

--因为customers被连接1锁住了,所以这里会阻塞。

update customers set CompanyName = CompanyName

commit tran

 

SQL Server遇到死锁时会自动杀死其中一个事务,而另一个事务会正常结束(提交或回滚)。

SQL Server对杀死的连接返回错误代码是1205,异常提示是:

Your transaction (process ID #52) was deadlocked on {lock | communication buffer | thRead} resources with another process and has been chosen as the deadlock victim. Rerun your transaction.

 

除了Read UnCommitted和Snapshot,其它类型的事务都可能产生死锁。

转载于:https://www.cnblogs.com/kungfupanda/p/3586787.html

评论将由博主筛选后显示,对所有人可见 | 还能输入1000个字符 “速评一下”
限时福利1:原价 129 元,最后2天仅需 69 元!后天涨价至98元 限时福利2:购课进答疑群专享柳峰(刘运强)老师答疑服务 限时福利3:购课添加助教领取价值 800 元的编程大礼包 为什么需要掌握高性能的MySQL实战? 由于互联网产品用户量大、高并发请求场景多,因此对MySQL的性能、可用性、扩展性都提出了很高的要求。使用MySQL解决大量数据以及高并发请求已经是程序员的必备技能,也是衡量一个程序员能力和薪资的标准之一。 为了让大家快速系统了解高性能MySQL核心知识全貌,我为你总结了「高性能 MySQL 知识框架图」,帮你梳理学习重点,建议收藏! 【课程设计】 课程分为四大篇章,将为你建立完整的 MySQL 知识体系,同时将重点讲解 MySQL 底层运行原理、数据库的性能调优、高并发、海量业务处理、面试解析等。 一、性能优化篇: 主要包括经典 MySQL 问题剖析、索引底层原理和事务与机制。通过深入理解 MySQL 的索引结构 B+Tree ,学员能够从根本上弄懂为什么有些 SQL 走索引、有些不走索引,从而彻底掌握索引的使用和优化技巧,能够避开很多实战中遇到的“坑”。 二、MySQL 8.0新特性篇: 主要包括窗口函数和通用表表达式。企业中的许多报表统计需求,如果不采用窗口函数,用普通的 SQL 语句是很难实现的。 三、高性能架构篇: 主要包括主从复制和读写分离。在企业的生产环境中,很少采用单台MySQL节点的情况,因为一旦单个节点发生故障,整个系统都不可用,后果往往不堪设想,因此掌握高可用架构的实现是非常有必要的。 四、面试篇: 程序员获得工作的第一步,就是高效的准备面试,面试篇主要从知识点回顾总结的角度出发,结合程序员面试高频MySQL问题精讲精练,帮助程序员吊打面试官,获得心仪的工作机会。
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页