一、MySQL安装

下载地址:mysql,下载完成之后直接解压即可。

mysql数据库没有mysql库_数据库


解压完成之后,如下图所示。

mysql数据库没有mysql库_数据_02


1、配置my.ini文件,在安装目录下右击新建my.ini文件,并编辑。

mysql数据库没有mysql库_mysql数据库没有mysql库_03


在配置my.ini文件时,注意修改下面路径。

[mysqld]
# 设置3306端口
port=3306
# 设置mysql的安装目录
basedir=C:\mysql-8.0.15-winx64
# 设置mysql数据库的数据的存放目录
datadir=C:\mysql-8.0.15-winx64\Data
# 允许最大连接数
max_connections=1000
# 允许连接失败的次数。
max_connect_errors=500
# 服务端使用的字符集默认为UTF8MB4
character-set-server=utf8mb4
# 创建新表时将使用的默认存储引擎
default-storage-engine=INNODB
# 默认使用“mysql_native_password”插件认证
#mysql_native_password
default_authentication_plugin=mysql_native_password
lower_case_table_names=2
default-time_zone = '+8:00'
[mysql]
# 设置mysql客户端默认字符集
default-character-set=utf8mb4
[client]
# 设置mysql客户端连接服务端时默认使用的端口
port=3306
default-character-set=utf8mb4

2、管理员权限打开cmd窗口,切换到mysql目录下的bin目录下;

3、执行 mysqld --initialize-insecure --console

4、执行 mysqld --install

5、执行 net start mysql

6、执行 mysql -u root -p 两次回车;

7、修改root用户密码:

ALTER USER 'root'@'%' IDENTIFIED WITH mysql_native_password BY '123456';
flush privileges;

– 第8、9、10、11、12步可选,可用Navicat操作–

8、创建数据库:create database 数据库名;

9、创建用户:create user 'LI'@'%' identified by 'LI';

10、为用户LI设置权限:grant all privileges on 数据库名.* to 'LI'@'%';

11、刷新权限:flush privileges;

12、查看用户权限:show grants for 'LI'@'%';

13、修改root用户可远程连接(Navicat必选,端口开放)

use mysql;
update user set host='%' where user='root' and host='localhost';
select host,user from user;
flush privileges;

14、退出mysql:quit

15、停止mysql服务:net stop mysql

16、启动mysql服务:net start mysql

17、执行 mysql -u root -p 回车,输入密码,回车;

18、为root用户重新授权:grant all privileges on *.* to 'root'@'%';

19、刷新权限:flush privileges,完成

卸载:

1、停止mysql服务:net stop mysql

2、卸载mysql服务:mysqld --remove

备份数据库:

mysqldump.exe -h localhost -P 3306 -u root -p 数据库 > d:\数据库名.sql

还原数据库:

mysql -u root -p 数据库名 < d:\数据库名.sql

升级数据库版本:

1、下载好最新的myql的zip安装包;

2、停止当前要升级的mysql服务:net stop 服务名

3、解压zip安装包,覆盖mysql现有安装目录;

4、启动mysql服务:net start 服务名

常用命令:

1、查看当前使用的数据库:select database();

2、查看数据库列表:show databases;

环境配置

如果不想每次都要cd到mysql的bin目录下,可以配置环境变量, cmd命令执行mysql指令的时候会去环境变量里面找对应的路径。
右键我的电脑->属性->高级系统设置->环境变量->path->编辑,将下载解压的mysql的bin目录的全路径放里面:C:\mysql-8.0.15\bin; 多个用分号隔开。

二、MySQL介绍

数据库中间件
数据库中间件一般提供了读写分离、数据库水平扩展的能力。下面主要介绍两个中间件。

一是 Sharding-Sphere,它是一个开源的分布式数据库中间件解决方案,由 Sharding-JDBC、Sharding-Proxy、Sharding-Sidecar 这几个独立产品组成,适用不同使用场景。这几个产品都提供标准化的数据分片、读写分离、柔性事务和数据治理功能,可适用于如 Java 同构、异构语言、容器、云原生等各种多样化的应用场景。 目前 Sharding-Sphere 已经进入 Apache 孵化,发展速度很快,可以重点关注。

二是 Mycat,它也提供了分库分表等能力,Mycat 基于 Proxy 代理模式,后端可以支持 MySQL、Oracle、DB2 等不同数据库实现,不过代理方式对性能会有一定影响。

其他还有一些数据库中间件例如 Vitess 等,使用不算广泛,了解即可。

数据库
对于数据库相关知识点,首先需要知道不同类型的数据库。

  • 关系型数据库

常用的关系型数据库主要是 Oracle 和 MySQL。Oracle 功能强大,主要缺点就是贵。MySQL 是互联网行业中最流行的数据库,这不仅仅是因为 MySQL 免费,可以说关系数据库场景中你需要的功能,MySQL 都能很好得满足。后面的详解部分会详细介绍 MySQL 的一些知识点。

MariaDB 是 MySQL 的分支,由开源社区维护,MariaDB 虽然被看作 MySQL 的替代品,但与 MySQL 相比,它在扩展功能、存储引擎上都有非常好的改进,后续可以关注。

PostgreSQL也叫 PGSQL,PGSQL 类似于 Oracle 的多进程框架,可以支持高并发的应用场景。PG 几乎支持所有的 SQL 标准,支持类型相当丰富。PG 更加适合严格的企业应用场景,而 MySQL 更适合业务逻辑相对简单、数据可靠性要求较低的互联网场景。

  • NoSQL

NoSQL,就是 Not only SQL,一般指非关系型数据库。

上一课介绍的 Redis 就是非关系型数据库,它提供了持久化能力,支持多种数据类型。Redis 适用于数据变化快且数据大小可预测的场景。

MongoDB 是一个基于分布式文件存储的数据库,将数据存储为一个文档,数据结构由键值对组成。MongoDB 比较适合表结构不明确,且数据结构可能不断变化的场景,不适合有事务和复杂查询的场景。

HBase 是建立在 HDFS,也就是 Hadoop 文件系统之上的分布式面向列的数据库,类似于谷歌的大表设计,HBase 可以快速随机访问海量结构化数据。在表中它由行排序,一个表有多个列族以及每一个列族可以有任意数量的列。 HBase 依赖 HDFS 可以实现海量数据的可靠存储,适用于数据量大,写多读少,不需要复杂查询的场景。

Cassandra 是一个高可靠的大规模分布式存储系统。支持分布式的结构化 key-value 存储,以高可用性为主要目标。适合写多的场景,适合做一些简单查询,不适合用来做数据分析统计。

Pika 是一个可持久化的大容量类 Redis 存储服务, 兼容五种主要数据结构的大部分命令。Pika 使用磁盘存储,主要解决 Redis 大容量存储的成本问题。

NewSQL
NewSQL 数据库也越来越被大家关注,NewSQL 是指新一代关系型数据库。比较典型的有TiDB。

TiDB 是开源的分布式关系数据库,几乎完全兼容 MySQL,能够支持水平弹性扩展、ACID 事务、标准 SQL、MySQL 语法和 MySQL 协议,具有数据强一致的高可用特性。既适合在线事务处理,也适合在线分析处理。

另外一个比较著名的 NewSQL 是蚂蚁金服的 OceanBase。OB 是可以满足金融级的可靠性和数据一致性要求的数据库系统。需要使用事务,并且数据量比较大的时候,就比较适合使用 OB。不过目前 OB 已经商业化,不再开源。

最后来看数据库的范式。目前关系数据库有六种范式:第一范式、第二范式、第三范式、巴斯-科德范式(BCNF)、第四范式和第五范式。范式级别越高对数据表的要求越严格。

  • 要求最低的第一范式只要求表中字段不可用在拆分。
  • 第二范式在第一范式的基础上要求每条记录由主键唯一区分,记录中所有属性都依赖于主键。
  • 第三范式在第二范式的基础上,要求所有属性必须直接依赖主键,不允许间接依赖。

一般说来,数据库只需满足第三范式就可以了。

数据库事务
第一个原子性,指事务由原子的操作序列组成,所有操作要么全部成功,要么全部失败回滚。

第二个事务的一致性,指事务的执行不能破坏数据库数据的完整性和一致性,一个事务在执行之前和执行之后,数据库都必须处以一致性状态。比如在做多表操作时,多个表要么都是事务后新的值,要么都是事务前的旧值。

第三个事务的隔离性,指多个用户并发访问数据库时,数据库为每个用户执行的事务,不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。事务的隔离级别在后文中介绍。

第四个事务的持久性,指一个事务一旦提交并执行成功,那么对数据库中数据的改变就是永久性的,即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作。

并发问题

在介绍数据的隔离级别之前,先看看没有隔离性的情况下数据库会出现哪些并发问题

mysql数据库没有mysql库_mysql_04


脏写脏写,意思是说有两个事务,事务 A 和事务 B 同时在更新一条数据,事务 A 先把它更新为 A 值,事务 B 紧接着就把它更新为 B 值。如图:

mysql数据库没有mysql库_数据_05


可以看到,此时事务 B 是后更新那行数据的值,所以此时那行数据的值是 B。而且此时事务 A 更新之后会记录一条 undo log 日志。因为事务 A 是先更新的,它在更新之前,这行数据的值为 NULL。所以此时事务 A 的 undo log 日志大概就是:更新之前这行数据的值为 NULL,主键为 XX,那么此时事务 B 更新完数据的值为 B,此时事务 A 突然回滚了,就会用它的 undo log 日志去回滚。此时事务 A 一回滚,直接就会把那行数据的值更新回 NULL 值。如图:

mysql数据库没有mysql库_mysql数据库没有mysql库_06


然后就尴尬了,事务 B 一看,为什么我更新的 B 值没了?就因为你事务 A 反悔了把数据值回滚成 NULL 了,结果我更新的 B 值也不见 了。所以对于事务 B 看到的场景而言,就是自己明明更新了,结果值却没了,这就是脏写。

所谓脏写,就是我刚才明明写了一个数据值,结果过了一会却没了。而它的本质就是事务 B 去修改了事务 A 修改过的值,但是此时事务 A 还没提交,所以事务 A 随时会回滚,导致事务 B 修改的值也没了,这就是脏写的定义。

脏读

假设事务 A 更新了一行数据的值为 A 值,此时事务 B 去查询了一下这行数据的值,看到的值是 A 值,如图:

mysql数据库没有mysql库_sql_07


接着,事务 B 拿着刚才查询到的 A 值做各种业务处理。但是接着坑爹的事情发生了,事务 A 突然回滚了事务,导致它刚才功能的 A 值没了,此时那行数据的值回滚为 NULL 值。然后事务 B 紧接着此时再次查询那行数据的值,看到的居然是 NULL 值。如图:

mysql数据库没有mysql库_数据库_08


这就是脏读。它的本质是事务 B 去查询了事务 A 修改过的数据,但是此时事务 A 还没提交,所以事务 A 随时会回滚导致事务 B 再次查询就读不到刚才事务 A 修改的数据了,这就是脏读。

其实总结一句话,无论是脏写还是脏读,都是因为一个事务去更新或者查询了另外一个还没提交的事务更新过的数据。因为另外一个事务还没提交,所以它随时可能会回滚,那么必然导致你更新的数据就没了,或者你之前查询到的数据就没了,这就是脏写和脏读两种场景。

脏读是指在一个事务处理过程里读取了另一个未提交的事务中的数据,例如,账户 A 转帐给 B 500元,B 余额增加后但事务还没有提交完成,此时如果另外的请求中获取的是 B 增加后的余额,这就发生了脏读,因为事务如果失败回滚时,B 的余额就不应该增加。

不可重复读

假设我们有一个事务 A 开启了,在这个事务 A 里会多次对一条数据进行查询。然后呢,另外有两个事务,一个是事务 B,一个是事务 C,他们两都是对一条数据进行更新的。然后我们假设一个前提,就是比如说事务 B 更新之后,如果还没提交,那么事务 A 是读不到的,必须要事务 B 提交之后,它修改的值才能被事务 A 读取到,其实这种情况下,就是我们首先避免了脏读的发生

因为脏读的意思就是事务 A 可以读到事务 B 修改过还没提交的数据,此时事务 B 一旦回滚,事务 A 再次读就读不到了,那么此时就会发生脏读问题。我们现在假设的前提是事务 A 只能在事务 B 提交之后读取到它修改的数据,所以此时必然是不会发生脏读的

但是,此时会有另外一个问题,叫做不可重复读。假设缓存页里一条数据原来的值是 A 值,此时事务 A 开启之后,第一次查询这条数据,读取到的就是 A 值。如图:

mysql数据库没有mysql库_mysql数据库没有mysql库_09


接着事务 B 更新了那行数据的值为 B 值,同时事务 B 立马提交了,然后事务 A 此时还没提交。大家注意,此时事务 A 是没提交的,它在事务执行期间第二次查询数据,此时查到的是事务 B 修改过的值,B 值,因为事务 B 已经提交了,所以事务 A 是可以读到的,如图:

mysql数据库没有mysql库_mysql数据库没有mysql库_10


紧接着事务 C 再次更新数据为 C 值,并且提交事务了,此时事务 A 在还没提交的情况下,第三次查询数据,查到的值为 C 值,如下:

mysql数据库没有mysql库_数据_11


那么上面的场景有什么问题呢?其实要说没问题也可以是没问题的,毕竟事务 B 和 事务 C 都提交之后,事务 A 多次查询查到它们修改的值,是 OK 的。但是你要说有问题,也可以是有问题的,就是事务 A 可能第一次查询到 A 值,那么它可能希望的是在事务执行期间,如果多次查询数据,都是同样的一个 A 值,它希望这个 A 值是它重复读取的时候一直可以读到的。它希望这行数据的值是可重复读的

但是此时,明显 A 值是不可重复读的。因为事务 B 和事务 C 一旦更新值并且提交了,事务 A 会读到别的值,所以此时这行数据的值是不可重复读的。此时对于你来说,这个不可重复读的场景,就是一种问题

上面描述的,其实就是不可重复读的问题,其实这个问题你说是问题也不一定就是什么大问题。因为这取决于你自己想要数据库是什么样子的,如果你希望看到的场景是不可重复读,也就是事务 A 在执行期间多次查询一条数据,每次都可以查到其它已经提交的事务修改过的值,那么就是不可重复读,如果你希望这样子,那也没问题。

如果你期望的是可重复读,但是数据库表现的是不可重复读,让你事务 A 执行期间多次查到的值都不一样,都的问题是别的提交过的事务修改过的,那么此时你就可以认为,数据库有问题,这个问题就是「不可重复读」。不可重复读是指对于数据库中某个数据,一个事务范围内多次查询返回了不同的数据值,这是由于在多次查询之间,有其他事务修改了数据并进行了提交。

幻读

脏写、脏读和不可重复读都分别代表了不同的数据库问题。脏写就是两个事务没提交的状况下,都修改同一条数据,结果一个事务回滚了,把另外一个事务修改的值也撤销了,所谓脏写就是两个事务没提交状态下修改同一个值。

脏读就是一个事务修改了一条数据的值,结果还没提交呢,另外一个事务就读到了你修改的值,然后你回滚了,人家事务再次读,就读不到了,即人家事务读到了你修改之后还没提交的值,这就是脏读了。而不可重复读,针对的是已经提交的事务修改的值,被你事务给读到了,你事务内多次查询,多次读到的是别的已经提交的事务修改过的值,这就导致不可重复读。

接着我们说说幻读。简单来说,你一个事务 A,先发送一条 SQL 语句,里面有一个条件,要查询一批数据出来,如 SELECT * FROM table WHERE id > 10。然后呢,它一开始查询出来了 10 条数据。接着这个时候,别的事务 B往表里插了几条数据,而且事务 B 还提交了,此时多了几行数据。如图:

mysql数据库没有mysql库_mysql_12


接着事务 A 此时第二次查询,再次按照之前的一模一样的条件执行 SELECT * FROM table WHERE id > 10 这条 SQL 语句,由于其他事务插入了几条数据,导致这次它查询出来了 12 条数据。如图:

mysql数据库没有mysql库_sql_13


于是事务 A 开始怀疑自己的眼镜了,为什么一模一样的 SQL 语句,第一次查询是 10 条数据,第二次查询是 12 条数据?难道刚才出现幻觉了?这就是「幻读」这个名词的由来

幻读就是你一个事务用一样的 SQL 多次查询,结果每次查询都会发现查到一些之前没看到过的数据。注意,幻读特指的是你查询到了之前查询没看到过的数据。此时说明你是幻读了

其实,脏写、脏读、不可重复读、幻读,都是因为业务系统会多线程并发执行,每个线程可能都会开启一个事务,每个事务都会执行增删改查操作。然后数据库会并发执行多个事务,多个事务可能会并发地对缓存页里的同一批数据进行增删改查操作,于是这个并发增删改查同一批数据的问题,可能就会导致我们说的脏写、脏读、不可重复读、幻读这些问题。

所以这些问题的本质,都是数据库的多事务并发问题,那么为了解决多事务并发问题,数据库才设计了事务隔离机制、MVCC 多版本隔离机制、锁机制,用一整套机制来解决多事务并发问题。指一个事务中执行两次完全相同的查询时,第二次查询所返回的结果集跟第一个查询不相同。与不可重复读的区别在于,不可重复读是对同一条记录,两次读取的值不同。而幻读是记录的增加或删除,导致两次相同条件获取的结果记录数不同。

隔离级别
事务的四种隔离级别可以解决上述几种并发问题。如上图右侧内容所示,由上到下,四种隔离级别由低到高。

第一个隔离级别是读未提交,也就是可以读取到其他事务未提交的内容,这是最低的隔离级别,这个隔离级别下,前面提到的三种并发问题都有可能发生。

第二个隔离级别是读已提交,就是只能读取到其他事务已经提交的数据。这个隔离级别可以解决脏读问题。

第三个隔离级别是可重复读,可以保证整个事务过程中,对同数据的多次读取结果是相同的。这个级别可以解决脏读和不可重复读的问题。MySQL 默认的隔离级别就是可重复读。

最后一个隔离级别是串行化,这是最高的隔离级别,所有事务操作都依次顺序执行。这个级别会导致并发度下降,性能最差。不过这个级别可以解决前面提到的所有并发问题。

事务分类

mysql数据库没有mysql库_数据_14


第一个是扁平化事务,在扁平事务中,所有的操作都在同一层次,这也是我们平时使用最多的一种事务。它的主要限制是不能提交或者回滚事务的某一部分,要么都成功,要么都回滚。

为了解决第一种事务的弊端,就有了第二种带保存点的扁平事务。它允许事务在执行过程中回滚到较早的状态,而不是全部回滚。通过在事务中插入保存点,当操作失败后,可以选择回滚到最近的保存点处。

第三种事务是链事务,可以看做是第二种事务的变种。它在事务提交时,会将必要的上下文隐式传递给下一个事务,当事务失败时就可以回滚到最近的事务。不过,链事务只能回滚到最近的保存点,而带保存点的扁平化事务是可以回滚到任意的保存点。

第四种事务是嵌套事务,由顶层事务和子事务构成,类似于树的结构。一般顶层事务负责逻辑管理,子事务负责具体的工作,子事务可以提交,但真正提交要等到父事务提交,如果上层事务回滚,那么所有的子事务都会回滚。

最后一种类型是分布式事务。是指分布式环境中的扁平化事务。

常用的分布式事务解决方案如上图右侧所示,下面进行简要介绍。

第一个分布式事务解决方案是 XA 协议,是保证强一致性的刚性事务。实现方式有两段式提交和三段式提交。两段式提交需要有一个事务协调者来保证所有的事务参与者都完成了第一阶段的准备工作。如果协调者收到所有参与者都准备好的消息,就会通知所有的事务执行第二阶段提交。一般场景下两段式提交已经能够很好得解决分布式事务了,然而两阶段在即使只有一个进程发生故障时,也会导致整个系统存在较长时间的阻塞。三段式提交通过增加 pre-commit 阶段来减少前面提到的系统阻塞的时间。三段式提交很少在实际中使用,简单了解就可以了。

第二个分布式解决方案是 TCC,是满足最终一致性的柔性事务方案。TCC 采用补偿机制,核心思想是对每个操作,都要注册对应的确认和补偿操作。它分为三个阶段:Try 阶段主要对业务系统进行检测及资源预留;Confirm 阶段对业务系统做确认提交;Cancel 阶段是在业务执行错误,执行回滚,释放预留的资源。

第三种方案是消息一致性方案。基本思路是将本地操作和发送消息放在一个事务中,保证本地操作和消息发送要么都成功要么都失败。下游应用订阅消息,收到消息后执行对应操作。

第四种方案可以了解一下阿里云中的全局事务服务 GTS,对应的开源版本是 Fescar。Fescar 基于两段式提交进行改良,剥离了分布式事务方案对数据库在协议支持上的要求。使用 Fescar 的前提是分支事务中涉及的资源,必须是支持 ACID 事务的关系型数据库。分支的提交和回滚机制,都依赖于本地事务来保障。 Fescar 的实现目前还存在一些局限,比如事务隔离级别最高支持到读已提交级别。