一致性的定义

  • 百度百科-一致性:

一致性就是数据保持一致,在分布式系统中,可以理解为多个节点中数据的值是一致的。

  • 百度百科-事务一致性:

一个或多个事务执行后,原来一致的数据和数据库仍然是一致的。它主要涉及事务的原子性。

  • 维基百科-一致性(数据库)

一致性是数据库系统的一项要求:任何数据库事务修改数据必须满足定义好的规则,包括数据完整性(约束)、级联回滚、触发器等。

我对一致性的理解

“一致”是指数据库中的数据是正确的,不存在矛盾。事务的一致性是指事务执行前后,数据都是正确的,不存在矛盾。如果执行后数据是矛盾的,事务就会回滚到执行前的状态(执行前是一致的)。


满足一致性的例子

  • 学生表中的学号是唯一的。
  • 账户的余额减少了,账单中要有对应的扣款记录,且减少的金额和账单的扣款金额一致。
  • 一篇文章浏览量为100次,则浏览记录表有该文章的100条浏览记录。
  • 发布文章的用户ID是100,则用户表中存在ID为100的用户。

不满足一致性的例子

  • 学生表中有重复的学号。
  • 转账成功了,但是付款的人余额没扣,或者收款的人余额没有增加。
  • 付款多次,只扣款1次(或者付款1次,扣款多次)。
  • 发布文章的用户ID是100,但用户表中没有ID=100的用户。
  • 文章的发布时间是空的。
  • 用户的年龄是负数。
  • 用户的年龄是几个字母。

数据库如何实现一致性?

  • 唯一索引

给学号添加唯一索引,创建学生信息时,如果已存在相同学号,则创建失败。

  • 外键约束

给文章表的用户ID创建外键,创建文章时,如果不存在对应的用户,则创建失败;删除用户时,如果文章表有该用户的文章,则无法删除用户,或者将用户与文章一起删除。

  • 触发器

插入文章的浏览记录时,使用触发器去更新对应文章的浏览量(保证每增加一条浏览记录,对应文章浏览量+1)。

  • 指定数据类型

设置年龄的类型为非负整数,则年龄为负数、字母时保存失败。

  • 设置默认值

如果没有指定文章的发布时间,则默认以文章记录的插入时间作为发布时间。

  • 设置字段不能为空

设置文章的发布时间NOT NULL,没指定发布时间,或发布时间为NULL时,文章创建失败。

  • 事务的原子性
    事务的原子性是指同一个事务中的操作,要么都成功,要么都失败。以A向B转账100元转账为例,需要执行以下2个操作:

1.将A的余额减少100元;
2.将B的余额增加100元。

这两个操作要么都成功,要么都失败,否则最后账目就会对不上(破坏一致性)。事务的原子性可以保证以上两个操作同时成功,或者同时失败。

  • 事务的隔离性

在并发的情况下,只靠事务的原子性并不能保证一致性。举个例子,A有100元,A同时向B发起两笔转账请求,转账金额分别是99元和1元。
在这里插入图片描述
两笔转账都执行成功了,理论上A的余额为0,但实际上A的余额被请求2修改为99元,数据的一致性被破坏了!

再举一个例子,A同时发起两笔转账,其中一笔因为某些原因操作失败,事务回滚,而另外一笔转账执行成功。执行时间线如下:

在这里插入图片描述
在这个场景下,A实际转账成功了1元,但是A的余额最终为0,数据的一致性又被破坏了!

事务的隔离性可以在多个事务并发执行的情况下,通过加锁等方式,保证数据的一致性。

什么是事务?

事务就是「一组原子性的SQL查询」,或者说一个独立的工作单元。如果数据库引擎能够成功地对数据库应用该组查询的全部语句,那么就执行该组查询。如果其中有任何一条语句因为崩溃或其他原因无法执行,那么所有的语句都不会执行。也就是说,事务内的语句,要么全部执行成功,要么全部执行失败

事务控制语法知道吗?

BEGIN 或 START TRANSACTION 显式地开启一个事务;
COMMIT / COMMIT WORK二者是等价的。提交事务,并使已对数据库进行的所有修改成为永久性的;
ROLLBACK / ROLLBACK WORK。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
SAVEPOINT identifier 在事务中创建一个保存点,一个事务中可以有多个 SAVEPOINT;
RELEASE SAVEPOINT identifier 删除一个事务的保存点;
ROLLBACK TO identifier 把事务回滚到标记点;
SET TRANSACTION 用来设置事务的隔离级别。InnoDB 存储引擎提供事务的隔离级别有READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ 和 SERIALIZABLE
START TRANSACTION;
SELECT balance FROM CMBC WHERE username='lemon';
UPDATE CMBC SET balance = balance - 1000000.00 WHERE username = 'lemon';
UPDATE ICBC SET balance = balance + 1000000.00 WHERE username = 'lemon';
COMMIT;
  • 原子性(atomicity)

一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚,对于一个事务来说,不可能只执行其中的一部分操作。

  • 一致性(consistency)

数据库总是从一个一致性的状态转换到另外一个一致性的状态。在前面的例子中,一致性确保了,即使在执行第三、四条语句之间时系统崩溃,CMBC账户中也不会损失100万,因为事务最终没有提交,所以事务中所做的修改也不会保存到数据库中。

  • 隔离性(isolation)

通常来说,一个事务所做的修改在最终提交以前,对其他事务是不可见的。在前面的例子中,当执行完第三条语句、第四条语句还未开始时,此时如果有其他人也准备给lemon的CMBC账户存钱,那他看到的CMBC账户里还是有100万的。

  • 持久性(durability)

一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,修改的数据也不会丢失。持久性是个有点模糊的概念,因为实际上持久性也分很多不同的级别。有些持久性策略能够提供非常强的安全保障,而有些则未必。而且「不可能有能做到100%的持久性保证的策略」否则还需要备份做什么。

什么是脏读、不可重复读、幻读?

脏读

在事务A修改数据之后提交数据之前,这时另一个事务B来读取数据,如果不加控制,事务B读取到A修改过数据,之后A又对数据做了修改再提交,则B读到的数据是脏数据,此过程称为脏读Dirty Read。

在这里插入图片描述
不可重复读

一个事务内在读取某些数据后的某个时间,再次读取以前读过的数据,却发现其读出的数据已经发生了变更、或者某些记录已经被删除了。
在这里插入图片描述
幻读
事务A在按查询条件读取某个范围的记录时,事务B又在该范围内插入了新的满足条件的记录,当事务A再次按条件查询记录时,会产生新的满足条件的记录(幻行 Phantom Row)
在这里插入图片描述

不可重复读与幻读有什么区别?

  • 不可重复读的重点是修改:
    在同一事务中,同样的条件,第一次读的数据和第二次读的「数据不一样」。(因为中间有其他事务提交了修改)
  • 幻读的重点在于新增或者删除:
    在同一事务中,同样的条件,第一次和第二次读出来的「记录数不一样」。(因为中间有其他事务提交了插入/删除

SQL的四个隔离级别知道吗?具体是什么解决了什么问题说说看

SQL实现了四个标准的隔离级别,每一种级别都规定了一个事务中所做的修改,哪些在事务内和事务间是可见的,哪些是不可见的。低级别的隔离级一般支持更高的并发处理,并拥有更低的系统开销。
在这里插入图片描述
各个隔离级别可以不同程度的解决脏读、不可重复读、幻读。隔离级别各有所长,没有完美的解决方案,脱离业务场景谈具体实施都是耍流氓。
在这里插入图片描述
MySQL中哪些存储引擎支持事务?

MySQL中InnoDB和NDB Cluster存储引擎提供了事务处理能力,以及其他支持事务的第三引擎

什么是自动提交?

MySQL默认采用自动提交AUTOCOMMIT模式。也就是说,如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作。

对于MyISAM或者内存表这些事务型的表,修改AUTOCOMMIT不会有任何影响。对这类表来说,没有COMMIT或者ROLLBACK的概念,也可以说是相当于一直处于AUTOCOMMIT启用的模式。

在事务中可以混合使用存储引擎吗?

尽量不要再同一个事务中使用多种存储引擎,MySQL服务器层不管理事务,事务是由下层的存储引擎实现的。

如果在事务中混合使用了事务型和非事务型的表(例如InnoDB和MyISAM表),在正常提交的情况下不会有什么问题。

但如果该事务需要回滚,非事务型的表上的变更就无法撤销,这会导致数据库处于不一致的状态,这种情况很难修复,事务的最终结果将无法确定。所以,为每张表选择合适的存储引擎非常重要。

MySQL存储引擎类型有哪些?

最常用的存储引擎是InnoDB引擎和MyISAM存储引擎,InnoDB是MySQL的默认事务引擎。

InnoDB存储引擎的特点和应用场景?

InnoDB是MySQL的默认「事务引擎」,被设置用来处理大量短期(short-lived)事务,短期事务大部分情况是正常提交的,很少会回滚。

特点

采用多版本并发控制(MVCC,MultiVersion Concurrency
Control)来支持高并发。并且实现了四个标准的隔离级别,通过间隙锁next-key locking策略防止幻读的出现。

引擎的表基于聚簇索引建立,聚簇索引对主键查询有很高的性能。不过它的二级索引secondary
index非主键索引中必须包含主键列,所以如果主键列很大的话,其他的所有索引都会很大。因此,若表上的索引较多的话,主键应当尽可能的小。另外InnoDB的存储格式是平台独立。

InnoDB做了很多优化,比如:磁盘读取数据方式采用的可预测性预读、自动在内存中创建hash索引以加速读操作的自适应哈希索引(adaptive
hash index),以及能够加速插入操作的插入缓冲区(insert buffer)等。

InnoDB通过一些机制和工具支持真正的热备份,MySQL的其他存储引擎不支持热备份,要获取一致性视图需要停止对所有表的写入,而在读写混合场景中,停止写入可能也意味着停止读取。

MyISAM存储引擎的特点和应用场景?

MyISAM是MySQL 5.1及之前的版本的默认的存储引擎。MyISAM提供了大量的特性,包括全文索引、压缩、空间函数(GIS)等,但MyISAM不「支持事务和行级锁」,对于只读数据,或者表比较小、可以容忍修复操作,依然可以使用它。

InnoDB与MyISAM对比
在这里插入图片描述
感谢
https://blog.51cto.com/u_14163302/2551117
https://www.zhihu.com/question/31346392/answer/1707203839

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐