什么是数据库?
存放数据的仓库。凡涉及到数据的存储,均需要数据库。
常见数据库分类
目前常见的数据库可以分为两类,其中已MySQL最为常见。因为我们平台主要应用了MySQL数据库,所以本文将主要介绍讲解MySQL数据库。
关系型数据库
MySQL
Oracle
SQL server
MariaDB
非关系型数据库
- MongoDB
- Redis
MySQL数据库
以下将主要涉及安装、数据库引擎、数据库事务、索引、数据备份、sql命令。
安装
MySQL支持Linux,Windows,MacOS等系统。进入MySQL官网下载,然后解压安装即可。安装完成后,将MySQL安装目录添加到系统环境变量中,以便在任意目录下使用MySQL命令连接数据库。
目录设置
MySQL数据库中的数据一般存放在data目录下。在Linux系统下安装时,可能需要自己手动创建数据库仓库。
数据库引擎
数据库存储引擎是数据库底层软件组织,数据库管理系统(DBMS)使用数据引擎进行创建、查询、更新和删除数据。不同的存储引擎提供不同的存储机制、索引技巧、锁定水平等功能,使用不同的存储引擎,还可以 获得特定的功能。现在许多不同的数据库管理系统都支持多种不同的数据引擎。MySQL的核心就是存储引擎。
MySQL5.5版本开始InnoDB已经成为Mysql的默认引擎(之前是MyISAM),说明其优势是有目共睹的,如果你不知道用什么,那就用InnoDB,至少不会差。
存储引擎的特点
下图是MySQL中的四种常见引擎区别对比。其中InnoDB在5.6版本支持全文索引。
如果要提供提交、回滚、崩溃恢复能力的事物安全(ACID兼容)能力,并要求实现并发控制,InnoDB是一个好的选择。
如果数据表主要用来插入和查询记录,则MyISAM引擎能提供较高的处理效率。
如果只是临时存放数据,数据量不大,并且不需要较高的数据安全性,可以选择将数据保存在内存中的Memory引擎,MySQL中使用该引擎作为临时表,存放查询的中间结果。
如果只有INSERT和SELECT操作,可以选择Archive,Archive支持高并发的插入操作,但是本身不是事务安全的。Archive非常适合存储归档数据,如记录日志信息可以使用Archive。
使用哪一种引擎需要灵活选择,一个数据库中多个表可以使用不同引擎以满足各种性能和实际需求,使用合适的存储引擎,将会提高整个数据库的性能
引擎管理命令
查看数据库支持的存储引擎
1
show engines;
查看数据库当前使用的存储引擎
1
show variables like '%storage_engine%';
查看数据库表所用的存储引擎
1
show create table table_name;
创建表指定存储引擎
1
create table table_name (column_name column_type) engine = engine_name;
修改表的存储引擎
1
alter table table_name engine=engine_name;
修改默认的存储引擎
在MySQL配置文件中修改内容:default-storage-engine=INNODB
- MySQL配置文件:windows系统 - MySQL安装目录/my.ini (5.7版本my.ini文件在数据目录中, C:/programdata/MySQL Server 5.7/mysql/)
- MySQL配置文件:linux系统 - /etc/my.cnf
数据库事务
概念
在MySQL中只有使用InnoDB引擎的库或者表支持事物。事务指逻辑上的一组操作(update、insert、delete),组成这组操作的各个单元,要不全部成功,要不全部不成功。
1 | /*例如:A——B转帐,对应于如下两条sql语句*/ |
事务需要满足四大特性(ACID):
- 原子性: 指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败。比如在同一个事务中的SQL语句,要么全部执行成功,要么全部执行失败
- 一致性: 事务必须使数据库从一个一致性状态变换到另外一个一致性状态。以转账为例,A向B转账,假设转账之前这两个用户的钱加起来总共是2000,那么A向B转账之后,不管这两个账户怎么转,A用户的钱和B用户的钱加起来的总额还是2000,这个就是事务的一致性。
- 隔离性: 指多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。
持久性: 指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响 。
事务的四大特性中最麻烦的是隔离性,后面重点介绍一下事务的隔离。
事务操作命令
BEGIN或START TRANSACTION:显式地开启一个事务;
COMMIT:也可以使用COMMIT WORK,不过二者是等价的。COMMIT会提交事务,并使已对数据库进行的所有修改成为永久性的;
ROLLBACK:也可以使用ROLLBACK WORK,不过二者是等价的。回滚会结束用户的事务,并撤销正在进行的所有未提交的修改;
SAVEPOINT identifier:SAVEPOINT允许在事务中创建一个保存点,一个事务中可以有多个SAVEPOINT;
RELEASE SAVEPOINT identifier:删除一个事务的保存点,当没有指定的保存点时,执行该语句会抛出一个异常;
ROLLBACK TO identifier:把事务回滚到标记点;
SET TRANSACTION:用来设置事务的隔离级别。
事务的隔离
多个线程开启各自事务操作数据库中数据时,数据库系统要负责隔离操作,以保证各个线程在获取数据时的准确性。 如果不考虑隔离行,则可能引发问题。
问题
- 脏读: 指一个事务读取了另外一个事务未提交的数据。
1 | 1.update account set money=money+100 where name='B'; |
当第1条sql执行完,第2条还没执行(A未提交时),如果此时B查询自己的帐户,就会发现自己多了100元钱。如果A等B走后再回滚,B就会损失100元。
- 不可重复读: 指在一个事务内读取表中的某一行数据,多次读取结果不同。 不可重复读和脏读的区别是,脏读是读取前一事务未提交的脏数据,不可重复读是重新读取了前一事务已提交的数据。
例如银行想查询A帐户余额,第一次查询A帐户为200元,此时A向帐户内存了100元并提交了,银行接着又进行了一次查询,此时A帐户为300元了。银行两次查询不一致,可能就会很困惑,不知道哪次查询是准的。
- 虚读(幻读): 指在一个事务内读取到了别的事务插入的数据,导致前后读取不一致。
如丙存款100元未提交,这时银行做报表统计account表中所有用户的总额为500元,然后丙提交了,这时银行再统计发现帐户为600元了,造成虚读同样会使银行不知所措,到底以哪个为准。
隔离级别
MySQL数据库共定义了四种隔离级别:
- Serializable(串行化):可避免脏读、不可重复读、虚读情况的发生。
- Repeatable read(可重复读):可避免脏读、不可重复读情况的发生。(此为MySQL默认事务隔离级别)
- Read committed(读已提交):可避免脏读情况发生。
- Read uncommitted(读未提交):最低级别,以上情况均无法保证。
1 | /* 查询当前事务隔离级别*/ |
演示实例
同时打开两个窗口模拟2个用户并发访问数据库,演示不同隔离级别下的并发问题。默认数据库中存在account表。
实例一:
1 | --A窗口 |
实例二:
1 | --A窗口 |
实例三:
1 | --A窗口 |
实例四:
1 | --A窗口 |
实例
通过下图中的实例,可以很好理解数据库事务。以及为什么需要事务。
1 |
数据库索引
在讲索引之前我们首先简单了解一下什么是主键和外键。
主键
在一张数据表中,每一行代表了一条数据记录。一条记录由多个字段组成,字段构成了表的列。同一表中任意两条数据记录均不能重复。 指能够通过某个字段唯一区分出不同的记录,这个字段被称为主键。
主键:一旦将数据记录插入数据表,主键信息最好不要更改。如果使用业务字段作为主键,一旦数据变动,则会导致主键信息也会变动。在一个数据表中不使用任何业务相关的字段作为主键,一般使用id。
1 | -- 如下id则为此表的主键 |
外键
在people表中,通过city_id
的字段,可以把数据与另一张表关联起来,这种列称为外键
。
1 | -- people表 |
当然以上列名city_id
没有约束关系,只是一个名字而已。外键是通过定义表的外键约束实现的。
1 | -- 定义people表city_id为外键关联到city表中的id。外键约束名称fk_city_id只是一个名字,可任意,无实际意义 |
索引
索引是关系数据库中对某一列或多个列的值进行预排序的数据结构,它也是一张表。通过使用索引,可以让数据库系统不必扫描整个表,而是直接定位到符合条件的记录,这样就大大加快了查询速度。 索引的优点,是能够极大的提高数据库的查询性能。 但它也有缺点, 在插入、更新和删除记录时,需要同时修改索引,因此,如果索引越多,插入、更新和删除记录的速度就越慢 。
注意: 索引的效率取决于索引列的值是否散列,即该列的值如果越互不相同,那么索引效率越高。反过来,如果记录的列存在大量相同的值,对该列创建索引就没有意义。对于主键,关系数据库会自动对其创建主键索引。使用主键索引的效率是最高的,因为主键会保证绝对唯一。
1 | -- people表 |
1 | -- 对people表name列添加名为idx_age的索引 |
唯一索引
在设计关系数据表的时候,看上去唯一的列,例如身份证号、邮箱地址等,因为他们具有业务含义,因此不宜作为主键。但是,这些列根据业务要求,又具有唯一性约束:即不能出现两条记录存储了同一个身份证号。这个时候,就可以给该列添加一个唯一索引。例如,我们假设people
表的name
不能重复:
1 | -- 通过UNIQUE关键字我们就添加了一个唯一索引。 |
小结:通过对数据库表创建索引,可以提高查询速度。通过创建唯一索引,可以保证某一列的值具有唯一性。数据库索引对于用户和应用程序来说都是透明的。
数据备份
导出数据库
第一种方法:使用mysqldump命令导出数据库或者数据库中的表
1,在终端中输入以下命令,导出数据库:mysqldump -u 用户名 -p 数据库名 > 导出的文件名
1 | > mysqldump -u root -p news > test.sql |
Tips:如果需要导出数据库中某张数据表的,在数据库名后面输入表名即可
1 | > mysqldump -u root -p database_name table_name > dump.txt |
2、会看到文件news.sql自动生成到当前路径下。以上操作默认MySQL目录添加到了系统的环境变量中。
第二种方法:使用图形化工具,如Navicat软件。如将A服务器上数据库导入到B服务器中的数据库。
注意:一定要注意数据导出的方向。否则方向出错,会导致原来A服务器上数据库的数据全被B覆盖,从而导致A数据丢失!
导入数据库
1,在终端中输入以下命令,连接MySQL
1 | > mysql -u root -p |
(输入root用户的登录密码,即可连接成功)
2,新建一个名为test的空数据库。
3,使用test数据库
1 | mysql> use test; |
4,导入sql文件:mysql>source 导入的文件名;
1 | mysql> source news.sql; |
常用SQL语句
管理语句
连接MySQL
并查看数据库。注意:SQL语句中命令关键字不区分大小写。
在MySQL
中,information_schema、mysql、performance_schema
和sys是系统库,不要去改动它们。其他的则是用户创建的数据库。mysql库中的user表存放了连接MySQL
的账户、密码和权限等信息。
1 | -- 通过命令行连接MySQL数据库,然后输入密码验证 |
对数据库操作
1 | -- 创建名为test的数据库 |
对数据表进行操作
1 | -- 查看test库中的所有表 |
退出MySQL
1 | quit; |
增删改查语句
SELECT查询
1 | -- 查询people表中的所有记录 |
聚合函数
- SUM 求和,数值类型
- AVG 求平均值,数值类型
- MAX 最大值,可以为数值或者string类型
- MIN 最小值,可以为数值或者string类型
多表查询(笛卡尔查询)和连接查询
1 | -- 同时查询people表和city表,此时结果集为两表函数的乘积吗,列数为和、行数为积。 |
INSERT插入
1 | -- 在此表中,id为主键,且自增,所以这里插入数据记录时不用考虑id值 |
DELETE删除
1 | -- 删除people表中的id大于等于6且id小于等于8的所有数据记录 |
UPDATE更新
1 | -- 更新people表中id=1的数据记录的name和age字段 |
LIKE模糊查询
在MySQL中,LIKE关键字能够进行模糊查询。
1 | -- %表示匹配任意多少个字符 |
MySQL性能调优
目前实验室的testlink和bugfree平台所使用的就是MySQL数据库。版本为5.5.27,数据库引擎为InnoDB。之前有同事反应访问testlink慢的问题,目前我正在看高性能MySQL文档。从以下两个方面着手进行优化。
优化MySQL数据库配置。
增大InnoDB缓冲池大小。配置MySQL正确的使用内存量,当然注意不要让服务器内存耗尽。以下给出一个预配置
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
29[mysqld]
# GENERAL
datadir = /var/lib/mysql
socket = /var/lib/mysql/mysql.sock
pid_file = /var/lib/mysql/mysql.pid
user = mysql
port = 3306
default_storage_engine = InnoDB
# InnoDB
innodb_buffer_pool_size = 2G
innodb_log_file_size = 256M
innodb_file_per_table = 1
innodb_flush_method = 0_DIRECT
# MyISAM
key_buffer_size = <value>
# LOGGING
log_error = /var/lib/mysql/mysql-error.log
slow_query_log = /var/lib/mysql/mysql-slow.log
# OTHER
tmp_table_size = 32M
max_heap_table_size = 32M
query_cache_type = 0
query_cache_size = 0
max_connections = <value>
thread_cache = <value>
open_files_limit = 65535
[client]
socket = /var/lib/mysql/mysql.sock
port = 3306优化SQL查询语句和考虑增加索引。
关于数据库性能优化这一块,具体内容非常庞大且复杂,在这里没法通过短短的一个章节文章就能介绍完。这里有一个关于性能调优配置的链接。有兴趣的可以去看一下。
MySQL拓展
对于技术面试来说,考察的核心包含以下两个特点:
- 考察的知识点广,因为不同的公司和不同的面试官技能知识结构是不同的,所以所关注的问题和面试内容也是不同的,所以具备面试知识点广的特点;
- 考察的知识点较深入,这些大厂的面试都是类似的,通常从一个大的面试点切入,然后层层深入,直到问到你不会为止,比如,你了解哪些数据库引擎?这个数据库引擎的特点是什么?这个数据库引擎是如何存储数据的?为什么要采用这种存储方式?等等。
以下八大模块,汇总并介绍MySQL中的典型面试问题
- 第一部分:通用模块。此部分对MySQL整体概念、执行流程、数据库引擎、查询缓存、表空间、回表查询、数据类型间的区别、内存表、临时表、删除表的 n 种方式、枚举、视图、数据恢复等相关知识点对应的面试题进行解答。
- 第二部分:索引模块。索引的好坏直接影响数据库的性能,所以索引的面试题也是面试中必问的问题,此部分为索引对应的面试题合集。
- 第三部分:事务模块。事务决定了程序的稳定性,在 MySQL 中的地位也是首屈一指,也是面试中必问的面试题,此部分为事务对应的面试题合集。
- 第四部分:锁。锁包括:全局锁、表锁、行锁、死锁、乐观锁、悲观锁等,不同的数据库引擎支持的锁支持粒度也是不同的,此部分的面试题,让你彻底搞定锁相关的面试题。
- 第五部分:日志。日志看似不起眼,却是 MySQL 主备同步和容灾恢复以及问题排除的关键,当然也是面试中必问的问题,这部分会对不同的数据库引擎中的重点日志,进行详细的介绍。
- 第六部分:MySQL 操作命令和内置函数。MySQL 的操作命令,对于程序员或者 DBA 来说也是必须具备的一项技能,比如,用户和权限的创建、数据库相关信息的查询等,都离不开对 MySQL 命令行的掌握。对内置函数的掌握程度,代表了你对 MySQL 的掌握程度,善用 MySQL 提供的内置函数,会让你有事半功倍的效果,内置函数也是笔试中必考的面试题。
- 第七部分:性能优化和分布式。性能优化和分布式是面试中决定你高度的关键指标,其中性能优化包括了慢查询的分析和处理,对分布式的掌握体现了你的技术深度。
- 第八部分:开放性问题。很多大公司最后也会问一下没有标准答案的开放性问题,以考察面试者的技术能力边界和对待问题的分析思路,这部分助你更平稳的获得 offer。