MySQL事务
文章目录
数据库作为一个网络服务器,我们在操作的时候,别人也可以在操作,我们进行增删改查的时候,别人也可以进行增上改查,所以可能会不安全,会出现多执行流
例如
在买票的时候,当A检查到还有一张票,将票卖掉,此时,数据库还没有更新,客户端B检查了票数,发现大于0,于是又卖了一张票,然后A将票数更新了,发现一张票被卖了两次
CURD满足的属性
- 买票的过程必须是原子的(原子性)
- 买票相互之间不能影响(隔离性)
- 买完票要永久有效(持久性)
- 买前,买后都必须要是确定的状态(一致性)
什么是事务
[Transaction]
事务本质就是一组SQL语句,理论上,事务本就不应该属于MySQL,而是应该在应用层上面,完成的一件事情,完成一系列相关操作的sql语句集合叫做事务
假如说你从学校毕业了,那么学校教务系统,后台的MySQL中就不需要你的信息了,那么管理员会运行几条sql命令来输出你的(姓名,电话,籍贯等信息),同时还有一些sql操作输出你的成绩,这些操作组合起来,就构成了一个”事务”
事务=原子性的操作多条的sql语句
再比如:
张三给李四转账200
张三的账户余额update减少200,李四的账户余额update增加200,在数据库角度是执行两条sql
所有的sql操作,一般都会被mysql包装成事务,无论是一条还是多条的sql,都是一样的对待的
一个完整的事务,绝不是简单的sql集合,还必须要满足4条属性ACID
- 原子性(atomicity,或称不可分割性),
执行一条sql,要么全部都执行完,要么全部不完成,而一旦事务在执行的时候出现了错误,就回滚(rollback),到事务开始前的状态,前面成功的sql也取消掉,就像这个事情没有发生过一样
- 一致性:(Consistency):
事务的一致性是指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。
比如:如果从A账户转账到B账户,不可能因为A账户扣了钱,而B账户没有加钱
- 隔离性:(isolation,又称独立性):
允许多个事务同时处理任务的时候,不影响别人
- 持久性:(durablity):
数据库把数据更新完,数据的修改必须是持久的,不会因为系统故障而丢失
为什么会出现事务
事务是被MySQL设计出来,为了当应用程序访问数据库的时候,事务可以简化我们的编程模型,不需要我们去考虑各种并发各种潜在错误,
所以当我们去使用事务的时候,要么提交,要么回滚,不会考虑网络中断的问题,
我们后面就把MySQL里面的一行信息称为一行记录
事务的版本支持
MySQL只有innodb支持事务,mysiam不支持事务,这就是我们使用innodb的原因,mysiam适合查询检索retrieve
事务的提交方式
事务的提交有两种:
- 自动提交
- 手动提交
查看事务的提交方式
1 |
|
设置为手动提交
1 |
|
设置MySQL的隔离级别设置为未提交,
1 |
|
查看隔离级别
1 |
|
处于R级别
实验演示
正常演示
创建一个account表
1 |
|
查看表结构
证明事务的开始和回滚
- 启动事务
两种方式
1
start transaction;
1
begin;
- 插入一批数据
- 设置回滚地址
1
savepoint s1;
数据操作的一端查看数据
打开的另一个终端也查看数据
假如说,我们操作的一端后悔插入了赵六,因为我们设置了s2,所以我们可以回滚到s2处,这样就不需要我们去进行删除操作- 回滚到设置的地方
这里我们设置回滚到s2地方
1
rollback to s2;
在两个不同的终端查看都是一样的结果
rollback 后面什么都不带就是直接回滚到最开始的地方1
rollback;
- 提交
事务结束,就提交
1
commit;
总结:
命令行启动事务
- start transaction/begin
- 正常的sql操作
- rollback//savepoint/rollback to sp
- commit
非正常演示
- 客户端崩溃实验
我们插入了一批数据,然后直接让他ctrl /,让MySQL崩溃掉
一方的MySQL关闭了,没有进行commit操作,另一个终端会直接回滚到事务开始前的状态
当命令行输入,手动启动(begin /start transaction)一个事务的时候,和MySQL中是否事务会自动提交无关
只要我们是begin,start transaction,就必须要我们进行手动提交
那么自动调教的设置,是给谁设置的呢
提交
我们把事务进行提交
提交在崩溃,事务就不会再回滚了,这个就叫做事务的持久性- 证明单sql和事务的关系
这里我们把自动提交关闭
这里我们就使用了单条sql命令,然后奔溃
我们发现,它左边insert的数据,也没了,进行了回滚
其实我们之前的所有单条sql,本质上再mys ql里面,全部各自会以事务的方式进行提交,自动提交
我们写的4,5条sql,实际上应该是4,5个事务- 自动提交给谁设置的
MySQL中的单条sql设置的,我们时默认行为
回滚(原子性)
持久(commit)
事务操作的注意事项
- 如果一个事务已经被提交了,就不能再回滚了
- 证明单sql和事务的关系
事务隔离级别
理解mysql服务
- MySQL服务可能会被多个客户端线程访问,访问的方式都是以事务的形式形成
- 一个事务可能有多条sql组成,意味着,任何一个事务,都有执行前,执行中,执行后阶段,事务的原子性,是让用户层,要么看到执行前,要么看到执行后,而对于执行中出现的任何问题,都可以随时回滚,所以单个事务,对用户表现出来的情况,都是原子性的
- 但是,因为所有的事务都有个执行过程,那么在多个事务执行多个sql的时候,就会互相影响,同时操作同一行数据
你妈让你好好学习,要么别学,要么学最好,中间怎么努力学习,你妈不关心,你的学习对于你妈妈来说就是原子的,
- 为了保证事务执行的过程中,尽量不受干扰,就有了一个重要特征:隔离性
- 数据库中,允许事务受不同程度的干扰,就有了一个重要特征:隔离级别
隔离级别
- 读未提交[Read Uncommitted]:在改隔离级别下,所有的事务,都能看到别的事务
没提交的执行结果,读到了对方未提交的数据
我们在一个终端,启动事务,插入数据,没有提交
在另一个终端里面查看,是可以查看到的
1 |
|
- 读提交[Read Committed]:你提交了,别人才会读到你的数据
- 可重复读[Repeatable Read]:MySQL默认的隔离级别,
- 串行化 [Serilaize];最高的隔离级别,效率太低了,并发没用了
查看设置隔离级别
- 查看全局隔离级别
1 |
|
- 查看当前隔离级别,只能在本次会话有效
1 |
|
- 设置
恢复成全局默认设置,设置成全局的就要重启才可以但是如果设置为session的,就不需要进行这样的操作,只会影响自己1
set global transaction isolation level Repeatable Read;
1
2set session transaction isolation level Repeatable Read;
隔离级别
读提交
读提交,这里我们会发现一方修改的数据,另一个不受影响,读不到对方未提交的数据
但是此时当前是事务未commit,在同一个事务内,同样的读取,在不同的时间段,读到不同的值,这种现象就叫做不可重复读问题
不可重复读,存在问题
- 读提交,你一提交,别人能读到!=你已提交,和你并行运行的事务也能读到(并行发事务不应该读到,一开始读到什么数据,之后都要读到什么数据)
- 不可重复读有什么问题——-应用层有什么问题呢
给一个用户会被触发多次sql
不可重复读,就是两个同时启动的事务,一方改变了数据,commit之后,但是另一方还在事务中,读到的数据,就是已经commit上去之后的
可重复读
- 就是为了解决不可重复读问题的
- 可重复读,就是两个同时启动的事commit之后,但是另一方还在事务中,读到的数据,还是对方还没begin之前的数据,和对方commit无关
- 我永远看到的数据都是一样的,这就叫做可重复读,
运行期间看不到对方的操作
都commit之后就能看得到了
MySQL对于insert也能处理RR(幻读)
串行化
变成单进程,效率非常低,指的是事务之间的串行化,不是mysql里面sql语句的串行化,把事务进行排队
隔离性
MySQL的内部机制,让“同时”启动,并发执行的事务,看到不同的数据(增删改),能不能看到,就叫做隔离性
我们作为一个事务,可以看到不同可见性的数据,程度不同,叫做隔离级别
为何要存在隔离级别
为了安全,不需要各自种类繁多的隔离级别,无脑串行化最安全
不仅仅是为了考虑安全问题,有可能就不考虑安全问题,
在安全和效率之间,寻找平衡点,也不需要各种种类繁多的隔离级别
这个平衡点不是MySQL来决定的,而是由我们来决定的
一致性
持久性,原子性,隔离性共同组成了一致性
需要由用户和MySQL共同决定
是事务维护的最终目标