一、事务及其特性
1.1 什么是事务?
定义:对于一个完整的不可分割的事件,保证其前后一致性的方案叫做事务;一个事物表示一个原子操作,对于事务的操作结果只有完全成功或未开始两种结果,事务的存在的意义则将保证该事件的完整性和可追溯性。
释义:一件事情(事务)往往由多个不可分割的事件组成,而组成一个完整事务的事件是可能存在部分成功和部分失败的情况,故由此会引发许许多多的难以预料的中间状态。比较经典的便是银行转账行为,一方进行支付成功,另外一方无法获取,或者另一方属于多个个体(工资接收方)中部分成功的问题。如果不进行事务维护,那么中间态的存在很多种可能的,在进行其他大量数据的相互影响中,存在过多此类问题后,系统难以进行时刻的还原,甚至会有多方的投诉,系统的信任问题,故为了解决此类情况,便有了事务处理。
1.2 事务的四大特性
1.2.1 原子性
一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作,这就是事务的原子性
1.2.2 隔离性
一个事务所做的修改操作在提交事务之前,对于其他事务来说是不可见的。
1.2.3 一致性
数据库总是从一个一致性的状态转换到另一个一致性的状态。(在前面的例子中,一致性确保了,即使在转账过程中系统崩溃,支票账户中也不会损失200美元,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。)
1.2.4 持久性
一旦事务提交,则其所做的修改会永久保存到数据库。
1.3 事务的隔离级别
上文讲清楚了什么是事务;这里主要是对事务的隔离级别进行明晰的定义,基于此,只要明晰了何种隔离级别,才会对不同的业务采用不同的事务处理方案。
1.3.1 读未提交(read-uncommitted)
读未提交: 允许一个事物读取另外一个事物中已修改且未提交事务的数据。
1.3.2 读已提交(read-committed)
读已提交:一个事物只能读取另外一个事务中已修改且提交过事务的数据。
1.3.3 可重复读(REPEATABLE-READ)
可重复读:对于上面读已提交导致的问题,那么在读已提交的隔离级别的基础上进行版本的快照设置,在进行事务的同时,对于当前的数据进行快照(一般是记录版本号等方式),同一个事物在读取事物的时候进行当前快照的数据读取,此时便可以在一个事物中进行重复读取。(mysql默认)select @@tx_isolation;
1.3.4 可串行化(SERIALIZABLE)
可串行化: 除了读取的事务之间没有锁,对于读写、写读、写写都是进行串行化处理;也就是说除了读读事务关系外,其余的事务处理都需要等上一个事务进行提交后才能进行下一个事务,将事务处理进行串行化处理。
可重复读是可以解决绝大部分场景的。但在进行金额等敏感数据的操作时,可重复读虽然可以解决数据一致性问题。但是快照的存在会使得两个终端进行数据操作时,可能存在的前后对不上的情况(eg:账户总共1000元 A端取钱100元,B端同时转款200元。操作结果是账号只剩下七百元,若A端不知道B端的行为的情况下,会觉得扣了200元【这也是为什么银行有短信服务的存在】)。
1.4 因不同事务隔离级别可能带来的问题。
1.4.1. 脏读--(读未提交)
并行事务在进行数据处理时,并行处理同一个数据,其中一个事务获取到了另外一个事物的.中间值,那么就会出现该脏读的情况。(一般是另外一个事务在进行修改操作导致的)
1.4.2. 幻读 (读未提交、读已提交)
一个事务在处理满足既定条件的数据时存在的数据在数量上不一致的情况。 (一般是由另外一个事物新增或删除导致的)
1.4.3. 不可重复读 (读未提交、读已提交【主要】)
并行事务在进行数据处理时,类似于脏读,多次读取某个数据存在前后不一致的情况;第一种便是在事务提交前读取导致偏差,第二种也可能是乐观锁导致数据在另外一个事务一致性情况下在时间上的读取差异(简而言之也就是一个A事务十分钟 B事务两分钟,B事务正好在A事务处理的事件端内,A事务正好读取了B事务处理的数据)。
二、mysql事务隔离级别实操
2.1 事务隔离级别简介
每次进行数据库连接的时候,会产生一个session,对于事务的隔离级别,可以是session级别的,也可以是global 全局的,如何设置呢?
-- 全局的隔离级别
set global transaction isolation level [隔离级别]
-- session级别的隔离级别
set session transaction isolation level [隔离级别]
注:隔离级别在一个session内也可以多次更改,故修改建议只是修改session内的隔离级别。
2.2 事务隔离级别实操
-- 初始状态 可重复读
select @@global.tx_isolation,@@tx_isolation;
-- 设置读未提交
set session transaction isolation level READ UNCOMMITTED;
select @@global.tx_isolation,@@tx_isolation;
SELECT * FROM t_user WHERE userid = '1'
-- 设置读已提交
set session transaction isolation level READ COMMITTED;
select @@global.tx_isolation,@@tx_isolation;
SELECT * FROM t_user WHERE userid = '1'
-- 设置可重复读
set session transaction isolation level repeatable read;
select @@global.tx_isolation,@@tx_isolation;
SELECT * FROM t_user WHERE userid = '1'
-- 设置可串行化
set session transaction isolation level serializable;
select @@global.tx_isolation,@@tx_isolation;
SELECT * FROM t_user WHERE userid = '1'