首页 > 数据库技术 > 详细

数据库基本知识点梳理系列 - 事务

时间:2019-11-22 15:42:32      阅读:73      评论:0      收藏:0      [点我收藏+]

数据库基本知识点梳理系列 - 了解数据库事务

Transaction 事务

事务是一种机制,是一种操作序列,它包含了数据库一组操作命令,这组命令要么全部执行,要么都不执行。因此事务是一组不可分割的事务逻辑单元,在数据库进行并发操作时候,事务是作为最小的控制单元来使用的.

事务的四大特性

名称 描述
原子性 事务必须是一个自动工作的单元,要么全部执行,要么全部不执行。
隔离性 并发多个事务时,各个事务不干涉内部数据,处理的都是另外一个事务处理之前或之后的数据。
一致性 事务结束的时候,所有的内部数据都是正确的。
持久性 事务提交之后,数据是永久性的,不可再回滚。

Sql Server中的事务

在SQL Server中事务被分为3类常见的事务:

事务名称 描述
自动提交事务 是SQL Server默认的一种事务模式,每条Sql语句都被看成一个事务进行处理,你应该没有见过,一条Update 修改2个字段的语句,只修该了1个字段而另外一个字段没有修改
显式事务 T-sql标明,由Begin Transaction开启事务开始,由Commit Transaction 提交事务、Rollback Transaction 回滚事务结束。
隐式事务 使用Set IMPLICIT_TRANSACTIONS ON 将将隐式事务模式打开,不用Begin Transaction开启事务,当一个事务结束,这个模式会自动启用下一个事务,只用Commit Transaction 提交事务、Rollback Transaction 回滚事务即可。

事务并发

多个事务并发时可能会造成的问题

问题名称 描述
更新丢失 多个用户同时对一个数据资源进行更新,必定会产生被覆盖的数据。
不可重复读 如果一个用户在一个事务中多次读取一条数据,而另外一个用户则同时更新这条数据,造成第一个用户多次读取数据不一致。
脏读 第一个事务读取第二个事务正在更新的数据表,如果第二个事务还没有更新完成,那么第一个事务读取的数据将是一半为更新过的,一半还没更新过的数据,这样的数据毫无意义。
幻读 第一个事务读取一个结果集后,第二个事务,对这个结果集经行增删操作,然而第一个事务中再次对这个结果集进行查询时,数据发现丢失或新增。

使用锁解决事务并发带来的问题

本专题主要关于事务的基础梳理, 为了提升阅读质量, 关于锁的详细梳理可以移步: 数据库基本知识点梳理系列 - 锁 .
数据库锁的主要分类: 表级锁, 行级锁

锁的模式和兼容性是SQL Server预先定义好的,没有任何参数或配置能够去修改它们。但是可以通过隔离级别来控制申请锁和释放锁的时机,如果应用申请的锁粒度都比较小,产生阻塞的几率就会比较小。如果一个连接会经常申请页面级、表级,甚至是数据库一级的锁资源,程序产生阻塞的可能性就会很大。

事务的隔离级别 - (原理是锁)

笔者按: 锁与事务的隔离级别孰先孰后并不重要, 重要的是二者紧密关联, 事务的隔离级别用于描述具体的业务场景, 实现事务的隔离级别的技术是使用锁.

语法

set tran isolation level <级别>

事务隔离级别名称 描述 原理
read uncommitted 事务B可以读取到事务A正在处理的数据,及时事务A还没提交事务和回滚事务, 事务B此时读到的数据可能是脏数据. 这是事务隔离的最低级别. 事务对当前被读取的数据不加锁; 事务在更新某数据时必须加行级共享锁,此时其他事务无法修改该数据, 直到事务结束释放共享锁.
read committed 事务B在事务A完成之前, 无法读取事务A正在操作的数据, 但是可以修改事务A正在操作的数据. 这个隔离级别是sql server数据库默认的隔离级别. 能够避免脏读, 但是会造成不可重复读, 什么叫做不可重复读, 即当事务A开始其事务, 读取一行数据后, 得到结果A, 等待了10s, 此时有一个并行事务B对同一个数据进行了update 操作将数据结果改为B, 10s过后, 事务A继续处理, 再次查询数据, 结果是B, 此时的现象叫做不可重复读现象. 这里要注意的是, 不可重复读指的是对同一个数据的多次读取, 获得的结果不同., 还有一种类似的叫做幻读, 幻读的意思是在同一个查询条件下, 经过多次查询, 返回的结果集是不同的. 是因为有其他事务在对表进行insert或者delete. 所以不可重复读和幻读的案例中, 虽然都是事务A多次查询数据, 但是效果是不一样的. 所以称谓不同. 事务A对当前被读取的数据加行级共享锁, 事务B无法读取该数据, 直到事务A读取完毕后释放共享锁; 事务B可以获取此数据的排他锁(如果事务A只是获取了共享锁并为获取排他锁的情况), 事务B对数据进行修改后, 释放排他锁.
repeatable read 事务B无法读取和修改事务A正在处理的数据. 这一特点避免了不可重复读的问题, 但是无法避免幻读问题. 因为此隔离级别的读锁是加在数据级别的, 并不是加在表级别. 事务A如果读取一个范围的数据, 事务B只是对表中添加了一行数据, 恰巧也符合这个范围, 事务A再次读取这个范围的数据时, 会发现两次读取的结果不同.造成了幻读. 尚未查明,等待补充
snapshot 指定事务在开始的时候,就获得了已经提交数据的快照,因此当前事务只能看到事务开始之前对数据所做的修改。 尚未查明,等待补充
serializable 将并发转为串行, 实际上是对表进行加锁. 这样的隔离级别是最高的. 但是效率是最低的. 一般不会使用这个隔离级别的. 事务在读取数据时,必须先对其加 表级共享锁 ,直到事务结束才释放;事务在更新数据时,必须先对其加 表级排他锁 ,直到事务结束才释放。

事务隔离级别的例子

read uncommitted

  • 开启一个窗口输入以下命令1
  begin tran
  set deadlock_priority low
  update [UsageCheckHistories] set Message = 'set tran isolation level read uncommitted' where id = 11311
  waitfor delay '0:0:5'
  rollback tran
  • 开启另一个窗口输入以下命令2
set tran isolation level read uncommitted
waitfor delay '0:0:1'
select * from [WoodBlockModelKPIs].[dbo].[UsageCheckHistories] where id = 11311
waitfor delay '0:0:10'
select * from [WoodBlockModelKPIs].[dbo].[UsageCheckHistories] where id = 11311

命令1开启了一个显示事务, 并设置锁级别为low, 将id为11311的数据的message update为‘set tran isolation level read uncommitted‘, 等待5秒后回滚事务. 命令2将事务隔离级别设置成为 read uncommitted, 等待1秒后, 读取数据id为11311的信息, 此时获取到message已经为‘set tran isolation level read uncommitted‘, 等待10秒后, 再次读该数据, 发现数据和之前不同.

read committed

  • 开启一个窗口输入:
 --Transaction A
use woodblockmodelkpis
begin tran
waitfor delay '0:0:1'
select * from [UsageCheckHistories] where id = 11311
waitfor delay '0:0:10'
select * from [UsageCheckHistories] where id = 11311
commit tran
  • 开启另一个窗口输入
 --Transaction B
use woodblockmodelkpis
set tran isolation level read committed
waitfor delay '0:0:1'
update [UsageCheckHistories] set Message = 'update message by Transaction B.' where id = 11311

技术分享图片

repeatable read

  • 开启一个窗口输入:
begin tran
update [UsageCheckHistories] set Message = '888' where id = 11311
waitfor delay '0:0:5'
select * from [UsageCheckHistories] where id = 11311
commit tran
waitfor delay '0:0:1'
select * from [UsageCheckHistories] where id = 11311
  • 开启另一个窗口输入:
set tran isolation level repeatable read
waitfor delay '0:0:1'
update [UsageCheckHistories] set Message = 'why we cannot see the record?' where id = 11311

命令1执行命令udpate, 延迟5秒后, 查询数据, 然后提交事务, 然后延迟1秒, 再查询数据
命令2将事务隔离级别设置成为 repeatable read, 然后延迟1秒等待命令1 update 888操作完成, 然后执行update, 此时命令执行完成的提示会等一会儿才有.
结果证明repeatable read使事务A无法修改事务B正在操作的数据.

技术分享图片

数据库基本知识点梳理系列 - 事务

原文:https://www.cnblogs.com/it-dennis/p/11911013.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!