三:事务 (非常重要)
1. 什么是事务
事务就是一系列sql语句的组合,是一个整体
2. 为什么需要事务
场景1:转账操作。A的钱减去100,B的钱加100。当A正在转账的过程中,A的钱被扣除的时候,正好手机关机了,此时A的钱已经转出去了。但是B却没有收到钱。那这种情况是我们不想看到的结果。那么此时,我们需要将"A减钱和B加钱"打包成一个事务,这个事务的任何一个步骤失败,那么整个操作都回滚。
3. 使用事务
# 语法 start transaction; sql 语句 ... [rollback] # 回滚 sql 语句 ... sql 语句 ... commit # 测试数据 create table account(name char(10),money float); insert into account values("big",1000),("dog",2000),("cat",3000),("me",0); # 事务 start transaction; update account set money=money - 100 where name = "cat"; update account set money=money + 100 where name = "dog"; rollback; commit; # 保存点 start transaction; update account set money=money - 100 where name = "cat"; savepoint a; update account set money=money + 100 where name = "dog"; savepoint b; [rollback to a] # 回滚到自动地点 [commit];
4. 事务的四个特征
# 1. 原子性 指的是这个事务的sql语句是一个整体,不能拆分,要么都执行成功,要么全部失败 # 2. 一致性 事务执行结束后,表的关联关系一定是正确的,不会发生数据错乱 # 3. 隔离性 事务之间相互隔离,数据不会相互影响,即使操作了同一个表,本质就是加锁。根据锁的力度不同分为了几个隔离级别 # 4. 持久性 事务执行成功后,数据将永久保存。无法恢复
5. 事务的用户隔离级别
中文 隔离级别 脏读 非重复读 幻想读 读未提交 read uncommitted yes yes yes 读已提交 read committed no yes yes 可重复读 repeatable read no no yes 可串行化 serializable no no no # 读未提交 不做任何隔离,可能脏读,幻读。 # 读已提交 可以防止脏读,不能防止幻读,不可重复度 # 可重复读 可防止脏读、不可重复读,不能防止幻读 # 可串行化 所有问题都没有,就是性能低 // 脏读、不可重复读、幻读的区别 # 脏读:指一个线程中的事务读取到了另外一个线程中未提交的数据 # 不可重复读(虚读):指一个线程中的事务读取到了另外一个线程中提交的update的数据 # 幻读:指一个线程中的事务读取到了另外一个线程中提交的insert的数据
不可重复读与幻读比较相似,都是在一个事务中多次读取到不同的数据。网络上的总结如下:
不可重复读:所谓的虚读,也就是大家经常说的不可重复读,是指在数据库访问中,一个事务范围内两个相同的查询却返回了不同数据。这是由于查询时系统中其他事务修改的提交而引起的。比如事务T1读取某一数据,事务T2读取并修改了该数据,T1为了对读取值进行检验而再次读取该数据,便得到了不同的结果。
一种更易理解的说法是:在一个事务内,多次读同一个数据。在这个事务还没有结束时,另 一个事务也访问该同一数据。那么,在第一个事务的两次读数据之间。由于第二个事务的修改,那么第一个事务读到的数据可能不一样,这样就发生了在一个事务内 两次读到的数据是不一样的,因此称为不可重复读,即原始读取不可重复。
所谓幻读,是指事务A读取与搜索条件相匹配的若干行。事务B以插入或删除行等方式来修改事务A的结果集,然后再提交。
幻读是指当事务不是独立执行时发生的一种现象,例如第一个事务对一个表中的数据进行了修改,比如这种修改涉及到表中的“全部数据行”。同时,第二个事务也 修改这个表中的数据,这种修改是向表中插入“一行新数据”。那么,以后就会发生操作第一个事务的用户发现表中还有没有修改的数据行,就好象发生了幻觉一 样.一般解决幻读的方法是增加范围锁RangeS,锁定检锁范围为只读,这样就避免了幻读。简单来说,幻读是由插入或者删除引起的。大致的区别在于不可重复读是由于另一个事务对数据的更改所造成的,而幻读是由于另一个事务插入或删除引起的。
不可重复读(虚读)和幻读的差别:
从总的结果来看,似乎两者都表现为两次读取的结果不一致。
但如果你从控制的角度来看, 两者的区别就比较大:
对于前者, 只需要锁住满足条件的记录
对于后者, 要锁住满足条件及其相近的记录
6. 修改隔离级别
@ 表示用户自定义变量 @@ 表示系统内置变量 # 查看默认的隔离级别 SELECT @@global.tx_isolation; //查询全局事务 SELECT @@session.tx_isolation; //查询当前会话事务 show variables like "tx_isolation"; //查看环境变量 # 修改隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; //会话级别修改,测试可以不用设置全局事务 SET GLOBAL TRANSACTION ISOLATION LEVEL READ UNCOMMITTED; //全局级别修改,(这个可以不用设,只设置上面一行就可以了进行测试了)