背景

数据库相关的知识应该主要就是

  • 事务
  • 索引

准确的说数据库就是索引、锁,事务不过是锁在数据库上应用的一种表现的特征。

概述

数据库事务是一组操作数据的指令的集合,这种操作可以是读取,也可以是更新。事务具备以下特性:

  • 原子性:事务所包含的指令集要么全部执行,要么全部不执行
  • 一致性:一致性没有一个严格的数学定义,松散一点的说,就是能够按照用户的预期来执行(这里需要多说以下,数据库的一致性和分布式一致性所说的一致性是不同的,之前看raft或者poxas的时候,经常会搞混淆,分布式一致性可以叫成分布式共识更好一点,不同的 节点看到的状态是一致的,不会有节点看起来是A,另外一些节点看起来是B状态!)
  • 隔离性:隔离是事务之间相互之间不干扰,从一个事务的视角来看,其他的事务要么在当前这个事务之前已经完成,要么在当前这个事务已经完成之后才开始,这样每个事务都感觉不到其他事务的存在
  • 持久性:事务一旦完成之后,他对数据库的影响是永久性的,即便系统出现故障

接下来重点说一下事务隔离级别及其所带来的问题:

事务的隔离级别

隔离界别分为以下几种

读未提交(read uncommitted)

允许事务T1读取事务T2中没有提交的数据,如果T2执行失败,发生了回滚,那么T1就读取到了错误的数据,对应到具体的问题就是数据的脏读

读已提交 (read committed)

事务T1读取到了事务T2中已经提交的数据,这样会带来的问题是:如果T1连续两次读取到某一条数据,那这两次读取到的结果不一致,会引发的问题就是不可重复读

可重复读 (repeatable read)

事务T1在连续读取某一条记录的间隙不存在另外一个事务T2对该记录的修改(mysql innodb默认的事务隔离级别),无法解决幻读的问题

序列化 (serializable)

完全串行化,每个事务都会获取表级锁,可以解决所有的问题,带来的问题是事务吞吐量的降低、cpu利用率低下以及较高的响应时延

隔离级别引发的问题

接下来我们会通过mysql演示数据库事务隔离级别所带来的问题,mysql事务隔离级别查看及修改方式(我当前安装的是mysql8.0): 查看数据库事务隔离级别

1
2
3
4
5
6
7
mysql> select @@transaction_isolation;
+-------------------------+
| @@transaction_isolation |
+-------------------------+
| REPEATABLE-READ |
+-------------------------+
1 row in set (0.00 sec)

修改当前会话的事务隔离级别

1
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE

脏读

一个事务T1访问到了另外一个事务T2修改了、但是没有提交的数据

不可重复读

一个事务T1多次读取某一个数据,在两次读取数据之间,另外一个事务T2对数据进行了修改并提交,导致T1连续两次读取到的数据发生了变化,对比脏读, 不可重复读取到的是另一个事务已经提交的数据,而脏读读取到的是另一个事务没有提交的数据

可重复读

mysql innodb默认的事务隔离界别就是可重复读,这个我们可以测试一下: 上面我们在左边开启一个事务,然后插入一条数据,在右边区查看表中的记录,在左边的事务没有提交的情况下,可以看到右边查到的数据为空, 直到左边的事务commit之后,右边的查询才可以读取到 接下来我们模拟在一个事务连续两次读某个记录操作的过程中,另外一个事务来修改该记录,如下: 我们可以看到,左右两边同时开启一个事务之后,右边在update一条记录(未commit)的情况下,左边查看到的结果仍然是旧的数据, 接下来我们将右边的事务commit之后,再查看 左边的查询是否是可重复读的,如下 经过上面的测试流程我们可以清楚的看到在可重复读的隔离级别中,一个事务的多次读操作不会受到另外一个事务写的影响,最后我们来测试一下两个事务同时更新某一条记录的情况: 这种情况下我们发现其中的一个更新事务会被阻塞直至超时。

幻读

幻读也可以称之为虚读,事务T1批量修改表中的数据,在T1还没有提交之前事务T2新增了一行T1需要修改的数据并提交, T1在提交的时候发现了一行本来应该修改,但是没有修改的数据。 对比脏读,幻读和不可重复读都是读取了另外一条提交了的事务的数据, 幻读强调的是一批数据的修改,不可重复读强调的是一条数据的修改

实现原理

小结

本节主要介绍了数据库事务相关的知识,需要明确的是事务的隔离级别越高,性能就越差,另外实现事务隔离的机制通常是采用加锁的方式, 这将会在后续的文章中持续跟进。


原子性、一致性、持久性 —- redo log、undo log 隔离性 —– 锁来体现

  • 读未提交:脏读

  • 读已提交:不可重复

  • 可重复读:mysql的

  • 序列化:

  • 幻读:是区间读的一种现象

  • MVCC解决的事快照读的幻读问题,当前读的幻读是通过gap lock或者说next-key lock来解决的

  • 锁的划分
  • 操作类型
    • 读锁/共享
    • 写锁/排他
  • 资源粒度:行、表锁可以共存
    • 表锁
    • 行锁
      • MDL
      • 意向锁:意向锁并不是真正意义上的锁,而是一种标记,用于标记表中存在一些行是正在被加了行锁的,因此意向锁之间都是相互兼容的,意向锁和正常的表锁之间的兼容性则是只有读兼容,其实这也好理:简单的将意向锁理解成行锁就可以快速判断了。

锁是原子性的体现

事务是可见性的体现

flink on yarn:作业唯独、资源唯独、作业和资源的交互唯独