一.什么是事务
理解1(dljd-wh-redis):事务是指一系列操作步骤(多条sql语句),这一系列的操作步骤,要么完全地执行(提交),要么完全地不执行(回滚)。
理解2:
1,定义:数据库事务是访问(读)并可能更新(写)数据库中各种数据项的一个执行单元。
2,组成:一个数据库事务通常包含对数据库进行读或写的一个操作序列。
3,目的:
为数据库提供了一个从失败中恢复到正常的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。
总结~~~事务的目的就是要提供三种方法:
①失败恢复方法
②保持一致性的方法
③操作隔离的方法
4,三种情况下:
成功情况下:能将数据从一种状态变为另一种状态,并能够持久化。
异常情况下:①能将数据恢复到正常状态(解释:数据库中数据为 10,一个事务执行加一操作,操作结果为11,若提交时发生了异常,则应该回滚到初始状态10) ②要能保持一致性,包含数据的一致性和约束的一致性(解释:有学生表和选课表,学生01的成绩时90,学生02的成绩是80。数据一致性是指对学生01进行操作发生异常后进行回滚,回滚后不仅学生表中学生01的不变,其对应的选课表中学生01的成绩应该是90,保持不变。约束一致性是指若对学生表中新注册一个学生03,也要对应插入一条选课信息,若异常了,则要保证学生表和选课表都没有03的信息,若成功了,则应该都有,不能出现一个有一个没的情况 )
并发情况下:并发的操作之间不能产生相互影响
理解3:
事务是数据库的逻辑工作单位。
事务(Transaction)是并发控制单位,是用户定义的一个操作序列,这些操作要么都做,要么都不做,是一个不可分割的工作单位。
一组对数据库的读写操作,必须具有以下四种特性(ACID:原子性、一致性、隔离性、持久性)的操作才能叫做事务。
事务通常以BEGIN TRANSACTION开始,以COMMIT或ROLLBACK结束。
理解4:
事务是恢复和并发控制的基本单位。
事务(Transaction)是访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。
事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。
事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成(执行都执行,失败就回滚,对数据库数据没有影响)。
例如:在关系数据库中,一个事务可以是一条SQL语句,一组SQL语句或整个程序。或者例如银行转账工作:从一个账号扣款并在另一个账户增款,要么都执行,要么都不执行
理解5:Transaction 也就是所谓的事务了,通俗理解就是一件事情。
二、为什么要使用事务?
我为什么要使用事务? 俺这里再举个很俗很俗的例子:
俺到银行存钱,于是有这么几个步骤:
1、把钱交给工作人员;2、工作人员填单;3、将单子给我签字;4、工作人员确认并输入电脑。
要是,要是我把钱交给工作人员之后,进行到3我签字了。那哥们突然心脏病发作,over掉了,那,我的钱还没有输入电脑,但我却交了钱又签字确认了,而并没有其他任何记录。我岂不是要亏死了???我的血汗钱啊!赶紧退给我!!
于是,在数据库里产生了这么一个术语:事务(Transaction),也就是要么成功,要么失败,并恢复原状。
还是写程序把:
Create Proc sp我去存款(@M Money , @iOperator Int)
As
Begin
Declare @i int
Begin Tran --激活事务
Exec @i=sp交钱 @m,@iOperator
if @i<>0 --这里一般用系统错误号 @@Error。 我这里为了举例子没有用到。需要根据实际情况。
begin
Rollback Tran --回滚事务
RaisError ('银行的窗口太少了,我懒得排队,不交了!:( ', 16, 1) with Log --记录日志
Return -1 --返回错误号
end
Exec @i=sp填单 @m,@iOperator
if @i<>0
begin
Rollback Tran --回滚事务
RaisError ('银行的哥们打印机出了点毛病,打印不出单子来,把钱退回来给我吧??', 16, 1) with Log
Return -2
end
Exec @i=sp签字 @m
if @i<>0
begin
Rollback Tran --回滚事务
RaisError ('我 靠?什么烂银行,换了3支笔都写不出水来!!老子不存了!!不签!', 16, 1) with Log
Return -3
end
Exec @i=sp输入电脑 @m,@iOperator
if @i<>0
begin
Rollback Tran --回滚事务
RaisError ('什么意思?磁盘空间已满?好了好了,把钱给我,我到旁边的这家银行!', 16, 1) with Log
Return -4
end
Commit Tran --提交事务
Return 0
End
三、事务四大特性(简称 ACID)
四、事务的并发问题
多个事务对数据库的并发操作,可能会破坏事务的隔离性与一致性。由于并发访问而引发的这样的问题称为事务的并发问题。可能引发的并发问题主要包括三类:脏读、不可重复读和丢失修改。
1 脏读
2 不可重复读
- 事务A读取某一数据后,事务B对其做了修改,当事务A再次读取数据时,得到与前一次不同的值。
- 事务A按一定条件从数据库中读取某数据记录后,事务B删除了其中部分记录,当A再次按相同条件读取数据时,发现某些记录神秘地消失了。
- 事务A按一定条件从数据库中读取某数据记录后,事务B插入了一些记录,当A再次按相同条件读取数据时,发现多了一些记录。
3 丢失修改 - 写并发问题
两个事务A与B,读入同一数据并修改,B提交的结果破坏了A提交的结果,导致A的修改丢失。
4 幻读
也称为虚读。这个问题并非是《数据库系统概论》中给出的并发问题。而是现实存在的,由于对数据库的并发访问所引发的问题。
这里的幻读是指,在同一事务中,虽然多次执行相同的查询,查询结果是相同的。但后面的查询结果已经与DB中真正的数据不一致了。在同一事务中多次读取到的数据,不是真实的DB中当前数据,是虚的数据,是从缓存中读取的数据,就像是DB中数据的幻像。
四、事务的隔离级别
产生上述三类数据不一致性的主要原因是并发操作破坏了事务的隔离性,并发控制就是要用正确的方式高度并发操作,使一个事务的执行不受其它事务的干扰,从而避免造成数据的不一致性。
- 读取未提交:不防止任何并发问题
- 读取已提交:防止脏读,可能出现不可重复读与幻读
- 可重复读:防止脏读与不可重复读,可能出现幻读
- 串行化:不存在并发问题
打开 JDK6 的帮助文档,查找到 java.sql.Connection 接口,其有五个常量,代表五个隔离级别。
这五个隔离级别分别代表的常量数字,可以从 JDK 帮助文档中查看到。
五、封锁机制
事务的隔离级别,是DBMS隐式的为数据添加了锁。其底层实际上是在一个事务操作一个数据时,为该数据添加了一把锁。只有当该数据上的所有锁被释放掉后,其它事务才可操作该数据。但这个"操作"仅指修改、删除,不包括查询。当然,除了串行化级别是为表添加表级锁外,其它隔离级别所添加的锁均为行锁。
在实际应用中,若要实现"只为某些满足条件的记录添加锁,其它数据处于正常事务隔离级别中"的情况,则可以为这些数据手工加锁。这个手工加锁,称为封锁。
封锁是实现并发控制的一个非常重要的技术。所谓封锁是指,事务T在对某个数据对象例如表、记录等操作之前,先向系统发出请求,对其加锁。加锁后事务T就对该数据对象有了一定的控制,在事务T释放它的锁之前,其他的事务不能更新此数据对象。
锁可以分为两类:
乐观锁:每次访问数据时,都会乐观的认为其它事务此时肯定不会同时修改该数据。在真正修改时,会在代码中通过对锁的状态的判断来判断数据是否被其它事务修改过,是在代码中完成的,所以乐观锁是加在代码中的。
悲观锁:每次访问数据时,都会悲观的认为其它事务一定会同时修改该数据。所以,其在访问数据时,在数据库中就会给数据加锁,以防止其它事务同时修改该数据。所以锁是加在数据库中的。
1 乐观锁
2 悲观锁
悲观锁是加在DB中的封锁机制,又分为两种:排它锁,也称为X锁、写锁。共享锁,也称为S锁、读锁。
悲观锁是行锁,若要为表中的记录添加行锁,则需要通过执行查询语句来为符合条件的记录添加指定的锁。
在查询语句后添加for update,则会为每一条符合条件的记录添加写锁。例如:select * from student where id in(1,2,3) for update;会为id为1、2、3的记录添加写锁。
此时其它事务可以修改id为1、2、3之外的其它记录数据,可以查看所有记录数据,但不能修改id为1、2、3的记录数据,不能再为这些数据添加其它类型的锁。
在查询语句后添加lock in share mode,则会为每一条符合条件的记录添加读锁。例如:select * from student where id in(1,2,3) lock in share mode;id为1、2、3的记录添加读锁。
此时其它事务可以再为这3条记录添加读锁,可以任意读取其中的数据,但就是不能修改这些数据,不能为该数据添加写锁。
排它锁:若事务T对数据对象A加上写锁,则只允许T读取和修改A,其他任何事务都不能再对A添加任何类型的锁。直到T释放A上的写锁。这就保证了其他事务在T释放A上的锁之前不能再修改A。
但对于“表级锁”与“行级锁”,排它锁对于其它事务的读取权限规定是不同的。
对于“表级锁”中的排它锁,其它事务不仅不能修改表中数据,连读取的权限也没有。即一旦为表添加了排它锁,则其它事务对该表的增删改查操作权限全无。
对于“行级锁”中的排它锁,其它事务不能修改被锁定的数据,但可以读取。只不过读取到的是记录加锁之前DB中的原始数据。
共享锁:若事务T对数据对象A加上读锁,则事务T可以读取A但不能修改A,其他事务只能再对A加读锁,而不能加写锁,直到A上的读锁被全部释放。
排它锁与共享锁的区别总结:
- 一旦数据加上排它锁,则该数据上只能有排它锁这一把锁,不能再有其它任何锁。为该数据加锁的事务具有对该数据的增删改查的权限,而其它事务只有读取的权限。
- 一旦数据加上了共享锁,则该数据上可以添加很多共享锁,但不能添加排它锁。无论哪个事务,都只能读取数据,而不具有修改的权限。只有当该数据上的所有共享锁都被释放后,才可以为其添加排它锁。
六、参考文献
(1)(Undo Log、Redo Log保证、事务隔离级别)TNBLOG 事务简单理解 - 雨雨雨雨辰的专栏 - TNBLOG 事务简单理解 - 雨雨雨雨辰的专栏 - TNBLOG
(2)csdn 事务的隔离级别(通俗易懂) 事务的隔离级别(通俗易懂)_孤刺-CSDN博客
(3)(从程序方面理解事务)csdn (16条消息) 通俗解释事务_CountryShi的博客-CSDN博客 https://blog.csdn.net/CountryShi/article/details/79280216
(4)csdn 数据库:事务(个人大白话详讲) 数据库:事务(个人大白话详讲)_hhhhxxn的博客-CSDN博客
(5)(双客户端演示一致性)大白话讲解事务的ACID_Mysql-IT乾坤技术博客
深入:
(1)简书 白话事务 白话事务 - 简书
(2)csdn 自我感觉最通俗易懂的事务到分布式事务的理解 自我感觉最通俗易懂的事务到分布式事务的理解_小样_lxl的博客-CSDN博客
(3)51CTO 面试官:你说对MySQL事务很熟?那我问你10个问题 - 51CTO.COM 面试官:你说对MySQL事务很熟?那我问你10个问题 - 51CTO.COM
(4)知乎 如何理解数据库事务中的一致性的概念? - 知乎 (zhihu.com) 如何理解数据库事务中的一致性的概念? - 知乎
(5)csdn (16条消息) 自我感觉最通俗易懂的事务到分布式事务的理解_小样_lxl的博客-CSDN博客 自我感觉最通俗易懂的事务到分布式事务的理解_小样_lxl的博客-CSDN博客
(6)csdn (16条消息) 数据库事务概念理解(通俗易懂)_hestyle的博客-CSDN博客 数据库事务概念理解(通俗易懂)_hestyle的博客-CSDN博客_数据库中事务的概念
(7)博客园 InnoDB核心特性-事务 - 六月OvO - 博客园 (cnblogs.com) InnoDB核心特性-事务 - 六月OvO - 博客园
(8)csdn (16条消息) 一文搞懂数据库隔离级别及解决方案_邓靖川的博客-CSDN博客 https://blog.csdn.net/weixin_43934104/article/details/105847463?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EBlogCommendFromBaidu%7Edefault-5.base
(9)csdn (16条消息) 史上最清晰易懂的事务隔离级别图文讲解_西雅图的风的博客-CSDN博客 https://blog.csdn.net/ZYK1746914945/article/details/106885475?utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-11.base&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7EOPENSEARCH%7Edefault-11.base
(10)csdn 通俗易懂的MySQL事务隔离 https://blog.csdn.net/qq_34161458/article/details/105059423