数据库事务详解

事务特性:acid;aid为了实现c

        原子性:一个事务要么全执行,要么全不执行-》回滚    

                sqlite是备份

                其他是失败执行语义的反向操作-》算法

        一致性:

                完整性约束在一个事务执行后没有被破坏:主键约束,外键约束,自定义约束:转账两个账户余额的和应该不变 -》约束和回滚实现

        持久性:

                无论发生什么:崩溃等   ,都不会出现磁盘上数据的逻辑错误

                其实就是无论发生什么都没有错误(任何错误)

        隔离性:

                事务之间的影响问题

                问题:

                        脏读:读到了其他事务正在修改过程中的临时数据

                                事务A正在访问并修改数据, 事务B读到了A未提交的数据(脏数据)

                        不可重复读:

                                在事务A中先后读取同一个数据, 两次读取的数据不一样,  针对的是update操作

                        幻读:

                                2次读取的过程中,其他事务插入/删除了【有关】数据,针对的是insert和delete操作

                                事务A按照一定条件进行数据读取, 期间事务B插入或删除了相同搜索条件的新数据, 事务A再次按照原来的条件进行读取时, 发现了事务B新插入或删除的数据. 也就是说, 在事务A中按照某个条件先后两次查询数据库, 两次查询结果的条数不同, 这种现象叫做幻读

                         脏写:将临时无用数据写入了

                        第一类丢失更新:事物A 回滚时 让事物B已提交的数据都被回退了

                        第二类丢失更新:事物A读取数据后,事物B修改了数据,但是事物A仍然带着第一次读取的数据进行提交,导致事物B的修改丢失。这个问题有点像读已提交。

                解决方法-》加锁:

                        写锁(排他锁):给数据加上,其他事务   不能写,也不能读,而且数据只能加一个,其实也可以读-》但是不保证【问题】的发生

                                但是注意:写锁对于自己这个事务来说,等于是不加锁的

                        读锁(共享锁):给数据加上,所有事务不能写(只有晋升为写锁才能写),只能读,数据可以加多个事务的。

                                   晋升写锁:数据只加了一个事务的读锁

                                但是注意:读锁对于自己这个事务也是加锁的,整个事务的所有读都一样

                        范围锁:一定操作范围内的数据不能被读取和修改,用于解决幻读问题

                加锁后的结果-》隔离级别:

                        1 可串行化:对事物所有读写的数据,都加上读锁、写锁、和范围锁 就能实现串行化,效率低

                        2 可重复读:对事物涉及的数据加全周期的读锁,写锁;这样全周期读的数据都一样(读锁),也可以保证事务结束写操作实现(写锁):其他事务不能操作。

                                 但是没有解决幻读问题

                        3 读已提交:事物A读取数据部分加读锁,但是未施加全周期的读锁,但是没有解决幻读问题,可重复读问题

                                不可重复读:事务中可能有2次读取数据部分,这样如果其他事务修改,就2次读取数据不一致了-》不可重复读了

                        4 读未提交:对事物涉及的数据只加全周期的写锁,没有解决幻读问题,可重复读问题,脏读问题,但是没有脏写问题

                                脏读:全周期的写锁,相当于自己不加锁,自己可能读到自己的脏数据(临时数据)

                        5 完全不加锁:有所有问题

                                出现脏写问题,就已经连事物的原子性都无法保证了。所以一般隔离级别都不会包括他

                                完全不隔离还会导致第一类丢失更新的问题,就是事物A回滚时,使得事物B已提交的数据被修改。

读未提交解决第一类丢失问题
可重复读解决第二类丢失问题

 MVCC 无锁的隔离场景优化方案:主流的商业数据库都采用了这种方案。

         全称是 Multi-Version Concurrency Control 多版本并发控制

MVCC的基本思路

        MVCC的"无锁"是特指读取数据时,不需要加锁。
        MVCC的基本思路是对数据库的任何修改都不会覆盖之前的数据。而是产生一个新版本副本与老版本共存,以此达到读取时可以完全不加锁的目的。
        新版本和老版本,可以理解为每一行记录都有两个看不见的字段,CREATE_VERSION和DELETE_VERSION,这两个字段记录的都是事物的ID。这里事物的ID是一个全局严格递增的数值。

       数据操作
        数据被插入时:CREATE_VERSION记录插入数据的事物ID
        数据被删除时:DELETE_VERSION记录删除数据的事物ID
        数据被修改时:将修改视为“旧数据删除、新数据新增”则原有数据的。DELETE_VERSION和新数据的CREATE_VERSION为本次修改数据的事物ID。
MVCC优化事物隔离的场景

        隔离级别是可重复读:总是读取CREATE_VERSION 小于等于当前事物ID的记录,如果有多个就取事物ID最大的一个。这样事物A在读取数据时,事物B更新了数据产生了新的事物ID的CREATE_VERSION记录也不会被读取,事物A仍然读取的是其事物开始时的数据。这个数据不会被更改,天然不需要加锁。
        隔离级别是读已提交:每次读取最新的版本即可,这样每次都是读取到最后Commit的数据。
        可串行化和读未提交用不上MVCC:

                串行化的目标是阻塞其他事物的读取和写入,MVCC是做读取时无锁优化的,自然是用不上。
                读未提交 是需要直接读取未提交的数据,这种场景下直接修改原始数据即可,无需版本字段。

        弊端:
                写入+写入的场景下MVCC无能为力
                MVCC针对的是“读+锁”场景的优化,对于“写+写”的场景加锁几乎是唯一可行的解决方案。


乐观加锁和悲观加锁
        一般来说提到的锁都是悲观锁(Pessimistic Locking)数据库认为需要先加锁再访问数据,不然肯定会出问题。

        乐观锁策略(Optimistic Locking)认为竞争是偶然情况,没有竞争是普遍情况,应该一开始不加锁出现竞争时在补救。这种思路是 (Optimistic Concurrency Control,OCC)“乐观并发控制”
        乐观锁和悲观锁的性能优劣主要看并发竞争的剧烈程度,如果竞争剧烈乐观锁反而更慢

        

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值