简介
事务是访问数据库的一个操作序列,数据库应用系统通过事务集来完成对数据库的存取。事务的正确执行使得数据库从一种状态转换为另一种状态。
谈到本地事务,首先我们会想到事务的4个特性。
原子性(Atomicity)
数据库事务是不可分割的工作单位,只有使据库中所有的操作执行成功,才算整个事务成功;事务中任何一个SQL语句执行失败,那么已经执行成功的SQL语句也必须撤销,数据库状态应该退回到执行事务前的状态。
简单概括就是:事务中操作,要不全部执行,要不不执行。
A账户:500元
B账户:300元
A转账给B账户300元
A账户:500-300=200
B账户:300+300=600
不可能出现A账户钱少了,B账户没增加,也不可能出现B账户钱多了,A账户钱没有减少。
一致性(Consistency)
事务前后数据的完整性必须保持一致,如果事务成功,系统中所有变化将正确地应用,系统处于有效状态。如果在事务中出现错误,系统中的所有变化将自动地回滚,系统返回到原始状态。
A转帐前:500
B转账前:300
A转账后:200
B转账后:600
事务完成后,符合逻辑运算
隔离性(Isolation)
指在并发环境中,当不同的事务同时操纵相同的数据时,每个事务都有各自的完整数据空间,做到互不干扰。
比如下举例:两个事务同时进行,其中一个事务读取到另外一个事务还没有提交的数据
A转账B 200,同时C转账给A 100
A转帐前:500
B转账前:300
C转账前:800
A转账后:500-200=300
B转账后:300+200=500
C转账时读取到A的数据还是未减时数据 500,
A转账后:500+100=600
C转账后:800-100=700
此时事务隔离性出现问题,账户额度出现错误❌
Durability(持久性)
指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。
比如A给B转账了,即使银行服务挂了,修复好以后,这笔转账必须存在,不能丢失。
操作前A:800,B:200
操作后A:600,B:400
如果在操作前(事务还没有提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:800,B:200
如果在操作后(事务已经提交)服务器宕机或者断电,那么重启数据库以后,数据状态应该为
A:600,B:400
并发下事务产生的问题
脏读
是指事务A读到了事务B还没有提交的数据,比如银行取钱,事务A开启事务,此时切换到事务B,事务B开启事务-->取走100元,此时切换回事务A,事务A读取的肯定是数据库里面的原始数据,因为事务B取走了100块钱,并没有提交,数据库里面的账务余额肯定还是原始余额,这就是脏读
不可重复读
是指在一个事务里面读取了两次某个数据,读出来的数据不一致。还是以银行取钱为例,事务A开启事务-->查出银行卡余额为1000元,此时切换到事务B事务B开启事务-->事务B取走100元-->提交,数据库里面余额变为900元,此时切换回事务A,事务A再查一次查出账户余额为900元,这样对事务A而言,在同一个事务内两次读取账户余额数据不一致,这就是不可重复读
幻读
是指在一个事务里面的操作中发现了未被操作的数据。比如学生信息,事务A开启事务-->修改所有学生当天签到状况为false,此时切换到事务B,事务B开启事务-->事务B插入了一条学生数据,此时切换回事务A,事务A提交的时候发现了一条自己没有修改过的数据,这就是幻读,就好像发生了幻觉一样。幻读出现的前提是并发的事务中有事务发生了插入、删除操作
事务的隔离级别
事务隔离级别,就是为了解决上面几种问题而诞生的。为什么要有事务隔离级别,因为事务隔离级别越高,在并发下会产生的问题就越少,但同时付出的性能消耗也将越大,因此很多时候必须在并发性和性能之间做一个权衡。所以设立了几种事务隔离级别,以便让不同的项目可以根据自己项目的并发情况选择合适的事务隔离级别,对于在事务隔离级别之外会产生的并发问题,在代码中做补偿
set transaction isolation level 设置事务隔离级别
select @@tx_isolation 查询当前事务隔离级别
1. READ_UNCOMMITTED
读未提交,即能够读取到没有被提交的数据,所以很明显这个级别的隔离机制无法解决脏读、不可重复读、幻读中的任何一种,因此很少使用
2. READ_COMMITED
读已提交,即能够读到那些已经提交的数据,自然能够防止脏读,但是无法限制不可重复读和幻读
3. REPEATABLE_READ
重复读取,即在数据读出来之后加锁,类似"select * from XXX for update",明确数据读取出来就是为了更新用的,所以要加一把锁,防止别人修改它。REPEATABLE_READ的意思也类似,读取了一条数据,这个事务不结束,别的事务就不可以改这条记录,这样就解决了脏读、不可重复读的问题,但是幻读的问题还是无法解决
4. SERLALIZABLE
串行化,最高的事务隔离级别,不管多少事务,挨个运行完一个事务的所有子事务之后才可以执行另外一个事务里面的所有子事务,这样就解决了脏读、不可重复读和幻读的问题了
结束语
不是事务隔离级别设置得越高越好,事务隔离级别设置得越高,意味着势必要花手段去加锁用以保证事务的正确性,那么效率就要降低,因此实际开发中往往要在效率和并发正确性之间做一个取舍,一般情况下会设置为READ_COMMITED,此时避免了脏读,并发性也还不错,之后再通过一些别的手段去解决不可重复读和幻读的问题就好了。
网友评论