mysql的事务
一,事务
1.1事务介绍
1,事务就是由单独单元的一个或多个sql语句组成,在这个单元中,每个sql语句都是相互依赖的。而整个单独单元是作为一个不可分割的整体存在,如果单元中某条sql语句一旦执行失败或者产生错误,那么整个单元将会回滚。所有受到影响的数据将返回到事务开始之前的状态,但是如果单元中的所有sql语句都执行成功的话,那么该事务也就被顺利执行。
2,往通俗的讲就是,事务就是一个不可分割整体,里面的内容要么都执行成功,要么都不成功。不可能存在部分执行成功而部分执行不成功的情况。
3,的数据都是通过各种不同技术的存储引擎来引导存储的,不同的存储引擎,都有各自的特点。在mysql中,常见的存储引擎有innodb、myisam,memory等。其中innodb支持事务(transaction),而myisam,memory等不支持事务。
# 查看mysql支持的存储引擎
show engines;1.2事务的ACID
- 原子性(Atomicity):指事务是一个不可分割的工作单位,事务中的操作要么都发生,要么都不发生。
- 一致性(Consistency):事务必须使数据库从一个一致状态变换到另外一个一致状态。
- 隔离性(Isolation):一个事务的执行不能被其他事务干扰,即一个事务内部的操作及使用的数据对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。
- 持久性(Durability):一个事务一旦提交成功,它对数据库中数据的改变将是永久性的,接下来的其他操作或故障不应对其有任何影响。
1.3事务的分类
事务分为隐式事务和显式事务两种:
- 隐式事务:执行的DML语句(insert、update、delete)就是隐式事务,隐式事务不需要我们手动开启事务和结束事务。
- 显示事务:显示事务事务需要我们手动开启事务和结束事务;
显示事务的语法格式:
# 开启事务
# 第一种
set autocommit = 0;
# 第二种
start TRANSACTION;# 结束事务
# 第一种:提交
commit;
# 第二种:回滚
rollback;1.4事务并发问题
原因:同时运行多个事务,当这些事务访问数据库中相同数据时,如果没有采取必要的隔离机制,会产生各种并发问题;
- 读-读问题:读读并发不存在问题。
- 写-写问题:写写会产生脏写问题,两个事务没提交的状况下,都修改统一条数据,结果一个事务回滚了,把另外一个事务修改的值也撤销了,所谓脏写就是两个事务没提交状态下修改同一个值。
- 读-写/写-读:写读或读写会造成脏读、幻读、不可重复读的问题。
- 脏读:事务B读到事务A修改后并未提交的数据;
- 不可重复读:事务A多次查询得到的结果不一致
- 幻读:B插入一条数据,A在插入主键相同数据数据,会报主键重复的错误。
注意区分:脏读针对更新数据,幻读针对插入数据。
1.5事务的隔离级别
为了避免出现事务的各种并发问题,我们就必然要采取一些手段,对于写读或读写会造成脏读、幻读、不可重复读的问题,可以通过设置数据库隔离级别方式解决,mysql数据库系统提供了四种事务的隔离级别:
| 事务隔离级别 | 是否可以解决脏读 | 是否可以解决不可重复读 | 是否可以解决幻读 |
|---|---|---|---|
| 读未提交(read uncommitted) | 否 | 否 | 否 |
| 读已提交(read committed) | 是 | 否 | 否 |
| 可重复读(repeatable read) | 是 | 是 | 否 |
| 串行化(serializable) | 是 | 是 | 是 |
MySQL事务隔离级别默认是可重复读
设置事务隔离级别:
# 查看当前的事务隔离级别通过 tx_isolation变量;
select @@tx_isolation;
# 在mysql8.0之后,用 transaction_isolation变量代替;
select @@transaction_isolation;#设置当前mysql连接的隔离级别:
set session transaction isolation level read uncommitted;
set session transaction isolation level read committed;
set session transaction isolation level repeatable read;
set session transaction isolation level serializable;
#设置数据库系统的全局的隔离级别:
set global transaction isolation level read uncommitted;1.5.1读未提交

存在脏读:事务B在第⑤步读到事务A在第④步修改后并未提交的数据产生了脏读。
InnoDB对于写操作操作而言,会添加写锁的,而读操作,不加会添加任何锁,就会造成上面的脏读。
1.5.2读已提交

解决脏读:事务B在第⑤步没有读到事务A在第④步修改后并未提交的数据,解决脏读。
存在不可重复读:在事务B还未结束事务的时候,在执行第⑤步和第⑦步中执行同一条查询sql,得到的结果不一致。
①,InnoDB通过MVCC做到读写不阻塞,不仅解决了读写性能问题,而且避免了类似脏读这样的问题。
②,在读已提交的隔离级别下,MVCC生成的readview每次执行都会更新,所以会产生不可重复读问题。
1.5.3可重复读

解决脏读:事务B在第⑤步没有读到事务A在第④步修改后并未提交的数据,解决脏读。
解决不可重复读:在事务B还未结束事务的时候,在执行第⑤步和第⑦步中执行同一条查询sql,得到的结果一致。
存在幻读:在事务B还未结束事务的时候,在执行⑦步没有查到id为2的数据,可以插入,但是执行第⑧步的时候报错主键重复,明明没有确报主键重复就像产生幻觉一样。
①,InnoDB通过MVCC做到读写不阻塞,不仅解决了读写性能问题,而且避免了类似脏读这样的问题。
②,在可重复读的隔离级别下,MVCC生成的readview每次不会更新,所以不会产生不可重复读问题。
可重复读可以防止部分幻读,为什么是部分防止幻读,而不是完全防止?如果事务A和事务B都未提交事务,事务A insert(第④步)了一条数据并提交,事务B(第⑤和第⑦)再次查询,虽然读取的还是undo中的旧版本数据(防止了部分幻读),但是事务B中执行insert(第⑧步)还是会报错存在幻读的。
1.5.4 串行化

解决脏读,不可重复读和幻读:事务B未结束事务时,事务A进行写操作时,会进入阻塞状态,不可以修改数据,即存在未结束的事务就能进行写操作,只能进行读操作,读读并发不存在问题。
串行化的实现是通过间隙锁的方式。
1.6事务补充
1.6.1事务的隔离级别能解决写写问题吗?

mysql事务隔离级别不管是什么都能解决脏写问题,因为在两个事务没提交的状况下,只有一个事务能修改的值,另一个事务如果修改同一个值会进入阻塞状态,所以不会存在两个事务没提交状态下修改同一个值的情况。
1.6.2事务的保存点
事务保存点的使用格式:
# 开启事务
set autocommit = 0;
# 第一次写操作
# 设置保存点,xxx为保存点的名字,名字随便起
savepoint xxx;
# 第二次写操作
# 回滚到xxx保存点处,产生的效果第二次操作会回滚。
rollback to xxx;效果演示:
