事务由Mysql的引擎来实现,常见的Mysql的InnoDB引擎是支持事务的
比如就是在消费的时候,用户金额要减少,要生成用户的订单,且库存要减少,这样的操作必须全部执行或者全部不执行,否则可能就会使得用户钱减少了,但是没有得到东西的情况发生。
事务需要遵守4个特性
原子性
一致性
隔离性
持久性
原子性
即一个事务内的所有操作,要么全部完成,要么全部不完成,没有说完成一半的操作这一说,而且事务在执行过程中如果出错,就会回滚到事务开始的状态,就像这个事务从来没有执行过
这个原子性和redis的原子性不一样,只是称呼一样罢了,redis的原子性只是类似串行化,即在一系列给定顺序的操作执行过程中不会插入其他的操作命令
指事务操作前后,数据满足完整性约束,数据库保存一致性状态,例如转账的时候,A总共400花费了200,B总共700得到了200,一致性就是要求,最后的结果是A有200,B有900,而不会出现A扣除了,B却没增加的情况
数据库运行多个并发事务同时对其数据库进行读写和修改的能力,隔离就是为了防止多个事务并发执行时由于交叉执行而导致数据的不一致,多个事务同时使用相同数据,不会相互干扰,且每个事务都有一个完整的数据空间,对其他并发事务是隔离开的
持久性 - 通过 redo log来保证
原子性 - 通过 undo log来保证
隔离性 - 通过 MVCC(多版本并发控制)或者锁来保证
一致性 - 通过上面三个共同保证
一个事务读到了另外一个事务修改过又未提交的数据,就是脏读
例如A先读取了用户C的用户信息,然后又进行了更新,此时还没有提交事务,而又来了个事务B,也去查询了用户C的用户信息,而这个时候事务B读取到的用户信息就是事务A更新后的数据,即使没有提交事务
如果这个时候事务A出错了,事务进行了回滚,那事务B读取到的就是一个错误的用户信息了
出现的原因一般是另外一个事务进行删除或修改,且进行了提交
例如A和B两个事务在同时处理,A先读取C的用户信息,然后继续执行代码,然后事务B更新了这个数据,这时A再去读取,会发现两次读取数据不一样了,就会引起代码上的问题
比如我现在读取了一个用户,权限是学生,那我就按照学生的逻辑接着处理,这时候再读取一次来进行判断,发现怎么现在这个权限变成老师了,那后续的操作直接作废了。
在一个事务内多次查询某个符合查询条件的记录数量,如果出现前后两次查询到的记录数量不一致,则发生了幻读
一般是另外一个事务增加或修改了记录,使得符合查询条件的数量增多了
严重程度排序
脏读 > 不可重复读 > 幻读
指一个事务还未提交,它的变更就可以被其他事务读取
指一个事务提交后,变更才可以被其他事务读取
指一个事务执行过程中看到的数据,一直跟这个事务启动时看到的数据是一致的,这个是Mysql InnoDB引擎的默认隔离级别
对记录加上读写锁,在多个事务对这条记录进行读写操作时,如果发生了读写冲突,则后访问的事务需要等待前一个事务执行完释放锁才能继续
不同数据库对规定的4种隔离级别支持程度不同,而Mysql在可重复读的隔离级别下,可以很大程度避免幻读现象,而使用串行化会很大程度影响性能
但也并不是完全解决了幻读,在某些情况下还是可能出现幻读的
通过MVCC方式解决了幻读,因为可重复读隔离级别下,事务执行过程中看到的数据,一直跟这个事务启动时看到的数据一致,即使其他事务中途对其进行修改,在这个事务中是查询不出来的
通过next-key lock(记录锁+间隙锁)解决幻读,在执行该语句时,会加上next-key lock,如果有其他事务在锁范围内插入语句,就会被阻塞,无法插入
本文作者:Malyue
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!