一、事务基本概念
事务:事务是一组SQL语句的集合,必须满足ACID特性才能成为事务。
A原子性:这一组SQL语句要么全部执行成功,要么全部执行失败。
C一致性:事务执行前后保证完整性约束。
I隔离性:消除事务间的相互影响。
D持久性:保证事务执行的结果在磁盘上永久的存储。
二、原子性
A原子性:这一组SQL语句要么全部执行成功,要么全部执行失败。
那么如何保证事务的原子性呢?
假如我们下面5条SQL语句构成了一个事务,假如select与update都执行成功,但insert执行失败,如何让它们保持事务的原子性全都执行失败呢。采用日志系统,通过重做日志与未做日志保证了原子性。
redo log重做日志:记录了事务将要执行的每一个操作。 事务还没有执行,将要执行的事务记录在重做日志中,还不执行。执行日志先行:日志生成好了后,先将日志刷新到磁盘上。事务开始后,即使断电,因为在磁盘上最后还是可以保证全部执行成功;
undo log未做日志:保存了事务执行的每个状态。 事务在错误点执行回滚,回滚到最开始状态。
三、一致性
C一致性:事务执行前后保证完整性约束。
一致性的保证:由加锁控制。 我们在锁机制会详谈。
四、隔离性
I隔离性:消除事务间的相互影响。
4.1没有隔离性产生的问题
我们的隔离性可以消除事务之间的相互影响,但如果没有隔离性,事务之间会出现什么问题?
1.脏读:事务获取到其它事务执行过程中的结果。
例如:我们有一个数据张三,工资为5000。A事务执行过程中进行修改操作,B事务读取了A事务执行过程中的结构,该数据就是一个脏数据。
解决方案:事务执行过程中获取不到其它事务执行过程中的结果。
2.不可重复读(修改操作导致):事务执行过程中获取了其它事务不同的阶段的结果。
例如:我们有一个数据张三,我们有一个数据张三,工资为5000。假设脏读问题已经解决,不能读取到A事务执行过程中的结果。A事务正在使工资修改为8000,但B事务只能拿到A事务执行前的结果5000。再执行A事务,A事务提交执行完成,B事务再次进行查询获取A事务执行后的结果。产生了问题:拿到了两个不同的数据,产生了二义性。
解决方案:事务在其它事务执行过程中开启,其它事务相对于该事务透明。
3.幻读(插入或删除操作导致):事务执行过程中获取到其它事务不同阶段的结果。
例如:我们有一个数据张三,我们有一个数据张三,工资为5000。A事务开启查询工资为5000的员工个数为1,再插入一条数据李四工资也是5000;时间片到了,B事务开启先查询工资为5000员工个数只能拿到A事务执行前结果为1。再到A事务执行,A事务提交执行完成,B事务再次查询执行后的结果为2。
解决方案:间隙锁。
4.2隔离级别
隔离级别:
1.未提交读:事务未执行完成就读取事务执行过程中的结果。
会出现的问题:脏读,不可重复读,幻读。
2.已提交读:事务已提交后或回滚后才能读取事务执行后的结果。
会出现的问题:不可重复读,幻读。
3.可重复读:允许数据重复读。
会出现的问题:幻读。
4.可序列化:事务变成串行处理。
会出现的问题:效率变低。
当前隔离级别:每次一个客户端连接服务器,服务器分配给它的隔离级别,修改时修改的是当前隔离级别。
全局隔离级别:数据库服务端默认的隔离级别(可重复读),在配置文件中写的,数据库加载时直接读取配置文件。
查看隔离级别:可以使用select @@_isolation查看隔离级别:MySQL默认为可重复读的隔离级别。也可以使用set tx_isolation = “隔离级别”;来修改隔离级别。
修改隔离结级别: 这里我们开启了两个客户端,对A事务修改了隔离级别,B事务没有修改隔离级别。A事务的隔离级别修改并没有对B事务产生影响。这是因为有当前隔离级别与全局隔离级别。
五、持久性
D持久性:保证事务执行的结果在磁盘上永久的存储。
持久性的保证:由日志系统的日志先行来保证。日志每次先刷新到磁盘上,事务执行的每一条结果都有记录。即使断电了,加电后还是能够继续成功执行。