一,什么是事务
事务把一组SQL语句打包成为一个整体,在这组sql的执行过程中,要么全部成功,要么全部失败。这组sql语句可以是一条也可以是多条。
("一条都不执行"不是真的没执行,而是"自动还原到执行前的状态"即"回滚")
1.1 如果执行事务过程中,断电了,还能回滚吗?
可以。
MySQL服务器下次启动的时候,自动触发回滚
MySQL中会执行事务时记录一个特殊的日志,里面记录了N个操作,如果最后一个操作执行成功,整个事务执行完毕,MySQL会自动删除刚才的日志,如果第N个操作之前,数据库断电,刚才的日志仍然存在,下次启动数据库的时候,数据库发现了这个文件的存在,会根据文件中的内容,对之前的操作进行回滚,回滚完毕再删除这个文件
二,事务的ACID特性
1)原子性:一个事务的所有操作,要么全部成功,要么全部失败,不会出现只执行了一半的情况,如果事务在执行过程中发生错误,会回滚到事务开始前的状态,就像这个事务从来没有执行过一样
2)一致性:在事务开始之前和事务结束之后,数据库的完整性不会被破坏。这表示写入的数据必须完全符合所有的预设规则,包括数据的精度,关联性,以及事务执行过程中服务器崩溃后如何执行
(例如转账过程中,a-500,b+500是一致的,无论是否转账成功,转账人和收款人的总额是不变的)
3)隔离性:数据库允许多个并发事务同时对数据进行读写和修改,隔离性可以防止多个事务并发执行时由于交叉执行而导致的数据的不一致,事务可以指定不同的隔离级别,以权衡在不同的应用场景下数据库性能和安全
4)持久性:事务处理结束之后,对数据的修改将永远的写入存储介质,即使系统故障也不会丢失
(计算机的持久基本和硬盘相关)
三,事务的隔离性和隔离级别
3.0 如何使用事务
3.0.1 查看支持事务的存储引擎
要使用事务那么数据库就要支持事务,在MySQL中支持事务的存储引擎是InnoDB,可以通过show engines语句来查看
3.0.2 语法
1)开始一个新的事务
start transaction;
或
begin;
2)提交当前事务,并对更改持久化保存
commit;
3)回滚当前事务,取消其更改
rollback
无论是提交还是回滚,事务都会关闭
3.0.3 保存点
在事务执行的过程中设置保存点,回滚时指定保存点可以把数据恢复到保存点的状态
语法:
设置保存点
savepoint 保存点名字;
回滚到保存点
rollback to 保存点名字;
3.0.4自动/手动提交事务
默认情况下,MySQL是自动提交事务的,也就是说我们执行的每个修改操作,比如插入,更新和删除,都会自动开启一个事务并在完成之后自动提交,发生异常时自动回滚
查看当前事务是否自动提交可以使用一下语句
show variables like 'autocommit';
on表示自动提交开启
可以通过一下语句设置事务为自动或手动提交
1)设置为自动提交
set autocommit = 1;
set autocommit = on;
2)设置为手动提交
set autocommit = 0;
set autocommit = off;
注意:只要使用了set autocommit或begin开启事务,必须要通过commit提交后才会持久化,与是否设置set autocommit无关
手动提交模式下,不用显示开启事务,执行修改操作后,提交或回滚事务时直接使用commit或rollback
已提交的事务不能回滚
3.1 什么是隔离性
MySQL服务可以同时被多个客⼾端访问,每个客⼾端执⾏的DML语句以事务为基本单位,那么不
同的客⼾端在对同⼀张表中的同⼀条数据进⾏修改的时候就可能出现相互影响的情况,为了保证不同
的事务之间在执⾏的过程中不受影响,那么事务之间就需要要相互隔离,这种特性就是隔离性
3.2 隔离级别
事务的隔离级别有四种:
read uncommitted,读未提交
read committed,读已提交
repeatable,可重复读
serializable,串行化
3.3 查看隔离级别
事务的隔离级别分为全局作用域和回话作用域,查看不同作用域事务的隔离级别,可以使用一下方式
select @global.transaction_isolation;
select @session.transaction_isolation;
可以看出默认的事务隔离级别是"可重复读"
3.4 设置隔离级别
语法:set global/session transaction isolatton leval level/access_mode;
访问模式:
access_mode: {
read write 表示事务可以对数据进行读写
/ read only 表示事务是只读,不能对数据进行读写
}
3.5 不同隔离级别存在的问题
3.5.1 脏读问题
事务1对某个数据进行了一个修改,但是修改进行中,事务还没有提交
事务2对这个数据进行读取,读到的可能是一个已经修改的数据了(读到的这个数据很可能是脏数据,即临时数据(只是中间结果,不是最终状态))
万一事务1后面进行了回滚,或者进行了其他的修改,则意味着事务2读到的数据是错误的
(读到别人还没提交的修改)
如何解决脏读?
数据库中,规定事务1必须把事务提交了之后,才允许事务2读取到修改
针对未被提交的修改,不应该被其他的事务读取到
3.5.2 不可重复读
有一个事务1,这个事务1执行过程中,两次读取某个数据,得到的结果是不一样的
如果同一个事务,多次读取同一个数据,结果都相同,就叫可重复读
(同一个数据读两次,结果不一样)
解决不可重复读的问题:
给"读操作"加锁,有事务在读的时候,其他事务不能改
本来事务1和2和3都能够同时执行,但是加了锁之后,此时无法同时了,得等到1执行完了指环王2和3才可以执行
整体的执行效率就降低了
3.5.3 可重复读/幻读问题
同一个事务中,针对某个查询,再次读取到的"结果集"不同(查询操作得到的是"临时表")
比如:第一次读,读到的是3条记录
第二次读,读到的是4条记录(其中前三条和第一次读的是一样的)
(两次查询,记录数量不同)
解决:
需要进行"串行化",能够让服务器"串行的"处理事务
一条一条的执行处理,串行化彻底避免了幻读问题
3.6 不同隔离级别的性能与安全
数据库执行事物的效率和准确性是无法兼得的
隔离性高则效率低,隔离性低则效率高
1)read uncommitted 隔离性最弱,并发性最强→最不准确,效率最高→脏读,不可重复读,幻读
2)read committed 隔离性提高了,并发性降低了→准确性提高了,效率降低了→脏读解决,不可重复读和幻读存在
3)repeatable read (这是MySQL默认的隔离级别)隔离性再次提高,并发性再次降低→准确性再次提高,效率再次降低→脏读,不可重复读解决→幻读存在
4)serialzable 隔离性最高,并发性最低→准确性最高,效率最低→解决所有脏读,不可重复读,幻读问题
可以通过配置,修改这里的隔离级别
1)通过sql语句
是临时的修改,如果MySQL服务器重启了,设置的级别就没了
2)通过配置文件
进行了修改之后,除了当前这个窗口(一个数据库的网络连接)生效之外,然后得是后面再连接上数据库服务器的窗口才能生效