MySQL事务隔离级别(InnoDB)
MySQL(InnoDB引擎)有四种事务隔离级别,从上到下安全性越来越高,性能越来越不好
读未提交(read uncommitted)
读已提交(read committed)
可重复读(repeatable read)
串行化(serializable)
MySQL默认的事务隔离级别为 可重复读。
设置事务隔离级别基本命令:
查看MySQL数据库的当前事务隔离级别:select @@tx_isolation; #REPEATABLE-READ 可重复读
设置当前会话隔离级别为 可重复读: set session transaction isolatin level repeatable read;
设置系统当前隔离级别为 可重复读: set global transaction isolation level repeatable read;
查看数据库当前自动提交状态: show variables like 'autocommit'; # 结果为on表示开启自动提交,为off表示关闭自动提交
更改数据库自动提交状态: set autocommit=off; #设置为非自动提交,需要手动执行 commit 命令
事务的基本要素(ACID)
1、原子性(Atomicity):事务开始后所有操作,要么全部做完,要么全部不做,不可能停滞在中间环节。事务执行过程中出错,会回滚到事务开始前的状态,所有的操作就像没有发生一样。也就是说事务是一个不可分割的整体,就像化学中学过的原子,是物质构成的基本单位。
2、一致性(Consistency):事务开始前和结束后,数据库的完整性约束没有被破坏 。比如A向B转账,不可能A扣了钱,B却没收到。
3、隔离性(Isolation):同一时间,只允许一个事务请求同一数据,不同的事务之间彼此没有任何干扰。比如A正在从一张银行卡中取钱,在A取钱的过程结束前,B不能向这张卡转账。
4、持久性(Durability):事务完成后,事务对数据库的所有更新将被保存到数据库,不能回滚。
MySQL事务隔离级别
事务隔离级别 脏读 不可重复读 幻读
读未提交 会 会 会
读已提交 不会 会 会
可重复读 不会 不会 会 (InnoDB默认的事务隔离级别)
串行化 不会 不会 不会
事务的并发问题
假设同时开启A,B两个事务(前提需要设置事务为非自动提交:set autocommit=off),两个事务操作同一个数据库中的同一张表: USER(表的ID是唯一主键,因为幻读需要用到主键)
脏 读:事务A在USER表中插入一条数据 xxx, 未提交(也就是未执行commit命令),事务B读取USER表数据时会读到事务A插入的数据 xxx, 然后事务A发现插入的那条xxx数据有问题时执行回滚操作(rollback),事务B再次读取USER表数据的时候会发现被事务A回滚的数据 xxx不见了,这就是脏读。(读取到了未提交的事务)
不可重复读:事务A在USER表中插入一条数据 xxx, 未提交(也就是未执行commit命令),事务B读取USER表数据时读取不到事务A插入的那条数据 xxx,事务A提交(执行commit命令)后,事务B再次读取USER表数据时会读取到事务A插入的那条数据 xxx。 这就是不可重复读。(事务提交前与事务提交后读取到的内容不一致,只读取已提交的数据)
幻 读:事务A在USER表中插入一条数据 xxx(主键为99), 未提交(也就是未执行commit命令),事务B读取USER表数据时读取不到事务A插入的那条数据 xxx(主键为99), 事务A提交(执行commit命令)后,事务B再次读取USER表数据时还是读取不到事务A插入的那条数据 xxx(主键为99)。但是当事务B想要在USER表中插入一条主键为99的记录时, 会报错 Duplicate entry '99' for key 'PRIMARY',这就是幻读。(读不到已提交的事务,但是也无法写入相同数据)
读未提交 - 对应脏读
读已提交 - 对应不可重复读
可重复读 - 对应幻读
串行化 我们来单独解释下,serializable隔离级别的多个事务不可以同时对同一张表修改 ,就是指读写都会上锁,所以效率会低。
同上,事务A,B同时开启,事务A在USER表中新增数据xxx,未执行commit命令,事务B开始执行查询USER表,这时候事务B查询是没有结果的,需要等事务A执行完commit释放写锁后,事务B的查询语句才会拿到读锁开始执行,结果自动返回。