Createsequence's Blog

一个努力前进的程序猿


  • 首页

  • 标签

  • 分类

  • 归档

  • 搜索

《MySQL45讲》读书笔记(七):全局锁,表锁,行锁,间隙锁

发表于 2020-11-03 | 分类于 mysql
字数统计: 5.7k

此文为极客时间:MySQL实战45讲的 6、7、20 节锁相关部分的总结

一、全局锁

1.概述

全局锁就是对整个数据库实例加锁。通过使用 Flush tables with read lock(FTWRL)语句加锁,此后整个库都会处于只读状态,这时,其他线程的数据定义语句(DDL),数据操作语句(DML)以及更新类事务的提交语句都会被阻塞。

也就是说,加了全局锁以后,其他线程不能对数据增删改,也不能对表增删改。

另外值得一提的是,在此之前,数据库会等待 FTWRL 操作前的所有读写操作完成,事务提交完毕;并且把脏页的数据从缓存刷入磁盘,保证数据的一致性。

全局锁的典型使用场景是对数据库进行整库备份。

2.全局锁的缺陷和解决方案

全局锁有以下问题:

  • 如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
  • 如果你在从库上备份,那么备份期间从库不能执行主库同步过来的 binlog,会导致主从延迟。
阅读全文 »

《MySQL45讲》读书笔记(六):数据库事务概述

发表于 2020-11-02 | 分类于 mysql
字数统计: 3.8k

此文为极客时间:MySQL实战45讲的 3、8、18、19节事务相关部分的总结

一、事务的启动方式

mysql 主要有两种事务的启动方式:

  1. begin 或 start transaction显式启动事务。对应的提交语句是 commit ,回滚是 rollback
  2. set autocommit = 0关闭自动提交,然后在执行第一条 sql 的时候启动事务,这个事务会一直持续到你主动 commit 或者 rollback,或者断开连接才会结束。

有一些客户端连接框架会在连接成功后默认修改设置,这可能导致意外的长事务。因此,显示启动事务明显是比较安全的,但是对于一些需要频繁使用事务的业务,每次都需要调用 begin 然后再 commit。对于这种情况,可以使用 commit work and chain,当 autocommit = 1时,使用该语句可以在提交以后自动开启下一个新事务。

这样省去了再次执行 begin 语句的开销,而且可以明确地知道每个语句是否处于事务中。

除此之外,我们还可以使用 sql 去在 information_schema 库的 innodb_trx 这个表中查询长事务:

1
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started)) > 60

比如上面这条语句,就是用于查找持续时间超过 60s 的事务

二、事务的隔离级别

阅读全文 »

《MySQL45讲》读书笔记(五):数据库表空间的回收

发表于 2020-10-30 | 分类于 mysql
字数统计: 1.8k

此文为极客时间MySQL实战45讲第13节的笔记

一、表数据的存放位置

表数据既可以存在共享表空间里,也可以是单独的文件。这个行为是由参数 innodb_file_per_table 控制的:

  1. OFF :表的数据放在系统共享表空间,即跟数据字典放在一起;
  2. ON :表数据存储在一个以 .ibd 为后缀的文件中。(MySQL 5.6.6 默认为 ON)

一般情况下,表单独存放的时候,可以通过 drop table 语句直接删除,而如果放在共享表空间,及时删除了表也无法回收空间。

二、表数据的删除

一般情况下,很少有直接连结构带数据直接删掉表的情况,更多时候是只删除一些数据,但是这样往往会遇到这样的问题:表中的数据被删除了,但是表空间却没有被回收。

实际上,这与 innodb 中数据都以 B+ 树的结构存储有关:

image-20201105203027271
image-20201105203027271

以上图为例,如果我们删除 R4 这条数据,则 innodb 会把 R4 这个位置标记为删除,之后如果插入一个在 300~600 的记录的时候,就会直接使用现在 R4 的位置。同理,如果我们清除这个 PageA,那么这个数据页都会被标记删除,等到下一个数据页加载的时候就可以直接使用这个空间。而当两个相邻的数据页上被删除了记录很多,也就是页的利用率都很低的时候,系统就会自动合并两个页的数据,并且标记其中一个为可复用。

阅读全文 »

JDK1.8新特性(三):Lambda表达式

发表于 2020-10-30 | 分类于 java
字数统计: 2.2k

概述

JDK8 为我们带来了 Lambda 表达式和函数式接口,这一点在前文介绍 Stream 和 Collectors 的时候已有提及。通过使用这些特性,我们可以更简洁的创建匿名内部类,也可以将方法作为参数直接传入方法中调用。本文将就这两点简要的总结一下 Lambda 的使用。

一、函数式接口

我们知道,java 中允许将接口作为方法的参数类型,但是我们只能传入其实现类。实际开发中,有些接口的仅有少数的方法,并且往往其实现类只在特定的地方使用,为此专门去创建一个新的实现类其实是有点繁琐的,为此 JDK8 引入了函数式接口。

函数式接口有且仅有一个抽象方法,抽象方法允许有一个默认实现(实际上接口的默认实现也是 JDK8 的新特性)。当我们调用方法时,可以直接通过 Lambda 表达式直接以匿名内部类的形式去实现他的方法。表现为直接在参数小括号中: void test(param1, () -> System.out.print("hello world"))

当使用作为方法参数类型是,通过在接口上添加@FunctionalInterface注解来声明。

我们举个例子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 函数式接口
@FunctionalInterface
public interface TestInterface {
void test();
}

// 将接口作为方法参数
public static void test(TestInterface testInterface){
// 有且仅有一个抽象方法
testInterface.test();
}

// 调用方法
test(()-> System.out.println("hello world"));

我们可以看到,实现的代码非常的简洁,对于一些不复杂的功能用起来非常方便,而如果使用原本的实现方式:

1
2
3
4
5
6
7
8
9
TestInterface testInterface = new TestInterface() {
@Override
public void test() {
System.out.println("hello world")
}
}

// 调用方法
test(testInterface);
阅读全文 »

《MySQL45讲》读书笔记(四):索引

发表于 2020-10-29 | 分类于 mysql
字数统计: 5.8k

此文为极客时间:MySQL实战45讲的 4、5、9、10、11、15、18节索引相关部分的总结

一、Innodb索引模型

1.主键/非主键索引的区别

每个索引在Innodb中都是一颗B+树,其中根据索引叶子节点的不同,分为主键索引和非主键索引。

image-20200930164149290
image-20200930164149290

我们可以看到:

  • 主键索引将索引和整行的数据都放在了一起,所以又叫聚簇索引
  • 非主键索引的叶子节点内容是主键的值。所以又叫二级索引

其中,如果非主键索引查询字段没有做到覆盖索引,就需要先从非主键索引树中找到对应的主键,然后再回到主键索引树找到对应的行数据,这个过程叫做回表。

而相应的,直接把全部的主键索引过一遍,然后每拿到一个主键索引,就把相应的数据拿出来,这个过程叫做全表扫描。

2.索引维护

阅读全文 »

《MySQL45讲》读书笔记(三):内存数据刷盘机制

发表于 2020-10-28 | 分类于 mysql
字数统计: 1.1k

此文为极客时间:MySQL实战45讲的12节的学习笔记

一、mysql 的刷盘机制

而之前提到过,mysql 使用了 WAL 技术,即更新的时候先更新内存中的数据,然后必要的时候再将内存中的数据刷入磁盘。我们把内存中这些被修改过,跟磁盘中的数据页不一致的数据页称为脏页。

其中,有四种情况会触发脏页的刷盘:

  1. redo log 可写空间满了。
  2. 内存满了,需要淘汰的数据页恰好是脏页。
  3. 系统不繁忙的时候。
  4. 关闭数据库的时候。

其中,第三种情况不会为系统带来过多影响的,第四中情况下不会在乎为系统带来的影响。所以我们只需要关注第一和第二种情况:

对于第二种情况,由于 mysql 的更新需要先写日志,所以当日志满了的情况下,所有的更新都会停止,一直到刷完盘日志腾出了空间为止;

而对于第二种情况,当查询的数据在内存中的数据页没有的时候,就需要淘汰旧页释放内存以读入新页,所以当一次查询导致需要淘汰的脏页过多的时候,就需要先等待较长的刷盘时间,然后才能获取响应。

为了避免上述两种情况,必须要控制脏页在内存中的比例。

二、刷脏页的控制策略

阅读全文 »

《MySQL45讲》读书笔记(二):日志的文件是如何保证不丢失的

发表于 2020-10-27 | 分类于 mysql
字数统计: 2.7k

此文为极客时间:MySQL实战45讲的23节日志相关部分的学习总结

一、持久化的过程

从总的来看,日志一般分为两部分:内存中易遗失的缓存日志和磁盘上持久化的日志文件。

一次事务中,日志先被写入内存,存放在 cache/buffer 中,然后事务结束以后准备持久化:先写入磁盘的 page cache 中,这个过程叫做 write ,他仍然是内存操作,只不过从 mysql 的内存去了操作系统的内存,所以比较快;然后再调用操作系统的方法来写入磁盘,这个过程叫做 fsync ,是真正的持久化过程,比较耗费时间。

这个过程,我们可以简单的理解为下图:

日志的持久化过程
日志的持久化过程

基于以上的概念,我们了解一下 binlog 和 redo log 的持久化策略。

二、binlog 的持久化

1.文件结构

系统给 binlog cache 分配了一片内存,每个线程独享一块内存,参数 binlog_cache_size 用于控制单个线程内 binlog cache 所占内存的大小。如果超过了这个参数规定的大小,就要暂存到磁盘。

阅读全文 »

《MySQL45讲》读书笔记(一):三大日志概述

发表于 2020-10-25 | 分类于 mysql
字数统计: 1.8k

此文为极客时间:MySQL实战45讲的 2、15节日志相关部分和网上一些相关文章的内容的总结

一、redo log

redo log 又叫重做日志,提供的是数据丢失后的前滚操作。

redo log 是 innodb 引擎独有的日志,使用了 WAL 技术(Write-Ahead Logging),也就是预写日志。它的关键点就是先写日志,再写磁盘。对应到 mysql 中具体操作,就是每次更新操作,先写日志,然后更新内存数据,最后等系统压力小的时候再进行IO更新磁盘数据。避免了每一次更新都需要进行IO操作。redo log 是保证了事务持久性的关键。

redo log 一般用在数据库恢复的情况:

  1. 如果是正常运行的实例的话,数据页被修改以后,跟磁盘的数据页不一致,称为脏页。最终数据落盘,就是把内存中的数据页写盘。这个过程,甚至与 redo log 毫无关系。
  2. 在崩溃恢复场景中,InnoDB 如果判断到一个数据页可能在崩溃恢复的时候丢失了更新,就会将它读到内存,然后让 redo log 更新内存内容。更新完成后,内存页变成脏页,就回到了第一种情况的状态。

另外,redo log 与 undo log 都被叫做事务日志。

redo log 是一个物理日志,我们知道数据库引擎加载是按“页”来的,redo log记录的就是每个“页”上的数据发生的变化。但是不像 binlog 那样,redo log 不记录 sql,而是以类似 session_id + date + file_id + block_id + 修改数据这样的格式去记录数据。

image-20200930111506778
image-20200930111506778

redo log 的日志文件大小是根据配置固定的,如果有一组有四个文件,每个文件的大小是 1GB,那么总共就只能记录 4GB 的日志。

阅读全文 »

Mybatis通用底层实现

发表于 2020-10-16 | 分类于 杂七乱八
字数统计: 1.3k

概述

最近接触了一些项目,发现很多项目最开始的时候Service接口和实现类一个方法都没有,通过继承通用底层能够使用基本的增删改查操作了。这种骚操作以前听过但是着实没有亲手实现过,今天参考着自己实现一下。

依赖关系图
依赖关系图

以最终我想要获得的自定义接口实现类DemoRStudentClassServicelImpl为例,以下是相关类之间的依赖关系图,不难看出,大体是分成通用的DAO层和建立在前者之上的通用的Service层两部分实现。

一、通用DAO实现

1.通用底层对象BaseDO

框架定义了一个基础对象BaseDO,提供一些通用属性,和通用方法,比如创建时间,修改时间等。

所有的对象都需要继承此类,以便在后续操作中使得定义的方法通过泛型接收对象。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 基础对象
*/
public class BaseDO {

private String id;

private String createBy;

private Date createDate;

private String updateBy;

private Date updateDate;

}

/**
* 自定义对象
*/
@Date
public class DemoRStudentDO extend BaseDO{

private String name;

private String age;

}

2.通用底层IBaseDao与自定义Dao

阅读全文 »

设计模式(一):工厂模式

发表于 2020-09-26 | 分类于 设计模式
字数统计: 1.6k

概述

工厂模式(Factory Pattern)属于创建型模式,它提供了一种创建对象的最佳方式。 在工厂模式中,我们在创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。

工厂模式旨在与解决接口实现类选择这一类问题,让实例创建的代码使用实例的方法解耦。

当我们需要根据不同的明确条件下创建不同的实例的时候,就可以使用工厂模式。

工厂模式分为三类:

  • 工厂方法模式:一个工厂生产固定的一个类。
  • 简单/静态工厂模式:一个工厂生产固定种类的多个类。
  • 抽象工厂模式:一个抽象工厂生产一

一、工厂方法模式

假设我们有一个导出报表的抽象类:

1
2
3
4
5
6
/**
* 文件导出接口
*/
public abstract class Exporter {
void export();
}

他现在有一个Excel导出实现类:

阅读全文 »
1…567…10

99 日志
15 分类
22 标签
RSS
© 2022 Createsequence
主题 — NexT.Gemini v5.1.4
0%