MYSQL基础知识之事务
1、概念
事务是一组操作的集合,它是一个不可分割的工作单位,事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求,所以这些操作要么同时成功,要么同时失败。
事务的四大特性:
原子性(Atomicity):事务是不可分割的最小操作单元,要么全部成功,要么全部失败;
一致性(Consistency):事务完成时,必须使所有的数据都保持一致状态;
隔离性(Isolation):数据库系统提供的隔离机制,保证事务在不受外部并发操作影响的独立环境下运行;
持久性(Durability):事务一旦提交或回滚,它对数据库中的数据的改变是永久的。
MySQL的事务默认是自动提交的,当执行一条DML语句,MySQL会隐式的提交事务
2、手动提交事务
查看是否自动提交事务:select @@autocommit;
其中1为自动提交事务,0为手动提交事务。
事务提交方式改为手动提交:set @@autocommit=0;
提交事务:commit;
回滚事务:rollback;
在另外一个会话里查询该表,显示数据并未被UPDATE,原因就是还没进行事务提交。(注意要再另外一个窗口查看数据)
提交事务后才正真更新
自动提交事务中手动提交:
当我们不想把自动提交事务改为手动提交事务,而防止自动提交事务出错时,可以在自动提交事务中,手动开始事务。
语法:start transaction 或 begin;
在另一个窗口查看数据,可看到数据未更新
再在原窗口执行COMMIT;后即可看到数据已更新
3、并发事务问题
当有两个或两个以上的事务同时执行、提交事务时,可能会引发并发事务问题,并发事务常见的问题有:
脏读:一个事务读取了另一个事务还没提交的数据;
不可重复读:一个事务先后读取同一条记录,但两次读取的数据不同,这种称为不可重复读;
幻读:一个事务按照条件查询数据时,没有对应的数据行,但在插入数据时,这行数据已经存在了,好像出现了“幻影”。
4、事务隔离级别
为了解决事务并发问题,我们设置事务的隔离级别,不同的隔离级别可以解决不同的事务并发问题,如下表:
查看事务的隔离级别:select @@transaction_isolation;
设置事务隔离级别:
set [session | global] transaction isolation level {read uncommitted | read committed | repeatable read | serializable}
其中session是当前会话窗口有效,global是对当前客户端的所有会话窗口有效。
4.1、Read uncommitted(读未提交)
设置事务隔离级别为Read uncommitted:set session transaction isolation level read uncommitted;
窗口1:
窗口2:
再看窗口1:
结论:在窗口2更新数据事务后,没有提交事务,但在窗口1查看数据发现数据已经更新了,这就属于脏读了
4.2、Read committed(读已提交,可解决脏读问题)
设置事务级别为read committed
窗口1:
窗口2:
此时窗口2未提交,看窗口1
可看到数据未更新
窗口2COMMIT;后再看窗口1:
窗口2:
窗口1:
可看到数据已更新
结论:Read committed隔离级别可以解决脏读问题。但注意解决不了不可重复读和幻读
4.3、Repeatable Read(可重复读)
为了解决不可重复读,把事务隔离级别改为Repeatable Read
窗口1:
窗口2:
窗口1:
窗口1:
在窗口1开启一个事务并查询数据表的数据后,在窗口2中开启事务并更新提交事务,再返回窗口1中查询数据表发现查询结果和之前查询一样,这就叫可重复读,在窗口1中提交第一个事务后,再次查询数据表数据发现数据发生了改变。这就解决了并发问题的不可重复读。
Repeatable Read可以解决脏读和不可重复读,但解决不了幻读:
窗口1:
窗口2:
窗口1:
在窗口1中开启事务并查询id为3的数据,发现数据表中没有id为5的数据,在窗口2中,开启事务并添加id为5的数据并提交事务后,在窗口1中添加id为5的数据,发现已经有id为5的数据了,但查询id为5的数据时,发现没有查到,这就是幻读。
4.4、Serializable(串行化,可避免脏读、不可重复读、幻读的发生)
为了解决幻读并发事务问题,可以把事务隔离级别改为Serializable
窗口1:
窗口2:
在窗口1查询id为6的数据,因为没有id为6的数据,所以没有查询到,在窗口2中插入id为6的数据,发现一直没有插入成功,这是因为在窗口1中已经开启了一个事务,需要窗口1开启的事务结束后,才能执行窗口2的事务,这样就解决了幻读问题。