该系列用于记录在工作中的一些技能补全。什么技能?大概是前端所缺的很多的知识和技术吧。本节我们一起来了解下数据库。

# 认识数据库

以前对数据库的了解,大概就是一个存放数据的地方,可进行增删查改,更多的就...慢慢学吧。

# 数据库事务

# 事务是什么

所谓事务是用户定义的一个数据库操作序列,这些操作要么全做要么全不做,是一个不可分割的工作单位。

一个数据库事务通常包含了一个序列的对数据库的读/写操作。它的存在包含有以下两个目的:

  • 为数据库操作序列提供了一个从失败中恢复到正常状态的方法,同时提供了数据库即使在异常状态下仍能保持一致性的方法。
  • 当多个应用程序在并发访问数据库时,可以在这些应用程序之间提供一个隔离方法,以防止彼此的操作互相干扰。

当事务被提交给了 DBMS(数据库管理系统),则 DBMS(数据库管理系统)需要确保该事务中的所有操作都成功完成且其结果被永久保存在数据库中,如果事务中有的操作没有成功完成,则事务中的所有操作都需要被回滚,回到事务执行前的状态;同时,该事务对数据库或者其他事务的执行无影响,所有的事务都好像在独立的运行。

# ACID 的事务

并非任意的对数据库的操作序列都是数据库事务。数据库事务拥有以下四个特性,习惯上被称之为 ACID 特性。

# 原子性(Atomicity)

事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
一个事务是不可分割的,事务中的任何一条 SQL 执行失败,已经执行成功的语句也必须撤销,状态回退到执行事务之前。

# 一致性(Consistency)

事务应确保数据库的状态从一个一致状态转变为另一个一致状态。例如银行转账,保证事务结束后总数量不变。
一致状态的含义是数据库中的数据应满足完整性约束,事务开始和结束之间的中间状态不会被其他事务看到。

# 隔离性(Isolation)

多个事务并发执行时,一个事务的执行不应影响其他事务的执行。

# 持久性(Durability)

已被提交的事务对数据库的修改应该永久保存在数据库中。

一般来说,事务的 ACID 由 RDBMS 来实现的,RDBMS 采用日志来保证事务的原子性,一致性,持久性。采用锁的机制来实现事务的隔离性。

# 事务的隔离级别

在事务并发操作时,可能出现的问题有:

  • 脏读:事务 A 修改了一个数据,但未提交,事务 B 读到了事务 A 未提交的更新结果,如果事务 A 提交失败,事务 B 读到的就是脏数据。
  • 不可重复读:在同一个事务中,对于同一份数据读取到的结果不一致。比如,事务 B 在事务 A 提交前读到的结果,和提交后读到的结果可能不同。不可重复读出现的原因就是事务并发修改记录,要避免这种情况,最简单的方法就是对要修改的记录加锁,这回导致锁竞争加剧,影响性能。另一种方法是通过 MVCC 可以在无锁的情况下,避免不可重复读。
  • 幻读:在同一个事务中,同一个查询多次返回的结果不一致。事务 A 新增了一条记录,事务 B 在事务 A 提交前后各执行了一次查询操作,发现后一次比前一次多了一条记录。幻读是由于并发事务增加记录导致的,这个不能像不可重复读通过记录加锁解决,因为对于新增的记录根本无法加锁。需要将事务串行化,才能避免幻读。

ANSI/ISO SQL 定义的标准隔离级别有四种,从高到底依次为:可序列化(Serializable)、可重复读(Repeatable reads)、提交读(Read committed)、未提交读(Read uncommitted)。

# 未提交读(Read uncommitted)

最低的隔离级别,什么都不需要做,允许脏读,也就是可能读取到其他会话中未提交事务修改的数据。所有的并发事务问题都会发生。

# 提交读(Read committed)

只有在事务提交后,其更新结果才会被其他事务看见。可以解决脏读问题。Oracle 等多数数据库默认都是该级别 (不重复读)。

# 可重复读(Repeatable reads)

在一个事务中,对于同一份数据的读取结果总是相同的,无论是否有其他事务对这份数据进行操作,以及这个事务是否提交。MySQL/InnoDB 默认级别,可以解决脏读、不可重复读。

# 可序列化(Serializable)

事务串行化执行,隔离级别最高,牺牲了系统的并发性。可以解决并发事务的所有问题。

# 数据库索引

# 什么是索引

数据库索引是怎样提升性能的?使用索引的全部意义就是通过缩小一张表中需要查询的记录/行的数目来加快搜索的速度。可以把数据库索引比作书的目录索引,当我们需要在一本动物百科里寻找秋田犬的时候,可以通过目录快速定位到具体的位置。

数据库索引,是数据库管理系统中一个排序的数据结构,以协助快速查询、更新数据库表中数据。

# 索引是什么

一个索引是存储的表中一个特定列的值数据结构(最常见的是 B-Tree)。索引是在表的列上创建。所以,要记住的关键点是索引包含一个表中列的值,并且这些值存储在一个数据结构中。

数据库管理系统(RDBMS)通常决定索引应该用哪些数据结构。但是,在某些情况下,你在创建索引时可以指定索引要使用的数据结构。

# B-Tree 索引

B-Tree 是最常用的用于索引的数据结构。因为它们是时间复杂度低, 查找、删除、插入操作都可以可以在对数时间内完成。另外一个重要原因存储在 B-Tree 中的数据是有序的。

# 哈希索引

哈希表是另外一种你可能看到用作索引的数据结构——这些索引通常被称为哈希索引。使用哈希索引的原因是,在寻找值时哈希表效率极高。

哈系索引的工作方式是将列的值作为索引的键值(key),和键值相对应实际的值(value)是指向该表中相应行的指针。所以,如果使用哈希索引,对于比较字符串是否相等的查询能够极快的检索出的值。

哈希表是无顺的数据结构,对于很多类型的查询语句(范围查询)哈希索引都无能为力。哈希表的键值映射也暗示其键的存储是无序的。这就是为什么哈希索引通常不是数据库索引的默认数据结构——因为在作为索引的数据结构时,其不像 B-Tree 那么灵活。

# R-Tree

使用 R-Tree 作为数据结构的索引通常用来为空间问题提供帮助。例如,一个查询要求“查询出所有距离一公里之内的超市”,如果数据库表使用 R-Tree 索引,这类查询的效率将会提高。

# 位图索引

位图索引(bitmap index)适合放在包含布尔值(true 和 false)的列上,但是这些值(表示 true 或 false 的值)的许多实例-基本上都是选择性(selectivity)低的列。

# 合理使用索引

数据库索引能提升性能,那当然它也会有一些缺点:

  1. 索引会占用空间 - 你的表越大,索引占用的空间越大。
  2. 性能损失(主要值更新操作),当你在表中添加、删除或者更新行数据的时候,在索引中也会有相同的操作。记住:建立在某列(或多列)索引需要保存该列最新的数据。

基本原则是只如果表中某列在查询过程中使用的非常频繁,那就在该列上创建索引。

# 索引类型

根据数据库的功能,可以在数据库设计器中创建三种索引:唯一索引、主键索引和聚集索引。

# 唯一索引

唯一索引是不允许其中任何两行具有相同索引值的索引。

当现有数据中存在重复的键值时,大多数数据库不允许将新创建的唯一索引与表一起保存。数据库还可能防止添加将在表中创建重复键值的新数据。

# 主键索引

数据库表经常有一列或列组合,其值唯一标识表中的每一行。该列称为表的主键。

在数据库关系图中为表定义主键将自动创建主键索引,主键索引是唯一索引的特定类型。该索引要求主键中的每个值都唯一。当在查询中使用主键索引时,它还允许对数据的快速访问。
当表中只有一个主键时,它是唯一的索引;当表中有多个主键时,称为复合主键,复合主键联合保证唯一索引。

# 主键索引和唯一索引的区别

  • 主键是一种约束,唯一索引是一种索引,两者在本质上是不同的
  • 主键创建后一定包含一个唯一性索引,唯一性索引并不一定就是主键
  • 唯一性索引列允许空值,而主键列不允许为空值
  • 主键列在创建时,已经默认为非空值 + 唯一索引
  • 主键可以被其他表引用为外键,而唯一索引不能
  • 一个表最多只能创建一个主键,但可以创建多个唯一索引
  • 主键更适合那些不容易更改的唯一标识,如自动递增列、身份证号等

# 聚集索引

在聚集索引中,表中行的物理顺序与键值的逻辑(索引)顺序相同。一个表只能包含一个聚集索引。

如果某索引不是聚集索引,则表中行的物理顺序与键值的逻辑顺序不匹配。与非聚集索引相比,聚集索引通常提供更快的数据访问速度。

# 参考

# 结束语

关于数据库的事务和索引,也算是比较基础的内容了,但对本骚年来说也是不大了解。
一下子学这么多,有点消化不过来,本节就先介绍数据库事务和索引,文章大多数都是参考来的内容,很多也需要好好理解。

部分文章中使用了一些网站的截图,如果涉及侵权,请告诉我删一下谢谢~
温馨提示喵