SQL Server数据库高级进阶之事务实战演练
一、SQL Server事务的本质
• 什么是SQL Server数据库事务?
事务:是作为单个工作单元而执行的--系列操作,如查询和修改数据,甚至可能是修改数据定义。
事务:保持逻辑数据一致性与可恢复性,必不可少的利器。
• SQL Server数据库事务举例
在一个事务中,你写了2条sql语句,一条是修改订单表状态,一条是修改库存表库存-1 。 如果在修改订单表状态的时候出错,事务能够回滚,数据将恢复到没修改之前的数据状态,下面的修改库存也就不执行,这样确保你关系逻辑的一致,安全。• 阿笨对SQL Server事务一句话总结
即这一组命令要么都执行,要么都不执行,通俗的理解就是共同进退。
二、SQL Server事务分类
SQL Server定义事务边界的方式分为显式事务和隐式事务两种。
• 显式事务:明确指出事务的起止边界。如果不显式定义事务的边界,SQL Server 会默认把每个单独的语句作为-一个事务;换句话说,SQLServer默认在执行完每个语句之后就自动提交事务。
显示事务需要定义以BEGIN TRAN语句作为开始。如果想提交事务,则应该以COMMIT TRAN语句显式结束事务;如果不想提交事务(撤消事务中的修改),则应该以ROLLBACK TRAN语句显式结束事务。
• 隐式事务:SQL查询分析器中,当前会话默认就是为隐式事务。每执行一条DML操作,就直接提交到数据库保存。
三、SQL Server事务的小陷阱
下面的例子将两个INSERT语句封装在由BEGIN TRAN和COMMIT TRAN定义的一个显示事务边界中:
BEGIN TRAN;
INSERT INTO dbo. T1(keyco], col1, co12) VALUES(4, 101,‘C);
INSERT INTO dbo. T1(keyco], col1, co12) VALUES(4, 101,‘C);
COMMIT TRAN;
T-SQL使用下列语句来管理完整的事务(事务的基本三要素):
• 开始事务:BEGIN TRANSACTION
• 提交事务:COMMIT TRANSACTION
• 回滚(撤销)事务:ROLLBACK TRANSACTION
• 存储点语句:SAVE TRANSACTION(可选)
所谓事务存储点就是在事务过程当中插入若干个标记,当事务执行中出现错误时,可以不撤销整个事务,只是撤销部分事务,将事务退回到某个事物存储点。一旦事务提交或回滚,则事务结束。(备注:将事务回滚在初始状态成本有点大,那么关于事务使用存储点根据实际业务情况来判定是否使用。)
• 阿笨个人总结:
默认的隐式事务,在SQL Server查询分析器中每一个单独的语句就是一个事务,如果多行语句块需要包裹在一个事务中的话,则需要手动的开启显示事务。(2条消息)SQL Server中的事务(附有实例)_数据库_legendaryhaha的博客-CSDN博客 https://blog.csdn.net/legendaryhaha/article/details/80550180?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task
四、SQL Server事务的特性
事务必须有四个属性:原子性(Atomicity)、一致性 (Consistency)、隔离性(Isolation)、持久性(Durability) ,这4个属性的首字母可以缩写为ACID。
• 原子性(Atomicity)
原子性是指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
针对同一个事务
操作前A:800,B:200操作后A:600,B:400
一致性表示事务完成后,符合逻辑运算。
• 一致性(Consistency)
事务前后数据的完整性必须保持一致。
针对一个事务操作前与操作后的状态一致
操作前A:800,B:200
操作后A:600,B:400
一致性表示事务完成后,符合逻辑运算
• 隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
针对多个用户同时操作(两个事务同时进行),主要是排除其他事务对本次事务的影响。
即不同事务之间的相互影响和隔离的程度。比如,不同的隔离级别,事务的并发程度也不同,最强的隔离状态是所有的事务都是串行化的(serializable)(即一个事务完成之后才能进行下一个事务),这样并发性也会降到最低,在保证了强一致性的情况下,性能也会受很大影响,所以在实际工程当中,往往会折中一下。每个RMDB关系型数据库的事务默认隔离级别是不一样的。
• 持久性(Durability)
持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
SQL SERVER通过write-ahead transaction log来保证持久性。write-ahead transaction log的意思是,事务中对数据库的改变在写入到数据库之前,首先写入到事务日志中。而事务日志是按照顺序排号的(LSN)。当数据库崩溃或者服务器断点时,重启动SQL SERVER,SQL SERVER首先会检查日志顺序号,将本应对数据库做更改而未做的部分持久化到数据库,从而保证了持久性.。
表示事务结束后的数据不随着外界原因导致数据丢失
操作前A:800,B:200
操作后A:600,B:400
如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:800,B:200
如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:600,B:400
五、SQL Server事务的隔离级别
1)、什么是数据库隔离级别
数据库的隔离级别实际上是针对事务的隔离级别来说的,它是用来限制一个事务中正在读取或被修改的数据免于被其他事务修改的程度。理论上每个事务和其他的事务都应该完全隔离开来。然而出于性能和可行性的原因,实践中几乎不可能做到的。
2)、数据库为什么要有事务的隔离级别
在并发环境下如果没有锁和隔离级别, 不考虑事务的隔离性可能引发的问题 可能会发生以下四种情况:
脏读:在这种情况下,一个事务能够读取另一个事务正在修改且未提交的数据,那么另一个事务如果发生回滚操作,将导致第一个事务读取到的数据和实际的数据不一致;
丢失更新:这种情况下,事务没有隔离。多个事务能够读取同一份数据并且修改它。最后对数据集做出修改的事务将胜出,而其他的事务所做的修改都失效;
不可重复读:两个事务读取数据,但是在第二个事务读取前,另一个事务修改了该数据,因此两次读取的数据不一致;
幻读:这种情况和不可重复读类似,不同的是,两个事务读取一个范围的数据,但是在第二个事务读取之前,另一个事务新增了一条数据,导致两次读取的结果不同。
要想解决脏读、不可重复读、幻读等读现象,那么就需要提高事务的隔离级别。但与此同时,事务的隔离级别越高,并发能力也就越低。所以,还需要读者根据业务需要进行权衡。
在了解了并发情况下出现的上述问题后,就可以进一步理解隔离级别的概念,通俗一点讲就是:你希望以何种方式将并发的事务隔离开来, 隔离到什么程度?比如允许脏读,等。隔离级别越高,读取脏数据或者造成数据不一致的情况就越少,但是在高并发系统中的性能降低就越严重。
2)、Sql Server支持6种隔离级别
• 未提交读(Read Uncommited)
• 已提交读(Read Commited)(Sql Server的默认事务隔离级)
• 可重复读(Repeatable Read)
• 序列化(Serializable)
• 快照(Snapshot)
• 已提交读快照(Read Commited Snapshot)
查看SQL Server当前会话的隔离级别
DBCC USEROPTIONS
Sql Server的默认事务隔离级别是已提交读(Read Commited),一个事务不允许读取另一个事务未提交的数据。
Mysql默认的事务处理级别是可重复读(Repeatable Read)也就是可重复读。
Oracle默认系统事务隔离级别是已提交读(Read Commited),也就是读已提交。
备注:实际工作中一般数据库默认的事务隔离级别做好不要去做修改。
六、SQL Server事务的实战运用场景
1)、批量一次性提交事务处理数据(插入)。
一)、为什么一次性提交事务批量插入数据效率最高?
使用事务可以提高数据的插入效率,这是因为进行一个INSERT操作时,SQL SERVER内部会建立一个事务,在事务内才进行真正插入处理操作。通过使用事务可以减少创建事务的消耗,所有插入都在执行后才进行提交操作。
二)、关于批量插入大数据的带来的思考总结
• 为了提升效率,数据能一次提交不做多次提交;
• 能一次插入解析sql不要多次提交解析sql;
• 插入数据量太大时,需要程序预先切割数据;
2)、在事务范围中如何防止查询大面积的数据行内出现死锁的情况
要提升SQL的查询效能,一般来说大家会以建立索引(index)为第一考虑。其实除了index的建立之外,当我们在下SQL Command时,在语法中加一段WITH (NOLOCK)可以改善在线大量查询的环境中数据集被LOCK的现象藉此改善查询的效能。
锁争用的解决方法:SQL Server开始是用行级锁的,但是经常会扩大为页面锁和表锁,最终造成死锁。 幸运的是,我们可以通过SQL Server 的NOLOCK来手工处理。
NOLOCK的使用
NOLOCK可以忽略锁,直接从数据库读取数据。这意味着可以避开锁,从而提高性能和扩展性。不过有一点千万要注意的就是,WITH (NOLOCK)的SQL SELECT有可能会造成Dirty Read,就是读到无效的数据。SQLServer性能优化之 nolock,大幅提升数据库查询性能 - 雲霏霏
https://www.cnblogs.com/yunfeifei/p/3848644.html
七、SQL Server事务遵守原则
编写事务时要遵守的原则大概总结如下:
• 事务尽可能简短:
事务启动至结束后再数据库管理系统中保留大量资源,以保证事务的原子性、一致性,隔离性和持久性。如果在多用户系统中,较大的事务将会占用系统的大量资源,是系统不堪重负,会影响软件的性能,甚至导致系统崩溃。
• 事务中访问的数据量尽量最少:
当并发执行事务处理时,事务操作的数据量越少,事务之间对操作数据的争夺就越少。
• 查询数据时尽量不要使用事务:
对数据进行浏览查询操作并不会更新数据库的数据,因此尽量不使用事务查询数据,避免占用过量的系统资源。
• 在事务处理过程中尽量不要出现等待用户输入的操作:
在处理事务的过程中,如果需要等待用户输入数据,那么事务会长时间地占用资源,有可能造成系统阻塞。