根本概念

ACID 准则

ACID,即 Atomicity(原子性)、Consistency(一致性)、Isolation(阻隔性)、Durability(持久性)四种特性的缩写。

ACID 也是一种比较出名的描绘一致性的准则,一般呈现在分布式数据库等依据业务进程的体系中。

具体来说,ACID 准则描绘了分布式数据库需要满意的一致性需求,同时答应支付可用性的代价。

  • Atomicity:每次业务是原子的,业务包含的所有操作要么悉数成功,要么悉数不履行。一旦有操作失利,则需要回退状况到履行业务之前;
  • Consistency:数据库的状况在业务履行前后的状况是一致的和完好的,无中间状况。即只能处于成功业务提交后的状况;
  • Isolation:各种业务能够并发履行,但彼此之间相互不影响。按照标准 SQL 规范,从弱到强能够分为未授权读取、授权读取、可重复读取和串行化四种阻隔等级;
  • Durability:状况的改变是持久的,不会失效。一旦某个业务提交,则它造成的状况改变便是永久性的。

延伸-BASE与CAP

BASE准则

与 ACID 相对的一个准则是 eBay 技术专家 Dan Pritchett 提出的 BASE(Basic Availability,Soft-state,Eventual Consistency)准则。BASE 准则面向大型高可用分布式体系,主张献身掉对强一致性的追求,而实现终究一致性,来换取必定的可用性。

  • 根本可用(Basically Available):体系确保在呈现毛病或许异常状况时,依然能够确保根本的可用性,即体系能够正常呼应用户请求,可是或许会呈现一些数据的不一致或许过错。
  • 软状况(Soft State):体系中的数据状况不需要是强一致性的,即答应数据在一段时刻内处于中间状况,而不是有必要确保数据在任何时刻点都是完全一致的。这样能够进步体系的可扩展性和容错性。
  • 终究一致性(Eventual Consistency):体系确保终究会到达一致性状况,可是在数据更新后,不同节点之间或许存在一段时刻的数据不一致。这种不一致是暂时的,随着时刻的推移会逐步被修复,直到所有节点都到达一致性状况。

BASE的规划理念是为了满意大规模分布式体系的需求,它与ACID的规划理念不同,不要求在所有状况下都严格确保数据的一致性,而是答应在某些状况下献身一部分的一致性,以换取更高的可用性可扩展性。可是,在实践的应用中,需要依据具体的业务需求和体系特色,挑选合适的数据办理体系规划理念,综合考虑数据的一致性、可用性和可扩展性等方面的要素。

CAP

CAP是指分布式体系中三个根本特性的缩写:

  • 一致性(Consistency):所有节点在同一时刻看到的数据是一致的,即所有节点都具有相同的数据副本。在分布式体系中,这意味着在进行更新操作之后,所有节点有必要终究到达一致的状况。
  • 可用性(Availability):体系能够在任何时刻点正常呼应用户请求,即体系的服务不会由于某些异常状况而停止呼应。
  • 分区容错性(Partition tolerance):分布式体系能够在网络分区或许节点毛病的状况下持续运转。这意味着体系在遇到网络分区或许节点毛病时,依然能够确保数据的一致性和可用性。

CAP理论指出,在一个分布式体系中,最多只能同时满意其间的两个特性,而不能同时满意所有三个特性。因此,当体系遇到网络分区或许节点毛病时,分布式体系需要做出权衡,挑选满意一致性和可用性中的哪一个特性,然后确保体系的正确性和可靠性。假如挑选了分区容错性,那么体系或许会呈现数据不一致的状况;假如挑选了一致性和可用性,那么体系或许会呈现停机和延迟呼应等问题。

在实践的分布式体系中,需要依据具体的业务需求和体系特色,挑选合适的CAP特性,综合考虑数据的一致性、可用性和容错性等方面的要素。

数据库并发业务存在问题

脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)都是数据库中的并发操控问题,首要影响业务的阻隔性。

  • 脏读(Dirty read):指一个业务读取了另一个业务还未提交的未经提交的数据。假如另一个业务回滚,那么第一个业务读取的数据便是无效的,这或许会导致数据的不一致性。
  • 不可重复读(Non-repeatable read):指一个业务在读取同一行记载时,不同时刻内读取到的数据不一致。这是由于在两次读取之间,另一个业务修正或删除了该行记载。
  • 幻读(Phantom read):指一个业务在读取一组记载时,第2次读取时发现多了或少了一些记载。这是由于在两次读取之间,另一个业务插入了一些记载或许删除了一些记载。

脏读、不可重复读、幻读都是由于并发业务之间的竞赛而导致的问题,能够通过加锁或许运用更高等级的阻隔等级来解决。

数据库阻隔等级

SQL 标准的业务阻隔等级包含:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。

  • 读未提交是指,一个业务还没提交时,它做的改变就能被别的业务看到。
  • 读提交是指,一个业务提交之后,它做的改变才会被其他业务看到。
  • 可重复读是指,一个业务履行进程中看到的数据,总是跟这个业务在启动时看到的数据是一致的。当然在可重复读阻隔等级下,未提交改变对其他业务也是不可见的。
  • 串行化,顾名思义是对于同一行记载,“写”会加“写锁”,“读”会加“读锁”。当呈现读写锁抵触的时分,后拜访的业务有必要等前一个业务履行完成,才干持续履行。

阻隔等级解决并发问题

MYSQL系列-基本概念和SQL执行过程

数据库默许阻隔等级

MYSQL

默许阻隔等级是可重复读

mysql> show variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.01 sec)
mysql> show global variables like 'transaction_isolation';
+-----------------------+-----------------+
| Variable_name         | Value           |
+-----------------------+-----------------+
| transaction_isolation | REPEATABLE-READ |
+-----------------------+-----------------+
1 row in set (0.00 sec)

延伸:SESSION阻隔等级是指在一个 MySQL 会话中,能够通过设置阻隔等级来操控该会话中的业务阻隔等级。在同一个 MySQL 实例中,不同会话能够设置不同的阻隔等级。能够运用以下指令来设置 SESSION 阻隔等级:

SET SESSION TRANSACTION ISOLATION LEVEL <isolation_level>;

其间,isolation_level 表示要设置的阻隔等级,能够是 READ UNCOMMITTED、READ COMMITTED、REPEATABLE READ或 SERIALIZABLE。

ORACLE

Oracle默许的阻隔等级是读已提交(Read Committed)

一条查询SQL履行进程

SQL句子履行全体流程如下,在前面的全体架构图中也介绍过

MYSQL系列-基本概念和SQL执行过程

客户端

客户端首要是通过MYSQL驱动来和数据库进行通讯,MySQL 驱动是一种软件组件,用于在应用程序和 MySQL 数据库之间树立衔接,以便应用程序能够拜访和操作 MySQL 数据库。MySQL 驱动一般有以下几种类型:
JDBC驱动(Java Database Connectivity)、ODBC驱动(Open Database Connectivity)、Connector/C 驱动等 客户端需要频频运用数据库衔接,采用池化技术-数据库衔接池来进行办理:维护必定的衔接数,方便体系获取衔接,运用就去池子中获取,用完放回去就能够了,咱们不需要关怀衔接的创建与毁掉,也不需要关怀线程池是怎样去维护这些衔接的。

MYSQL系列-基本概念和SQL执行过程
常见的数据库衔接池有 Druid、C3P0、DBCP,后面有一节专门叙述

衔接器

衔接器担任跟客户端树立衔接、获取权限、维持和办理衔接。
指令如下:

/home/mysql/mysql3306/bin/mysql -uroot -p -S /home/mysql/mysql3306/mysqld.sock

衔接指令中的 mysql 是客户端东西,用来跟服务端树立衔接。在完成经典的 TCP 握手后,衔接器就要开端认证你的身份,这个时分用的便是你输入的用户名和暗码。

  • 假如用户名或暗码不对,你就会收到一个”Access denied for user”的过错,然后客户端程序完毕履行。
  • 假如用户名暗码认证通过,衔接器会到权限表里边查出你具有的权限。之后,这个衔接里边的权限判别逻辑,都将依赖于此时读到的权限

划要点:一个用户成功树立衔接后,即使你用办理员账号对这个用户的权限做了修正,也不会影响现已存在衔接的权限。修正完成后,只有再新建的衔接才会运用新的权限设置。

show processlist 能够检查当时衔接

mysql> show processlist;
+----+------+---------------------------+------+---------+------+----------+------------------+
| Id | User | Host                      | db   | Command | Time | State    | Info             |
+----+------+---------------------------+------+---------+------+----------+------------------+
|  2 | root | localhost                 | NULL | Query   |    0 | starting | show processlist |
|  8 | root | TOBY-HYW.mshome.net:24708 | NULL | Sleep   |   27 |          | NULL             |
|  9 | root | TOBY-HYW.mshome.net:24709 | NULL | Sleep   |   27 |          | NULL             |
+----+------+---------------------------+------+---------+------+----------+------------------+
3 rows in set (0.00 sec)

客户端假如太长时刻没动静,衔接器就会自动将它断开。这个时刻是由参数 wait_timeout 操控的,默许值是 8 小时。

mysql> show variables like 'wait_timeout';
+---------------+-------+
| Variable_name | Value |
+---------------+-------+
| wait_timeout  | 28800 |
+---------------+-------+
1 row in set (0.01 sec)

树立衔接的进程一般是比较复杂的,所以我主张你在运用中要尽量削减树立衔接的动作,也便是尽量运用长衔接。 MySQL 占用内存涨得特别快,这是由于 MySQL 在履行进程中临时运用的内存是办理在衔接目标里边的。这些资源会在衔接断开的时分才释放。解决此问题:

  1. 定时断开长衔接。运用一段时刻,或许程序里边判别履行过一个占用内存的大查询后,断开衔接,之后要查询再重连。
  2. 假如你用的是 MySQL 5.7 或更新版别,能够在每次履行一个比较大的操作后,通过履行 mysql_reset_connection 来从头初始化衔接资源。这个进程不需要重连和从头做权限验证,可是会将衔接康复到刚刚创建完时的状况。

查询缓存

命中则直接完毕,一般不运用。查询缓存的失效十分频频,只要有对一个表的更新,这个表上所有的查询缓存都会被清空。query_cache_type(OFF|ON|DEMAND 按需,运用select SQL_CACHE * from T where ID=10显示指定)操控 默许是封闭的

mysql> show variables like 'query_cache_type';
+------------------+-------+
| Variable_name    | Value |
+------------------+-------+
| query_cache_type | OFF   |
+------------------+-------+

MySQL 8.0 版别直接将查询缓存的整块功用删掉了,也便是说 8.0 开端彻底没有这个功用了。

分析器

词法分析、语法分析 假如你的句子不对,就会收到“You have an error in your SQL syntax”的过错提醒

优化器

优化器是在表里边有多个索引的时分,决议运用哪个索引;或许在一个句子有多表关联(join)的时分,决议各个表的衔接顺序。

履行器

MySQL 通过分析器知道了你要做什么,通过优化器知道了该怎样做,所以就进入了履行器阶段,开端履行句子。

开端履行的时分,要先判别一下你对这个表有没有履行查询的权限,假如没有,就会回来没有权限的过错, 假如有权限,就翻开表持续履行。翻开表的时分,履行器就会依据表的引擎定义,去运用这个引擎供给的接口。

引擎层

供给接口给履行层运用,分为多个履行引擎,后面独自叙述

问题解答

问题1

假如表 T 中没有字段 k,而你履行了这个句子 select * from T where k=1, 那肯定是会报“不存在这个列”的过错: “Unknown column ‘k’ in ‘where clause’”。你觉得这个过错是在咱们上面提到的哪个阶段报出来的呢?

答案:分析器

一条更新SQL履行进程

更新SQL和查询SQL在server层是一样的(在查询缓存时将缓存失效调),在引擎层不一样,更新流程还涉及两个重要的日志模块

参阅
1.一条SQL句子是怎么履行的
2.MySQL – 一条 SQL 的履行进程详解