目录
原子性
一致性
持久性
隔离性
事务隔离级别
并发执行可能存在问题
脏读问题
不可重复读
幻读
难点解析
原子性
事务最核心的就是原子性
以前人们认为原子不可再分,用原子性来表示一个事务不可分割
update account set balance=balance-500 where name ="张三"
如果在此过程中数据库崩溃,那么张三扣钱而李四不加钱
update account set balance=balance+500 where name ="李四"
要么全部都不执行,要么全部都执行
事务就能保证,当执行过程中出现问题的时候,自动把前面SQL执行的效果进行还原,恢复如初,回滚rollback
在事务执行过程中,mysql才会记录每一步执行了什么,一旦有问题就回滚
事务有空间代价和时间代价,事务只有在开启状态才会消耗这些代价
如果是ctrl+z的话意味着每一步回退和记录都得消耗这个空间和时间
实际上人对SQL操作在实际运用中并不是很多,大部分都是机械在对服务器进行操作,出错概率很小,撤回机制没有必要。
开启事务:start transaction;
执行多条SQL语句
回滚或提交:rollback/commit;
除了原子性外事务还有
一致性
事务执行前后,数据处在一致状态,数据CURD对的上
持久性
事务进行的改动,都是写到硬盘,不会随着程序重启/主机重启后丢失
隔离性
多个事务,并发执行的时候,事务之间能够保持隔离,互不干扰。
同一时刻,多个客户端都给服务器提交事务,执行事务
事务隔离级别
- read uncommitted 允许读未提交的数据,并发程度相当高,隔离性最低,可能有脏读,不可重复读,幻读的问题
- read commited 只能读提交后的数据,相当于对写进行加锁,并发性开始下降,隔离性开始提高,解决了脏读的问题
- repeatable read 读和写操作都加了锁,并发程度再降低,隔离性再提高,解决了脏读,不可重复读,可能会有幻读的问题
- serializable 严格执行串行化,并发程度最低,隔离性最高,解决了脏读,不可重复读,幻读的问题,但效率最低
MySQL默认为repeatable read
在MySQL配置文件中my.ini中进行设置,根据不同的需求场景,可以设置不同的档位
并发执行可能存在问题
脏读问题
一个事务A在修改数据同时,另一个事务B读取了数据,此时A很可能在提交的时候修改
了B读取的数据,导致事务B读取的数据为无效数据,这种错误操作就是脏读操作
解决方法:在事务提交之前,不能进行读操作,提交之后才能读
也就是对 写操作 加锁
在加锁之前,我的写操作,和同学的读操作就是完全高并发的
但是并发性虽然高,隔离性却是最低的
在加锁之后,写的时候不能进行读操作,并非性降低了,隔离性提高了
不可重复读
在一个事务A中多次读取同一个数据,发现不一样
解决方法: 读数据的时候,不能修改,读加锁
引入读加锁后,并发程度进一步降低了,效率也下降了
但隔离性提高了,数据准确性也提高了
幻读
特殊的不可重复读,对A文件进行读的时候,增加了新文件B
导致读之前的结果集与读之后的结果集不同。
解决方法:
串行执行,效率最低,并发程度最低,此时,隔离性最高,数据的准确性最高。
MySQL的优化措施: REPEATABLE_READ(可重复读)+间隙锁就能解决幻读问题了,不一定要串行化 这样就构造了一个查锁吗,查的数据被锁了,不查的空数据也被锁了
间隙锁:加锁范围是被查询范围内的空隙(未填写数据的空位置),防止查询期间其他事务插入到间隙中,导致读之前的结果集与读之后的结果集不同。
上述
三种情况,不一定是bug,要根据实际需求,需要考虑对特定目标的准确性要求
衡量是不是BUG的唯一标准,就是看是否符合需求
难点解析
1.REPEATABLE_READ(可重复读)给查的数据加上锁,在事务结束之前都不能修改,以此来解决不可重复读问题2.REPEATABLE_READ(可重复读)+间隙锁就能解决幻读问题了,不一定要串行化
这样就构造了一个查锁吗,查的数据被锁了,不查的空数据也被锁了3.串行化就是等一个结束了再上另一个事务(类似葫芦娃救爷爷)
4.在串行化隔离级别下,读操作也会被加锁(一般是共享锁),不过在读取数据后就会放开数据,多个事务可以交替读.但是只能由一个事务改,且在写完之前都不能读
哈,谢谢各位同志的阅读,然后呢如果觉得本文对您有所帮助的话,还给个免费的赞捏
Thanks♪(・ω・)ノ