数据库索引,事物,隔离级别(脏读,幻读,不可重复读)

本文详细介绍了MySQL数据库中的索引概念、优势与使用,包括自动索引、手动创建与管理,以及针对InnoDB存储引擎的索引数据结构。此外,文章还探讨了数据库事务的原子性、一致性、持久性和隔离性,以及不同隔离级别的应用场景和影响。
摘要由CSDN通过智能技术生成
  • 本文讲解的数据库为MYSQL

数据库索引

1. 索引是什么

在我们平时看书的过程中,一般第一页都是这本书的目录,以便我们快速定位章节和内容,同理数据库的索引,就是用来创建数据库查询目录的以列为维度进行设置的,以便来维护数据库查询的速度

索引的优势

  • 可以提高查询的速度

劣势

  • 会占用额外的空间,有额外的内存损耗

2. 索引的使用

在我们平时的数据库操作中,以下3种方式数据库会默认为该列加上索引

  1. 主键(Primary Key)
  2. 外键(Foreign Key)
  3. unique

如果项目有需求我们需要手动创建为一列创建索引的话,我们可以使用

//创建数据库索引
create index 索引名 on 表名(列名);
//删除数据库索引
drop index 索引名 on 表名;
//查询索引
show index from 表名;

需要注意的是,在一般的业务场景下,如果我们要为一列添加索引的话,最好一开始就进行添加,要是表中数据量过大,添加和删除索引很容易造成程序的卡顿和服务器给挂掉。

3. 索引的数据结构

这一小节 我们是针对mysql常用存储引擎innodb来进行讨论的, 其他存储引擎使用的数据结构可能会有差异,同时这里提到的数据结构也不做展开叙述 后面可能出一个板块单独进行叙述

1.hashmap

因为考虑数据库最常用的操作是查询,所以这里我们应该首先想到的数据结构是hashmap,他的查询时间复杂度是O(1),但是呢 数据库实际上没有采取哈希表进行存储数据,因为在数据库进行查询的过程中,通常会涉及到like和where这类模糊查询,这是hashmap解决不了的问题.(其他数据库存储引擎可能使用了 但是innodb没有)

2.红黑树

数据库不使用红黑树的原因是,因为红黑树虽然是平衡二叉树同时也是一个查询结构,但是一般的数据库中存储的数据是非常巨大的,可能达到千万级别的数量,所以存储数据量过大的时候,红黑树的深度也会很深,又因为数据库的操作是硬盘上的操作,和内存相比每一次都会消耗大量的I/O,所以红黑树并不适合于数据库的底层数据结构.

3.B树和B+树

上述结构都不符合 为了优化上述结构最后数据库使用了B+树来作为了底层的数据结构,B+树是一种搜索类数据结构。(这里不对B树和B+树做过多的介绍,后面可能会专门写一篇数据结构的)因为B+树一个节点可以存储多个元素的特性,会让树的深度很浅,所以硬盘的I/O开销相对来说会小很多,同时B+树的每一个叶子节点,都通过了链表相连接,所以在查询性能的基础上还可以做到实现模糊匹配这一功能。

2.数据库事务

有时我们为了完成一个操作,可能会涉及到多行sql,比如我有一个账户来进行游戏内的金币交易操作  假设有以下数据库的表 game

  • name    coins
  •    A         500
  •    B        500

此时A对B转了300个金币,此时我们应该是

  1. updata game set coins = coins - 300 where name = A;
  2. updata game set coins = coins + 300 where name = B;

上述操作应该是都完成以后,这个业务才算成功完成,但是要是在我们执行代码的途中,执行完第一条指令之后,还没开始执行第二条语句的时候,程序突然给崩了。 那对A而言自己的钱已经减少了300个金币了 ,但是B又没有成功收到这300个金币。此时这种情况明显是不可取的,为了解决上述情况,于是在数据库中引入了事务操作,什么是事务呢?通俗一点来讲,就是把多个操作打包成一个操作进行执行. 如果其中有一个操作执行失败了,前面已经执行的sql语句便不会进行执行,而是会回滚到整个事务开始执行前的时候。

就拿上述转金币的过程举例,要是上述过程中A第一条sql已经执行成功,但是执行第二条指令的时候程序崩溃了,此时的结果便会回到第一条sql语句执行前,也就是A的金币此时也不会实际进行扣除.这个操作就叫做回滚(rollback)

//开启事务
commit 
//中间的操作全为事务处理操作
......
//手动回滚事务
rollback

事务的操作必须以上述为开头和结尾,但是在实际开发过程中,一般事务的开启都是在代码中体现的,并不会真正在数据库这边写 一般情况下。

事务的基本特性

面试常考

  • 原子性:事务保证了多个操作被打包成为了一个操作
  • 一致性:事务开始前和事务结束后数据能对上
  • 持久性:事务里面的操作,要是执行成功所有的结果都会写入硬盘
  • 隔离性:并发执行事务的时候会在执行效率和数据可靠之间做出选择

事务的隔离性越高,并发性就越低,同时数据也就越可靠

隔离性会在下面的隔离等级做出详细的解释

3. 隔离级别

3.1 脏读

在了解到上述事务的特征和本质后。

此时我们假设有2个事务正在并发执行。还是用到了上述的表结构和操作语句

假设有以下数据库的表 game

  • name    coins
  •    A         500
  •    B        500

此时A对B转了300个金币,此时我们应该是

  1. updata game set coins = coins - 300 where name = A;
  2. updata game set coins = coins + 300 where name = B;

然后B事务此时在我执行第一条sql的时候,对数据进行了读取。他读取到A此时的金币数量应该为200,但是又因为程序崩溃导致事务回滚了。A的数据应该还是原有的500.就导致了其他事务读取到了一个虚假的信息。

为了防止脏读,我们可以采取,事务在进行写入(修改)操作的时候,其他事务不允许读取当前事务还未提交的数据. 写加锁操作

3.2 不可重复读

在不可重复读的时候,我们假设程序已经做出了针对于脏读的限定,也就是事务在修改数据的时候,如果未提交,其他事务不能访问该事务里面的数据内容.(写加锁操作)

数据在事务操作过程中,可能会涉及到多个读的过程,多次读的过程中,读取到的数据不一致就是不可重复读。

通俗来讲,此时假设有B事务在执行一个操作,他需要查询5次A金币的数量,查询到第三次的时候这时另外一个事物突然执行了上述转金币的操作. 按照约定,在A做修改的时候无法对A进行读取,但是,一旦当A事务执行完毕之后,我本来前三次读取A的金币是500的,但是我后面继续读取数据的时候,A的金币突然变成200了。就可能会导致一系列的问题.

为了防止不可重复,我们可以在读取数据的时候也进行加锁.也就是读加锁操作. 我们在读取这个数据的时候,其他事务不能对这个数据进行修改操作

3.3 幻读

在讲幻读的时候,我们假设程序已经做出了解决脏读和不可重复读的情况,进行了读加锁和写加锁

一个事物在多次读取同一个表的情况下,此时有一个另外一个事物,往表里插入或者删除了一条数据,此时导致多次读取的结果不一致,就称为幻读.

解决幻读只有彻底放弃事务并发执行,改为串行化(也就是事务执行的时候一个挨一个)

3.4 隔离级别

为了解决上述问题,MYSQL引入了隔离级别这个概念

  • read uncommitted 

他允许读取未提交的事物,也就是上述的三大问题,一个也无法防止,但是这样做,事务执行的并发性最好,效率最高,但数据不一定准确

  • read committed

只允许读取提交的事物了,他对事物进行了写加锁,解决了上述的脏读问题,但是剩下2个问题仍然存在.同时他的并发性相比于上一个等级,略有下降,同时数据可靠性会高一些。

  • repeatable read

可以重复读取数据 ,他对事物进行了读加锁和写加锁,解决了上述的脏读和不可能重复读的问题,但是幻读的问题仍然未解决. 同时他的并发性相比于上一个等级,略有下降,同时数据可靠性会高一些。

  • serializable

事务的串行执行,开始之后,事务不能进行并发执行了,但可以解决上述三大问题,同时开启之后,效率最低,但是数据可靠性最高。

  • 28
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值