数据库事务的简单理解

数据库事务的简单理解
事务的概念
  1. 概念:只为单个逻辑工作的一系列操作,要木完全执行,要木完全不执行,简单来说,事务就是并发控制的单位,是用户定义的一个操作序列。

    事务只是一个改变,一些操作的集合,我们可以理解为他就是一个程序的执行单元,我们要通过某些手段让这个执行单元满足这个四个特性,那木我们就可以称之为一个事务,或者说是一个正确的事务,完美的事务。

  2. ACID:原子性,一致性,隔离性,持久性

    • 原子性 :满足原子操作单元,对数据的操作,要木全部执行,要木全部失败
    • 一致性:事务开始和完成,数据都必须保持一致
    • 隔离性:事物之间是相互独立的,中间状态时不可见的
    • 持久性:数据的修改时永久的
  3. 场景 :银行转账 A有1000元向B转账200

    • 原子性 就是A转出去200元和B收到200元必须都发生,要木都不发生
    • 一致性 转账完成后A剩下了800元 而B获得了200元
    • 隔离性 A给B转账的同时,C也给B转账100。A和C的操作互不干涉,且B获得金额300元。
    • 持久性 转账完毕之后,A和B账户的金额不再会变
事务的隔离级别

背景: 多个事务共同操作数据库

start/begin sql语句 commit rollback

1. 因为并发而可能出现的问题
  • 脏读 : A事务对某一个数据进行操作的时候,还未提交。B事务就得到了A事务的结果。
  • 不可重复读:A事务在本次事务中,对自己未操作过的数据进行读取,结果出现了不一致的记录或者不存在的记录。(update 和 delete)
  • 幻读:A事务在本次事务中,对自己未操作过的数据进行多次读取,第一次读取的时候,记录不存在,而第二次读取的时候,记录出现了(insert)
2. 为了权衡并发和隔离的矛盾,于是定义了事务的四个隔离级别
  1. 未提交读 read-uncommitted 最低的级别 会发生脏读,不可重复读,幻读
  2. 已提交的读 red-committed 语句级别的 会发生不可重复读,幻读 (Oracle)
  3. 可重复读 repeatable-read 事务级别的 会发生幻读 (MySQL)
  4. 串行化 serializable 最高级别的
如何去实现数据库中的隔离

加锁实现

表锁和行锁 InnoDB引擎提供

从字面上理解就可以了 表锁就是你只要操作数据表中的数据就会导致

  1. 锁粒度 表锁大于行锁
  2. 加锁效率 表锁大于行锁
  3. 冲突概率 表锁大于行锁
  4. 并发性能 表锁小于行锁
事务隔离级别的实现方式 (LBCC lock-Based Concurrent Control)
1. 共享锁

对select语句加入的锁,是一种可重入锁,是行锁

也被人称之为读锁,对某一个资源加共享锁,自身可以读取资源,其他人也可以读取该资源,但是无法对该资源进行修改,只有当所有的读锁释放完成之后才可以对该资源进行修改。

加锁 select * from table lock in share mode;

释放锁 commit; rollback;

读锁是行锁,锁住的是表中的某一个资源或者某一段资源

2.排他锁

对DML语句默认会加排他锁,是一种不可重入锁,是行锁

顾名思义 : 对某一资源加排他锁,自身可以进行增删改查,其他人无法进行任何操作

排他锁无法与其他锁共存.

默认加锁 : DML语句

手动加锁 : select * from table for update;

释放锁 : commit; rollback;

3.意向共享锁

这个不是我们手动创建的,也不能手动创建, 表锁

充当一种标识的作用, 当表里面有共享锁的时候, 可以理解为这个表的前面就会标识有多少个共享锁. 当一个共享锁释放之后, 对应的意向共享锁也会消失

4.意向排他锁

这个不是我们手动创建的,也不能手动创建, 表锁

充当一种标识的作用, 当表里面有排他锁的时候, 可以理解为这个表的前面就会标识有多少个排他锁. 当一个排他锁释放之后, 对应的意向排他锁也会消失.

其实意向排他锁和意向共享锁是为了, 在其他表锁在对这个表上锁的情况下看看, 是否还有事务对表中的数据进行操作, 若是有的话, 就等待他们执行完毕后再去加表锁. 防止出现问题

锁的算法

对当前数据库中表的记录划分的范围划分在这里插入图片描述

1. 记录锁 (Record Locks)

就是对单个数据进行加锁的行锁 一般是用"="查找某个或者修改单个数据的时候所加的锁就是记录锁

2. 间隙锁(Gap Locks)

就是对多个数据进行加锁的行锁

但是是没有触及到表中记录的范围查找

比如

select * from table where id > 1 and id < 4

它加锁的方式就是间隙锁 加锁的数据段就是(1,4)

select * from table where id > 15

这个加锁的方式是间隙锁 加锁的数据段就是 (10, +无穷大)

3. 临建锁(Next-key-locks)

就是对多个数据进行加锁的行锁

但是是触及到表中记录的范围查找

比如

select * form wher id > 0 and id < 5

加锁的方式就是临建锁, 加锁的数据段就是(-无穷大,7]

事务隔离级别的实现方式(MVCC Multi-Version Concurrent Control)

多版本的并发控制 一种行级锁的变种, 是 MySQL 的 InnoDB 存储引擎实现隔离级别的一种具体方式,用于实现提交读和可重复读这两种隔离级别

提高我们的并发量 实其效率更快

**在 MVCC 中事务的修改操作(DELETE、INSERT、UPDATE)会为数据行新增一个版本快照。**这个快快照是对于整个数据库来说的, 但是快照所保存的并不是整个数据库内容,不是复制粘贴将整个数据库中的内容保存到另一个地方 . 而是对于没每一个DML操作之后提交的数据形成一个版本号. 也就是 transaction_id, 这个id记录了每个事务对某个数据的修改.

1.快照读

快照读解决的就是不可重复读的问题

2.当前读

就是为了 避免出现了非一致性问题.
在这里插入图片描述

每一个事务开启的时候都会获得InnoDB引擎给与的自增版本号, 事务1的到的版本号(TRX_ID)为103, 事务2得到的版本号为104, 事务三得到的版本号为105, 并且每一个事务得到了最后一个事务提交的数据的版本号(UP_Limit_ID)102, 当他们想要查询A的值的时候, 就会通过UP_Limt_ID中获取得到A的值为100 .

解析事务1.快照读其实就是在同一个事务中没有对这个数据进行修改的话, 它的row_trx_id就为空, 于是它读取数据的时候,读取得永远是版本号为102中数据中内容 所以 W = 100 Q = 100

解析事务2, 读取X的时候 row_trx_id为空,我们直接从UP_Limt_ID中获取到A=100, 得到X=100但是在执行M的时候,事务3已经结束事务并且提交了事务, 而对于修改的操作, 我们理解他要获取最新的A的值(101)进行+1操作, 把A的值设为102的同时并且将row_trx_id = 104, 也就是说在数据库底层已经存储了 版本号为104并且A值102的数据. 当我们进行Y操作的时候, 读取底层的版本号进行对比, 发现row_trx_id = 102并且发现和我们开始事务的时候引擎自动给我们设置的版本号相同,所以读取到Y=102

也就是说在一个事务中,我们进行读取操作的时候, 我们需要先用我们得到的row_trx_id一一对比Undo日志中的数据, 获取之后就是我们所需要的数据. 如果row_trx_id为空, 那木证明我们未在这个事务中进行过增删改查操作, 通过up_limt_id中获得版本号,然后通过这个版本号来对比, 最终查到对应的数据.

up_limt_id 是我们进行事务之前获得到的最后一次提交的版本号

TRX_ID 是我们开启事务之前, InnoDB引擎自动给我们分配的版本号

row_trx_id 是我们事务之中若是进行了增删改操作, 那木我们自己的事务要认, 于是从row_trx_id中的版本号中获取数据.

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值