## 视图

### 前言

对于复杂的查询，往往是有多个数据表进行关联查询而得到，如果数据库因为需求等原因发生了改变，为了保证查询出来的数据与之前相同，则需要在多个地方进行修改，维护起来非常麻烦。可以通过定义视图来解决

### 简介

通俗的讲，视图就是一条SELECT语句执行后返回的结果集。所以我们在创建视图的时候，主要的工作就落在创建这条SQL查询语句上。视图是对若干张基本表的引用，一张虚表，查询语句执行的结果，不存储具体的数据（基本表数据发生了改变，视图也会跟着改变）；方便操作，特别是查询操作，减少复杂的SQL语句，增强可读性；

### 定义

建议以v_开头

```sql
create view 视图名称 as select语句;
```

### 查看

查看表会将所有的视图也列出来

```sql
show tables;
```

###  使用

视图的用途就是查询

```sql
select * from v_stu_score;
```

### 删除

```sql
drop view 视图名称;
例：
drop view v_stu_sco;
```

### 作用

1. 提高了重用性，就像一个函数
2. 对数据库重构，却不影响程序的运行
3. 提高了安全性能，可以对不同的用户
4. 让数据更加清晰

## 事务

### 前言

事务广泛的运用于订单系统、银行系统等多种场景。

### 简介

所谓事务,它是一个操作序列，这些操作要么都执行，要么都不执行，它是一个不可分割的工作单位。

### 四大特性(ACID)

- 原子性(Atomicity)：一个事务必须被视为一个不可分割的最小工作单元，整个事务中的所有操作要么全部提交成功，要么全部失败回滚，对于一个事务来说，不可能只执行其中的一部分操作，这就是事务的原子性
- 一致性(Consistency)：数据库总是从一个一致性的状态转换到另一个一致性的状态。（在前面的例子中，一致性确保了，即使在执行第三、四条语句之间时系统崩溃，支票账户中也不会损失200美元，因为事务最终没有提交，所以事务中所做的修改也不会保存到数据库中。）
- 隔离性(Isolation)：通常来说，一个事务所做的修改在最终提交以前，对其他事务是不可见的。（在前面的例子中，当执行完第三条语句、第四条语句还未开始时，此时有另外的一个账户汇总程序开始运行，则其看到支票帐户的余额并没有被减去200美元。）
- 持久性(Durability)：一旦事务提交，则其所做的修改会永久保存到数据库。（此时即使系统崩溃，修改的数据也不会丢失。）

### 命令

表的引擎类型必须是innodb类型才可以使用事务，这是mysql表的默认引擎，查看表的创建语句，可以看到engine=innodb

```sql
-- 选择数据库
use jing_dong;
-- 查看goods表
show create table goods;
```

#### 开启事务

开启事务后执行修改命令，变更会维护到本地缓存中，而不维护到物理表中，命令如下：

```sql
begin;
或者
start transaction;
```

#### 提交事务

将缓存中的数据变更维护到物理表中，命令如下

```sql
commit;
```

#### 回滚事务

放弃缓存中变更的数据，命令如下：

```sql
rollback;
```

#### 注意

1. 修改数据的命令会自动的触发事务，包括insert、update、delete
2. 而在SQL语句中有手动开启事务的原因是：可以进行多次数据的修改，如果成功一起成功，否则一起会滚到之前的数据

## 索引

### 前言

一般的应用系统对比数据库的读写比例在10:1左右(即有10次查询操作时有1次写的操作)，而且插入操作和更新操作很少出现性能问题，遇到最多、最容易出问题还是一些复杂的查询操作，所以查询语句的优化显然是重中之重。当数据库中数据量很大时，查找数据会变得很慢，可以通过创建索引的方式进行优化。

### 简介

索引是一种特殊的文件(InnoDB数据表上的索引是表空间的一个组成部分)，它们包含着对数据表里所有记录的引用指针。更通俗的说，数据库索引好比是一本书前面的目录，能加快数据库的查询速度。

### 目的

索引的目的在于提高查询效率，可以类比字典，如果要查“mysql”这个单词，我们肯定需要定位到m字母，然后从下往下找到y字母，再找到剩下的sql。如果没有索引，那么你可能需要把所有单词看一遍才能找到你想要的，如果我想找到m开头的单词呢？或者ze开头的单词呢？是不是觉得如果没有索引，这个事情根本无法完成？

### 原理

除了词典，生活中随处可见索引的例子，如火车站的车次表、图书的目录等。它们的原理都是一样的，通过不断的缩小想要获得数据的范围来筛选出最终想要的结果，同时把随机的事件变成顺序的事件，也就是我们总是通过同一种查找方式来锁定数据。数据库也是一样，但显然要复杂许多，因为不仅面临着等值查询，还有范围查询(>、<、between、in)、模糊查询(like)、并集查询(or)等等。数据库应该选择怎么样的方式来应对所有的问题呢？我们回想字典的例子，能不能把数据分成段，然后分段查询呢？最简单的如果1000条数据，1到100分成第一段，101到200分成第二段，201到300分成第三段……这样查第250条数据，只要找第三段就可以了，一下子去除了90%的无效数据。

### 使用

#### 查看索引

```sql
show index from 表名;
```

#### 创建索引

如果指定字段是字符串，需要指定长度，建议长度与定义字段时的长度一致，字段类型如果不是字符串，可以不填写长度部分

```sql
create index 索引名称 on 表名(字段名称(长度))
```

#### 删除索引

```sql
drop index 索引名称 on 表名;
```

### 注意：

要注意的是，建立太多的索引将会影响更新和插入的速度，因为它需要同样更新每个索引文件。对于一个经常需要更新和插入的表格，就没有必要为一个很少使用的where字句单独建立索引了，对于比较小的表，排序的开销不会很大，也没有必要建立另外的索引。建立索引会占用磁盘空间。

## 账户管理

在生产环境下操作数据库时，绝对不可以使用root账户连接，而是创建特定的账户，授予这个账户特定的操作权限，然后连接进行操作，主要的操作就是数据的crud。MySQL账户体系：根据账户所具有的权限的不同，MySQL的账户可以分为以下几种：

- 服务实例级账号：，启动了一个mysqld，即为一个数据库实例；如果某用户如root,拥有服务实例级分配的权限，那么该账号就可以删除所有的数据库、连同这些库中的表
- 数据库级别账号：对特定数据库执行增删改查的所有操作
- 数据表级别账号：对特定表执行增删改查等所有操作
- 字段级别的权限：对某些表的特定字段进行操作
- 存储程序级别的账号：对存储程序进行增删改查的操作

- 账户的操作主要包括创建账户、删除账户、修改密码、授权权限等

注意：

1. 进行账户操作时，需要使用root账户登录，这个账户拥有最高的实例级权限
2. 通常都使用数据库级操作权限

### 授予权限

需要使用实例级账户登录后操作，以root为例

主要操作包括：

- 查看所有用户
- 修改密码
- 删除用户

#### 查看所有用户

- 所有用户及权限信息存储在mysql数据库的user表中
- 查看user表的结构

```sql
desc user;
```

- 主要字段说明：
  - Host表示允许访问的主机
  - User表示用户名
  - authentication_string表示密码，为加密后的值

查看所有用户

```sql
select host,user,authentication_string from user;
```

#### 创建账户、授权

- 需要使用实例级账户登录后操作，以root为例
- 常用权限主要包括：create、alter、drop、insert、update、delete、select
- 如果分配所有权限，可以使用all privileges

```sql
grant 权限列表 on 数据库 to '用户名'@'访问主机' identified by '密码';
```

#### 修改权限

```sql
grant 权限名称 on 数据库 to 账户@主机 with grant option;
```

#### 修改密码

使用root登录，修改mysql数据库的user表，使用password()函数进行密码加密

```sql
update user set authentication_string=password('新密码') where user='用户名';
```

注意修改完成后需要刷新权限

```sql
刷新权限：flush privileges
```

#### 远程登录（危险慎用）

如果向在一个Ubuntu中使用msyql命令远程连接另外一台mysql服务器的话，通过以下方式即可完成，但是此方法仅仅了解就好了，不要在实际生产环境中使用，修改 `/etc/mysql/mysql.conf.d/mysqld.cnf` 文件把`bind-address = 127.0.0.1`注释掉，然后重启msyql

```sql
service mysql restart
```

如果依然连不上，可能原因：

1)网络不通：通过 ping xxx.xxx.xx.xxx可以发现网络是否正常

2)查看数据库是否配置了bind_address参数：本地登录数据库查看my.cnf文件和数据库当前参数show variables like 'bind_address'；如果设置了bind_address=127.0.0.1 那么只能本地登录

3)查看数据库是否设置了skip_networking参数：如果设置了该参数，那么只能本地登录mysql数据库

4)端口指定是否正确

#### 删除账户

- 使用root登录

```sql
drop user '用户名'@'主机';
```

- 使用root登录，删除mysql数据库的user表中数据

```sql
delete from user where user='用户名';
```

- 推荐使用第一种删除用户, 如果使用第一种删除失败，采用第二种方式

## 主从同步

### 简介

主从同步使得数据可以从一个数据库服务器复制到其他服务器上，在复制数据时，一个服务器充当主服务器（master），其余的服务器充当从服务器（slave）。因为复制是异步进行的，所以从服务器不需要一直连接着主服务器，从服务器甚至可以通过拨号断断续续地连接主服务器。通过配置文件，可以指定复制所有的数据库，某个数据库，甚至是某个数据库上的某个表。

### 好处

- 通过增加从服务器来提高数据库的性能，在主服务器上执行写入和更新，在从服务器上向外提供读功能，可以动态地调整从服务器的数量，从而调整整个数据库的性能。
- 提高数据安全，因为数据已复制到从服务器，从服务器可以终止复制进程，所以，可以在从服务器上备份而不破坏主服务器相应数据
- 在主服务器上生成实时数据，而在从服务器上分析这些数据，从而提高主服务器的性能

### 机制

Mysql服务器之间的主从同步是基于二进制日志机制，主服务器使用二进制日志来记录数据库的变动情况，从服务器通过读取和执行该日志文件来保持和主服务器的数据一致。

在使用二进制日志时，主服务器的所有操作都会被记录下来，然后从服务器会接收到该日志的一个副本。从服务器可以指定执行该日志中的哪一类事件（譬如只插入数据或者只更新数据），默认会执行日志中的所有语句。

每一个从服务器会记录关于二进制日志的信息：文件名和已经处理过的语句，这样意味着不同的从服务器可以分别执行同一个二进制日志的不同部分，并且从服务器可以随时连接或者中断和服务器的连接。

主服务器和每一个从服务器都必须配置一个唯一的ID号（在my.cnf文件的[mysqld]模块下有一个server-id配置项），另外，每一个从服务器还需要通过CHANGE MASTER TO语句来配置它要连接的主服务器的ip地址，日志文件名称和该日志里面的位置（这些信息存储在主服务器的数据库里）

### 基本步骤

有很多种配置主从同步的方法，可以总结为如下的步骤：

1. 在主服务器上，必须开启二进制日志机制和配置一个独立的ID
2. 在每一个从服务器上，配置一个唯一的ID，创建一个用来专门复制主服务器数据的账号
3. 在开始复制进程前，在主服务器上记录二进制文件的位置信息
4. 如果在开始复制之前，数据库中已经有数据，就必须先创建一个数据快照（可以使用mysqldump导出数据库，或者直接复制数据文件）
5. 配置从服务器要连接的主服务器的IP地址和登陆授权，二进制日志文件名和位置

### 详细配置

主和从的身份可以自己指定，我们将虚拟机Ubuntu中MySQL作为主服务器，将Windows中的MySQL作为从服务器。 在主从设置前，要保证Ubuntu与Windows间的网络连通。

#### 备份主服务器原有数据到从服务器

如果在设置主从同步前，主服务器上已有大量数据，可以使用mysqldump进行数据备份并还原到从服务器以实现数据的复制。

#### 在主服务器Ubuntu上进行备份，执行命令：

```sql
mysqldump -uroot -pmysql --all-databases --lock-all-tables > ~/master_db.sql
```

说明：

- -u ：用户名
- -p ：示密码
- --all-databases ：导出所有数据库
- --lock-all-tables ：执行操作时锁住所有表，防止操作时有数据修改
- ~/master_db.sql :导出的备份数据（sql文件）位置，可自己指定

#### 数据还原

在从服务器命令行中执行还原操作:

```sql
mysql –uroot –pmysql < master_db.sql
```



#### 配置主服务器master

- 编辑设置mysqld的配置文件，设置log_bin和server-id

```bash
sudo vim /etc/mysql/mysql.conf.d/mysqld.cnf
```

- 重启mysql服务

```bash
sudo service mysql restart
```

- 登入主服务器Ubuntu中的mysql，创建用于从服务器同步数据使用的帐号

```mysql
mysql –uroot –pmysql
GRANT REPLICATION SLAVE ON *.* TO 'slave'@'%' identified by 'slave';
FLUSH PRIVILEGES;
```

- 获取主服务器的二进制日志信息

```
SHOW MASTER STATUS;
```

File为使用的日志文件名字，Position为使用的文件位置，这两个参数须记下，配置从服务器时会用到

#### 配置从服务器slave

- 编辑从服务器配置文件将`server-id`修改为2，并保存退出

- 重启MySQL服务

  ```bash
  service mysql restart
  ```

- 设置连接到master主服务器

  ```
  change master to master_host='10.211.55.5', master_user='slave', master_password='slave',master_log_file='mysql-bin.000006', master_log_pos=590;
  ```
  
  注：
  
  - master_host：主服务器Ubuntu的ip地址
  - master_log_file: 前面查询到的主服务器日志文件名
  - master_log_pos: 前面查询到的主服务器日志文件位置

#### 开启同步，查看同步状态

```mysql
start slave;
show slave status ;
```

#### 测试主从同步

在主服务器创建一个数据库，在从服务器中查看新建的数据库是否存在