提示:以下是本篇文章正文内容,Java系列学习将会持续更新
一、索引
1-1 什么是索引?
索引是一种特殊的文件,包含着对数据表里所有记录的引用指针。可以对表中的一列或多列创建索引, 并指定索引的类型,各类索引有各自的数据结构实现。
1-2 作用和使用场景
作用:
- 数据库中的表、数据、索引之间的关系,类似于书架上的图书、书籍内容和书籍目录的关系。
- 索引所起的作用类似书籍目录,可用于快速定位、检索数据。
- 索引对于提高数据库的性能有很大的帮助。
使用场景:
- 数据量较大,且经常对这些列进行条件查询。
- 该数据库表的插入操作,及对这些列的修改操作频率较低。
- 磁盘空间足,索引会占用额外的磁盘空间。
- 当有索引的情况下,大量数据的插入会变得相当慢。可以等删除索引、等插完数据、再重新构建。
满足以上条件时,考虑对表中的这些字段创建索引,以提高查询效率。
反之,如果非条件查询列,或经常做插入、修改操作,或磁盘空间不足时,不考虑创建索引。
1-3 如何构建索引?
索引的分类:
- 主键索引: 也简称主键。它可以提高查询效率,并提供唯一性约束。一张表中只能有一个主键。
- 普通索引:就是普普通通的索引。
- 唯一索引:索引的值不能重复。
- 复合索引:在工作中用得比较频繁的一个索引;
创建方式: 复合索引中的索引的顺序是非常重要的;
创建索引:
// 使用 create index 命令创建
create index 索引名 on 表名(列名);
// 使用 alter table 命令去增加索引
alter table 表名 add index 索引名 (字段1 ASC, ...);
案例:
-- 构建索引
ALTER TABLE `searcher`.`inverted_indexes`
ADD INDEX `INDEX_word_weight` (`word` ASC, `weight` DESC);
;
查看与删除:
//2,查看索引
show index from 表名;
//3,删除索引
drop index 索引名 on 表名;
1-4 底层原理
数据库索引的底层数据机构是 B+树
。
先认识一下
B树
B树
又可以叫做N叉搜索树
,每个节点上最多可能会有N-1个值,N-1个值,那就把这个节点划分为了N个区间,每一个区间下,又会衍生出子节点,子节点的值就在这个范围内。
这种N叉树的结构,一个节点可以存多个值,相对于二叉搜索树,把树的高度大大降低,查询次数也就会相应降低,降低了硬盘IO。
那为什么不选择B树呢?
因为它涉及到一个分裂
和合并
的过程,如果说你插入了值,那么可能范围符合但是该节点已经放满,所以可能会需要分裂出一个新的节点来进行存放。同理删除值后如果某个节点的元素个数太少,符合范围条件的节点需要进行合并,整个过程的操作比较复杂。
那就引出了
B+树
对于B+树来说,也是一个N叉搜索树,只不过每个节点上就N个值,分出N个区间,并且父节点的元素会在子节点中以最大值或者最小值的形式出现在子节点中。最后最重要的一个特点,在最底层的叶子节点上,B+树会把所有的叶子节点以链表的形式连接起来。其实我们会发现,B+树的叶子节点上,已经保存了整棵树所有的值,并且是排序好的
。所以这个时候,对于我们的范围查找就很友好了,只需要去遍历链表,然后根据范围截取出子链表就好了。
最厉害的一个点,既然我们的叶子节点是全集数据,所以我们就只需要把我们的每一行记录关联到每一个叶子节点上,然后非叶子节点上就只存放索引列的值,所以相应的非叶子节点占用的空间就比较小,这个时候就可以直接把非叶子节点缓存到内存里面,然后直接在内存里面去遍历查找我们的非叶子节点(索引列),找到相应的范围之后去硬盘访问相应的记录即可,这个时候相对于B树,查找速度又加快了,硬盘IO也进一步得到了降低。
二、事务
2-1 什么是事务?
在数据库里面,我们希望有些操作能够以原子的方式进行,要么都能执行成功,要么就都不执行,也就是只能是一个整体的被执行,这样的一组具有原子性的操作我们就称之为 事务 。事务就是来保证原子性的,原子性就是事务的核心。
事务存在的意义就是能够使得我们多个数据库操作(SQL语句)能够以原子的方式去执行。在事务的执行过程中,MySQL会记录每一步操作都干了啥,当执行过程中出现问题的时候,我们的回滚机制rollback可以让我们的数据恢复如初,也就是相当于没有执行过一样。
2-2 事务的特征
事务应该具有4个属性:原子性、一致性、隔离性、持久性。这四个属性通常称为ACID
特性。
特征 | 说明 |
---|---|
原子性 (atomicity) | 一个事务是一个不可分割的工作单位,事务中包括的操作要么都做,要么都不做。 |
一致性 (consistency) | 业务方来定义的,针对数据整体做的不可变承诺。事务必须是使数据库从一个一致性状态变到另一个一致性状态。一致性与原子性是密切相关的。 |
隔离性 (isolation) | 当多个事务对同一资源同时操作时,一个事务的执行不能被其他事务干扰。这里的同时只是宏观上的表现,实际上也就是微观上同一时刻只有一个事务在执行,而其它事务是在等待中。 |
持久性 (durability) | 指一个事务一旦提交,它对数据库中数据的改变就应该是永久性的。接下来的其他操作或故障不应该对其有任何影响。 |
DBMS只有满足这4条特征,才能称为支持事功能。
2-3 隔离级别
更追求隔离性(数据更正确) | ----------------------------- | ---------------------------------------------------- | -----------------------------------> | 更追求并发性(性能更高) |
---|---|---|---|---|
(可串行性)serializable |
(快照读)snapshot_read |
(可重复读)repeatable_read |
(读已提交)read_committed |
(读未提交)read_uncommitted |
这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。 |
不是标准中存在的隔离级别,目前来说,没有副作用。 MySQL中的可重复读就是实际上的快照读。因为MVCC机制解决了幻读。 |
这是MySQL的默认事务隔离级别,它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。不过理论上,这会导致另一个棘手的问题:幻读。幻读指 当用户修改某一范围的数据行时,另一个事务又在该范围内插入了新行,当用户再读取该范围的数据行时,会发现有一条未修改的数据“幻影” 。 |
它满足了隔离的简单定义:一个事务只能看见已经提交事务所做的改变。不可重复读副作用: 一个事务多次读取同一数据可能会得到多个不同的结果 。 |
在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。 读取未提交的数据,也被称之为 脏读 。相当于完全破坏了隔离性。 |
2-4 使用事务
①SQL使用事务
-- 开启事务
start transaction;
SQL1;
SQL2;
rollback; -- 主动回滚
-- 开启事务
start transaction;
-- 这3条sql语句共同构成一个事务,要么都能执行,要么都不能成功执行
SQL1;
SQL2;
SQL3;
-- 如果sql1和sql2执行成功,但sql3执行失败,则该事务结束后,被修改的数据会回滚
commit; -- 提交事务,代表事务完成 (事务失败会回滚)
②JDBC使用事务
// 要使用事务,在同一个事务中,操作 sql1 和 sql2,意味着必须在一条 Connection 完成
try (Connection c = DBUtil.connection()) {
// connection 中有一个自动提交(autocommit)的属性,默认情况下是 true(开启)
// 开启状态下,意味着,每一条 sql 都会被独立的视为一个事务
// 我们要让 sql1 和 sql2 看作整体,只需要关闭 connection 的自动提交
c.setAutoCommit(false);
// 此时就可以手动的控制事务的结束位置,并且需要手动提交
try (PreparedStatement ps = c.prepareStatement(sql1)) {
ps.executeUpdate();
}
try (PreparedStatement ps = c.prepareStatement(sql2)) {
ps.executeUpdate();
}
// 由于我们关闭了自动提交了,所以,所有的修改还没有真正地落盘
c.commit(); // 只有加上这句话,才表示事务被提交了(数据真正落盘了)
}
总结:
提示:这里对文章进行总结:
以上就是今天的学习内容,本文是MySQL的学习,认识了索引和事务,如何使用索引和事务,以及索引的底层原理、事务的四大特征。之后的学习内容将持续更新!!!