1.MySQL 在 Centos 7环境安装
1.1 卸载不要的环境
-
ps ajx |grep mariadb # 先检查是否有 mariadb 存在
-
systemctl stop mariadb.service # 停⽌ mariadb 服务
-
ps ajx |grep mariadb # 再 检查是否有 mariadb 存在
1.2 删除多余的安装包
1.3 获取mysql官⽅yum源
1.4 安装mysql yum 源,对⽐前后yum源
- rpm -Uvh 安装包 #安装mysql yum源
1.5 查看是否能正常工作
- yum list | grep mysql #查看所有的mysql文件
1.6 安装mysql服务
1.7 数据存储位置 查看配置⽂件
- ls /var/lib/mysql#查看数据存储位置
- ls /etc/my.cnf #查看配置文件
1.8 启动服务
1.9 配置 && 登录
- root直接使用:mysql -uroot
- 或mysql -h 127.0.0.1 -P 3306 -u root -p
- 其他用户可以使用: mysql -h 127.0.0.1 -P 3306
2. 数据库基础
2.1 什么是数据库
- 已特定的格式保存好的文件,我们叫做数据库,
- 提供较为便捷的数据的存取服务的软件集合,解决方案 -- mysql数据库
2.1 为什么有数据库
- 文件或者数据库,其实都可以进行数据的存储
- 如果用文件,数据内容的管理工作,需要程序员自己做!
- 数据库的本质: 是对文件的内容提供基本的内容操作,不用程序员(用户)手动的进行数据管理
- 数据库也是"文件系统"
2.2 创建一个数据库的本质
图形化界面的访问数据库的软件 -- client
mysql的生态中,也会提供第三方库,让语言也能直接访问mysql -- client
- 建立一个数据库 create database XXX本质是在linux下建立了一个目录
- 建一张表 的本质是在linux下创建对应的文件
2.3 MySQL架构
- MySQL 是一个可移植的数据库,几乎能在当前所有的操作系统上运行,如 Unix/Linux、Windows、Mac 和 Solaris
- 各种系统在底层实现方面各有不同,但是 MySQL 基本上能保证在各个平台上的物理体系结构的一致性。
2.4 SQL分类
- DDL【data definition language】 数据定义语言,用来维护存储数据的结构 代表指令: create, drop, alter
- DML【data manipulation language】 数据操纵语言,用来对数据进行操作 代表指令: insert,delete,update
- DML中又单独分了一个DQL,数据查询语言,代表指令: select
- DCL【Data Control Language】 数据控制语言,主要负责权限管理和事务 代表指令: grant,revoke,commit
2.5 存储引擎
- show engines;// 查看存储引擎的命令
3. 库的操作
3.1 创建数据库
- create database 名字;// 创建库
- crate database '特殊名字';// 创建特殊名字的库,''会起到转移字符的作用
3.2 字符集和校验规则
字符集->将数据按照特定的编码存储 == mysql的存数据
校验规则->读取数据时候的校验编码 == mysql的取数据
一般字符集和校验规则(集) 匹配的
3.2.1 查看系统默认字符集以及校验规则
- show variables like 'character_set_database';查看系统默认字符集
- show variables like 'collation_database';查看系统默认校验规则
3.3.2 查看数据库支持的字符集 && 校验规则
-
show charset;// 字符集
- show collation;// 效验集
3.4 校验规则对数据库的影响
- 数据库的编码和效验规则,本质会影响对应的数据库内部的表,比如查数据,比较数据
3.5 补充数据库的创建
- create database 库名字 character set 字符集 collate 效验规则
- create database 库名字 charset=字符集 collate 效验规则
3.6 操纵数据库
3.6.1 查看数据库 && 显示创建语句
3.6.2 修改数据库
- alter database 名字 charset=字符集 collation 效验规则
- 对数据库的修改主要指的是修改数据库的字符集,校验规则
3.6.3 数据库删除
- drop database 名字;
- 对应的数据库文件夹被删除,级联删除,里面的数据表全部被删
- 建议不要随便的删除库
3.6.4 备份和恢复
- 备份: mysqldump -P3306 -u root -p 密码 -B 数据库名 > 数据库备份存储的文件路径
- 恢复: mysql> source 数据库备份存储的文件路径
单独备份数据库的表
- mysqldump -u root -p 数据库名 表名1 表名2 > 数据库备份存储的文件路径
备份多个数据库
3.6 查看连接情况
- use 库名字; // 进入这个库 或 使用这个库
- show processlist;// 查看数据库连接情况
4.表的操作
4.1 创建表
- t2 表存储引擎是mysiam,在数据目录中有三个不同的文件
- t2.frm: 表结构
- t2.MYD: 表数据
- t2.MYI: 表索引
4.2 查看表
- Field Type Null Default Extra
- 字段名字 字段类型 是否允许为空 默认值 扩充
4.3 修改表
4.3.1 添加字段
- alter table 表名字 add
- 插入新字段后,对原来表中的数据没有影响:
4.3.2 修改字段
- 修改name,将其长度改成60
- alter table 表名字 modify
4.3.3 删除字段
- alter table 表名字 drop
- 注意: 但删除到只有一个字段的时候就不能删除了
除非使用删除表的命令
4.4 删除表
5. 数据类型
5.1 数据类型分类
5.2 数值类型
5.2.1 tinyint类型
注意 :尽量不使用unsigned,对于int类型可能存放不下的数据,int unsigned同样可能存放不
下,与其如此,还不如设计时,将int类型提升为bigint类型
5.2.2 bit类型
5.2.3 float类型
float [(m, d)] [ unsigned ] : M 指定显示 长度 , d 指定小数 位数 ,占用空间 4 个字节
- 在mysql中是不会发生取整规则的,但它会在保存值时会进行四舍五入
- 当然float类型也有无符号类型,float unsigned
5.2.4 decimal类型
decimal (m, d) [ unsigned ] : 定点数 m 指定 长度 , d 表示小数点的 位数
- decimal整数最大位数m为65。支持小数最大位数d是30。
如果d被省略,默认为0.如果m被省略,默认是10。
- decimal和float很像,也有无符号decimal unsigned,
但是二者的精度是不一样的,float的精度是7
5.3 文本 && 二进制类型
5.3.1 char类型
char (L): 固定长度字符串, L 是可以 存储的长度 ,单位为字符,最大长度值可以为 255
- char(2) 表示可以存放两个字符,可以是字母或汉字,但是不能超过2个, 最多只能是255
5.3.2 varchar类型
varchar (L): 可变长度字符串, L 表示 字符长度 ,最大长度 65535个字节
- varchar长度可以指定为0到65535之间的值,但是有1 - 3 个字节用于记录数据大小,所以说有效字节数是65532。
- 当我们的表的编码是utf8时,varchar(n)的参数n最大值是65532/3=21844[因为utf中,一个字符占用3个字节),
- 如果编码是gbk,varchar(n)的参数n最大是65532/2=32766(因为gbk中,一个字符占用2字节)
5.3.3 char和varchar比较
-
如果数据确定长度都 一样 ,就使用 定长
-
如果数据长度 有变化 , 就使用 变长(varchar) ,
5.4 日期和时间类型
常用的日期有如下三个:
-
date : 日期 'yyyy - mm - dd' ,占用三字节
-
datetime :时间日期格式 'yyyy - mm - dd HH:ii:ss' 表示范围从 1000 到 9999 ,占用八字节
-
timestamp :时间戳,从 1970 年开始的 yyyy - mm - dd HH:ii:ss 格式和 datetime 完全一致,占用四字节
- 添加数据时,时间戳自动补齐
- 更新数据,时间戳会更新
5.5 string类型
5.5.1 enum和set 类型
enum :枚举, “ 单选 ” 类型;
enum(' 选项 1',' 选项 2',' 选项 3',...);
5.5.1 集合查询使用find_ in_ set函数
find_in_set(sub,str_list) :
如果 sub 在 str_list 中,则返回下标;如果不在,返回 0 ; str_list 用逗号分隔的字符串。
6. 表的约束
6.1 空属性
null(默认的)和not null(不为空)
- 在设计myclass表的时候,就约束了插入的数据->班级名和教室,不能为空
6.2 默认值
- 这里的default默认值就像是c++的缺省值一样
6.3 列描述
- 这里的commet就像是c++中的注释,虽然不影响数据,但这是一种规范
6.4 zerofill
- int(11): 整数后面的数字代表的不是字节,而是宽度
- 而这个数字只有在设置zerofill之后才会生效,而zerofill最大的作用就是格式化输出
6.5 主键
primary key 用来唯一的约束该字段里面的数据, 不能重复 , 不能为空 ,一张表中 最多只能有一个主键 ;主键所在的列通常是整数类型
6.5.1 创建主键 && 主键约束
6.5.2 删除主键 && 追加主键
6.5.3 复合主键
-
一般在表创建时就应该设置主键,
-
如果有多个字段作为主键,可以使用 复合主键
6.6 自增长
auto_increment :当对应的字段,不给值,会 自动的被系统触发 ,系统会从当前字段中已经有的 最大值 +1 操作,得到一个新的不同的值。通常和主键搭配使用,作为逻辑主键。
- 这里的auto_increment和c++中的enum枚举很像,
- auot_incremment在需要查找索引值的时候有用
6.7 唯一键
一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。
主键更多的是标识唯一性的。而唯一键更多的是保证在业务上不要和别的信息出现重复
- 唯一键的本质和主键差不多,唯一键允许为空,而且可以多个为空,空字段不做唯一性比较。
6.8 外键
外键约束主要 定义在从表 上,主表则必须是有主键约束或 unique约束。当定义外键后,要求外键列数据必须在主表的主键列存在或为null
foreign key (字段名) references 主表(列)
- 那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入
7. 表的增删改查
7.1 creat->增加
7.1.1 单行数据 + 全列插入
7.1.2 多行数据 + 指定列插入
7.1.3 插入否则更新
insert...on duplicate key update column = value...
7.1.4 替换
7.2 Retrieve->查找
7.2.1 全列查询
7.2.2 指定列查询
7.2.3 查询字段为表达式
7.2.4 为查询结果指定别名
7.2.5 结果去重
- select distinct 字段 from 表名
7.2.6 比较运算符 && 逻辑运算符
比较运算符:
运算符 |
说明 |
>,>=,<,<= |
大于,大于等于,小于,小于等于 |
= |
等于,null 不安全,例如 null = null 的结果是null |
<=> |
等于,null安全,例如 null <=> null的结果是true(1) |
!=,<> |
不等于 |
between a and b |
范围匹配,[a,b],如果 a <= value <= b,返回true(1) |
in(option) |
如果是 option 中的任意一个,返回 TRUE(1)
|
is null
|
是null |
is not null |
不是null |
like |
模糊匹配,%表示任意多个(包括0个) 任意字符;_表示任意一个字符 |
逻辑运算符:
运算符 |
说明 |
and |
多个条件必须都为true(1),结果才是true(1) |
or |
任意一个条件为true(1),结果为true(1) |
not |
条件为true(1),结果为false(0) |
- where 条件中使用表达式,别名不能用在where条件中,
- null 与 null的比较建议使用<=>(是否相等),<>(是否不相等)
7.2.7 结果排序
- asc 为升序(从小到大),desc 为降序(从大到小),默认为 ASC
- 且如果有字段为null,则null在排序中是最小的
7.2.8 筛选分页结果
- select ... from 表名 [where ...] [order by ...] limit n;
- select ... from 表名 [where ...] [order by ...] limit s,n;
- select ... from 表名 [where ...] [order by ...] limit n offset s;
7.3 Updat->改
7.4 Delete->删
7.4.1 删除表中数据
- delete from 表名 [where ...] [order by ...] [limit ...]
7.4.2 截断表
truncate [table] table_name
- 只能对整表操作,不能像 delete 一样针对部分数据操作;
- 实际上 MySQL 不对数据操作,所以比 delete更快,但是truncate在删除数据的时候,并不经过真正的事物,所以无法回滚
- 会重置 auto_increment项
7.4.3 插入查询结果
insert into 表名 [(column) [,colum ...])] select ...
案例: 删除表中的重复记录,重复的数据只能有一份
7.5 聚合函数
聚合统计一定是直接或者间接统计列方向的某些数据
函数
|
说明
|
count ([distinct] expr)
|
返回查询到的数据的 数量
|
sum ([distinct] expr)
|
返回查询到的数据的 总和,不是数字没有意义
|
avg ([distinct] expr)
|
返回查询到的数据的 平均值,不是数字没有意义
|
max ([distinct] expr)
|
返回查询到的数据的 最大值,不是数字没有意义
|
min ([distinct] expr)
|
返回查询到的数据的 最小值,不是数字没有意义
|
7.5.1 count 统计数据数量
7.5.2 sum 统计数据总和
7.5.3 avg 统计数据平均总分
7.5.4 max 求数据的最大值
7.5.5 min求数据的最小值
7.6 group by子句的使用
mysql可以支持按照指定的列进行对数据做分组,我们可以让特定的sql在特定的组内进行某种操作
7.6.1 测试一
7.6.2 测试二
- 在emp表中: 显示薪水大于 1000 的部门,并从中筛选出平均工资小于 2000的 ( 部门, 平均工资)
- having经常和group by搭配使用,它是对聚合统计之后的结果进行筛选,作用有点像些where。
注意: having 在查询语句中必须依赖于group by
7.6.3 小结
- group by是通过分组这样的手段,为未来进行聚合统计提供基本的功能支持(group by一定是配合聚合统计使用的)
- group by后面跟的都是分组的字段依据,只有在group by后面出现的字段,未来在聚合统计的时候,在select 中才能出现
- where vs having 这两个不是冲突的,是相互补充的,但是二者的先后顺序是不一样的
having通常: 是在完成整个分组聚合统计之后,才进行筛选的
where通常: 是在表中数据初步被筛选的时候,才起效果的
7.7 sql查询中各个关键字的执行先后顺序
- from > on > join > where > group by > with > having > select > distinct > order by > limit
8. 函数
8.1 日期函数
函数名称 |
描述 |
current_date() |
当前日期 |
current_time() |
当前时间 |
current_timestamp() |
当前时间戳 |
date(datetime) |
返回datetime参数的日期部分 |
date_add(date,interval d_value_type) |
在date中添加日期或时间 interval后的数据单位可以是: year minute second day |
date_sub(date,interval d_value_type) |
在date中减去日期或时间 interval后的数据单位可以是: year minute second day |
datediff(date1,date2) |
两个日期的差,单位是天 |
now() |
当前日期时间 |
8.1.1 留言表
- select * from msg where date_add(sendtime, interval 2 minute) > now();
8.2 字符串函数
函数名称 |
描述 |
charset(str) |
返回字符串字符集 |
concat(string2 [,...]) |
连接字符串 |
instr(string,substring) |
返回substring在string中出现的位置,没有返回0 |
ucase(string2) |
转换成大写 |
lcase(string2) |
转换成小写 |
left(string2,length) |
从string2中的左边起取length个字符 |
length(string) |
string的长度 |
replace(str,search_str,replace_str) |
在str中用replace_str替换search_str |
strcmp(string1,string2) |
逐字符比较两个字符串的大小 |
substring(str,position,[,lenth]) |
从str的postion开始,取length个字符 |
ltrim(string) rtrim(string) trim(string) |
去除前空格或后空格 |
8.2.1charset 获取字符集
- select charset(ename) from emp;
8.2.2concat 连接字符串
- select concat(name,'的语文是',Chinese,'分,数学是',math,'分')as '分数' from student;
8.2.3length 显示字符串长度(以字节为单位)
8.2.4 replace 字符串替换
- select replace(ename,'S','上海') , ename from emp;
- 将emp表中所有名字中有S的替换成'上海'
8.2.5 substring字符串提取
8.2.6 lcase 字符串转换(小写)
- select concat(lcase(substring(ename,1,1)),substring(ename,2)) from emp;
8.3 数学函数
函数名称 |
描述 |
abs(number) |
绝对值函数 |
bin(decimal_number) |
十进制转换二进制 |
hex(decimal_number) |
转换成十六进制 |
conv(number,from_base,to_base) |
进制转换 |
ceiling(number) |
向上取整 |
floor(number) |
向下取整 |
format(number,deinmal_places) |
格式化,保留小数位数 |
hex(decimalNumber) |
转换成十六进制 |
rand() |
返回随机浮点数,范围[0.0,1.0) |
mod(number,denominator) |
取模,求余数 |
8.4 其他函数
8.4.1 user() 查询当前用户
8.4.2 md5加密
8.4.3 database()显示当前正在使用的数据库
8.4.4 对用户加密
8.4.5ifnull 函数
9. 复合查询(重点)
9.1 解决多表查询的思路:
- 先读题,确定都和那些表有关
- ''无脑''组合形成一张表 -- 多张表转成一张表
- 将多表查询,看做成为一张表的查询
9.2 多表查询
显示部门号为 10 的部门名,员工名和工资
- select ename,sal,dname from emp,dept where emp.depton = dept.deptno
and dept.deptno = 10;
9.3 自连接
自连接是指在同一张表连接查询
显示员工FORD的上级领导的编号和姓名(mgr是员工领导的编号--empno)
9.3.1 使用的子查询
9.3.2 使用多表查询(自查询)
- from emp leader, emp worker,给自己的表起别名,
因为要先做笛卡尔积,所以这里的别名会先识别
9.4 子查询
9.4.1 单行子查询
显示SMITH同一部门的员工
9.4.2 多行子查询
in关键字的使用
查询和 10 号部门的工作岗位相同的雇员的名字,岗位,工资,部门号,但是不包含 10 自
己的
all关键字的使用
显示工资比部门 30 的所有员工的工资高的员工的姓名、工资和部门号
any关键字的使用
显示工资比部门 30 的任意员工的工资高的员工的姓名、工资和部门号(包含自己部门
的员工)
9.4.3 多列子查询
查询和 SMITH 的部门和岗位完全相同的所有雇员,不含 SMITH 本人
9.4.4 终极解决方案 - > 在from子句中使用子查询
select查询到的结果也是一张表,自然也可以跟其他表连接
显示每个高于自己部门平均工资的员工的姓名、部门、工资、平均工资
- 获取各个部门的平均工资,将其看作临时表,
- 注意: 这里的新表需要加别名,像自连接一样,以示区分
8.4.5 合并查询
union && union all 关键字的使用
将工资大于 2500 或职位是 MANAGER 的人找出来
- union会取得两个结果集的并集,并自动去掉结果集中的重复行
- 如何使用的是union all的话,则不会去掉重复行
10 .表的内连和外连
10.1 内连接
显示 SMITH 的名字和部门名称
10.1.1 简略写法
10.1.2 标准写法
- select ename, dname from EMP inner join DEPT on EMP.deptno=DEPT.deptno and ename='SMITH';
10.2 外连接
10.2 .1 左外连接
查询所有学生的成绩,如果这个学生没有成绩,也要将学生的个人信息显示出来
10 .2.1 右外连接
对 stu 表和 exam 表联合查询,把所有的成绩都显示出来,即使这个成绩没有学生与它对应,也要
显示出来
11.索引
11.0 创建海量数据
drop database if exists `bit_index`;
create database if not exists `bit_index` default character set utf8;
use `bit_index`;
-- 构建一个8000000条记录的数据
-- 构建的海量表数据需要有差异性,所以使用存储过程来创建, 拷贝下面代码就可以了,暂时不用理解
-- 产生随机字符串
delimiter $$
create function rand_string(n INT)
returns varchar(255)
begin
declare chars_str varchar(100) default
'abcdefghijklmnopqrstuvwxyzABCDEFJHIJKLMNOPQRSTUVWXYZ';
declare return_str varchar(255) default '';
declare i int default 0;
while i < n do
set return_str =concat(return_str,substring(chars_str,floor(1+rand()*52),1));
set i = i + 1;
end while;
return return_str;
end $$
delimiter ;
-- 产生随机数字
delimiter $$
create function rand_num( )
returns int(5)
begin
declare i int default 0;
set i = floor(10+rand()*500);
return i;
end $$
delimiter ;
-- 创建存储过程,向雇员表添加海量数据
delimiter $$
create procedure insert_emp(in start int(10),in max_num int(10))
begin
declare i int default 0;
set autocommit = 0;
repeat
set i = i + 1;
insert into EMP values ((start+i)
,rand_string(6),'SALESMAN',0001,curdate(),2000,400,rand_num());
until i = max_num
end repeat;
commit;
end $$
delimiter ;
-- 雇员表
CREATE TABLE `EMP` (
`empno` int(6) unsigned zerofill NOT NULL COMMENT '雇员编号',
`ename` varchar(10) DEFAULT NULL COMMENT '雇员姓名',
`job` varchar(9) DEFAULT NULL COMMENT '雇员职位',
`mgr` int(4) unsigned zerofill DEFAULT NULL COMMENT '雇员领导编号',
`hiredate` datetime DEFAULT NULL COMMENT '雇佣时间',
`sal` decimal(7,2) DEFAULT NULL COMMENT '工资月薪',
`comm` decimal(7,2) DEFAULT NULL COMMENT '奖金',
`deptno` int(2) unsigned zerofill DEFAULT NULL COMMENT '部门编号'
);
-- 执行存储过程,添加8000000条记录
call insert_emp(100001, 8000000);
11. 1 常见索引
- 主键索引(primary key)
- 唯一索引(unique)
- 普通索引(index)
- 全文索引(fulltext)--解决中子文索引问题。
11.2 索引的重要性
- 在对数据进行增删查改的时候,本质是在内存中进行的
- 而索引的本质就是协助查找
11.3 MySQL 与磁盘交互基本单位
11.4 索引的理解
11.4.1 mysql的所有操作都是在内存中的
- mysql本质就是一个进程,一定是在OS之上运行的
- 对mysql内部的数据等做操作(CURD)的时候,本质其实就是操作文件内容
- 文件必须先被打开,对文件内容做任何操作,都不是直接在磁盘设备上做操作的
- 任何磁盘数据,在进程中要进行操作,本质都必须在内存中进行
msql内部一定要有自己的内存管理,且它启动时会预先申请一批内存空间
11.4.2 理解单个Page
- MySQL 中要管理很多数据表文件,而要管理好这些文件,就需要 先描述,在组织 ,
- 我们目前可以简单理解成一个个独立文件是由一个或者多个Page构成的
11.5 页目录 && 索引所使用的数据结构
页目录
- 虽然插入的时候是乱序的,但查的时候却是有序的,或者说page内部的数据是有序的
- 且又因为page内部的数据是有序的,则就引入页内目录
单页情况
多页情况
目录页
- 不同的page,在mysql中,都是16kb,使用prev和next构成双向链表
- 所有的数据,全部都在叶子节点
- 表中的所有带有主键的数据,都是以B+的形式呈现的,
其中,B+数和数据是耦合在一起的,聚簇索引->InnoDB
小结:
- Page分为目录页和数据页。目录页只放各个下级Page的最小键值。
- 查找的时候,自顶向下找,只需要加载部分目录页到内存,即可完成算法的整个查找过程,大大减少了IO次数
主键索引:
- 具有主键的表,一表一个B+树
- 如果没有主键,mysql 会自动形成隐藏主键
- B+中所有的叶子节点,路上节点,都是按需加载到mysql page中的
InnoDB 在建立索引结构来管理数据的时候,其他数据结构为何不行?
- 链表,线性遍历不行
-
二叉搜索树,可能退化成为线性结构
-
AVL && 红黑树,深度太深
-
11.6 聚簇索引 VS 非聚簇索引
- myisam存储引擎,数据和主键索引分开的
- innodb存储引擎,数据和主键索引放在一起的
11.7 索引操作
11.7.1 创建主键索引
11.7.2 唯一索引的创建
11.7.3 普通索引的创建
create table user8(id int primary key,
name varchar ( 20 ),
email varchar ( 30 ),
index(name)
);
普通索引的特点:
-
一个表中可以有 多个普通索引 ,普通索引在实际开发中用的比较多
-
如果某列需要创建索引,但是该列有 重复的值 ,那么我们就应该使用 普通索引
11.7.4 全文索引的创建
当对文章字段或有大量文字的字段进行检索时,会使用到全文索引。 MySQL 提供全文索引机制,但是有要求,要求表的存储引擎必须是MyISAM ,而且默认的全文索引支持英文, 不支持中文 。如果对中文进行全文检索,可以使用sphinx 的中文版 (coreseek);
直接查询
全文索引查询
11.7.5 查询索引
- show keys from 表名
- show index from 表名;
-
desc 表名;
11.7.6 删除索引
12. 事务管理
一个或多个sql语句的集合,就是事务,事务 = 数据结构 + 算法
12.1 例子
业务需求 : 张三给李四转50
- 需要保证张三账号少了50,李四账号多了50,
- 一件或多件事,必须做完(绝对成功,绝对失败),不要出现中间操作这样的概念 -- 原子
小结
-
上层看来比较简单的需求,可能对应的后端要做很多的工作,
组合起来才是一个完整的需求解决的方案
-
事务本身不是数据库类软件天然有的,
事务本质工作其实是为了简化程序员的工作模型
12.2 事务的特性
-
原子性:
一个事务( transaction )中的所有操作,要么全部完成,要么全部不完成,不会结束在中 间某个环节。
事务在执行过程中发生 错误 ,会被 回滚 (Rollback )到事务开始前的状态,就像这个 事务从来没有执行过一样。
-
一致性:
在 事务开始之前 和 事务结束 以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,
这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。
-
隔离性:
数据库允许 多个并发事务 同时对其数据进行 读写 和 修改 的能力,隔离性可以防止多个事务
并发执行时由于交叉执行而导致数据的不一致。事务隔离分为不同级别,包括
读未提交( Read uncommitted)、读提交( read committed) 、
可重复读( repeatable read) 和串行化(Serializable)
- 持久性:事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失
-
这四个属性,可以简称为 ACID (单词的首字母)
12.3 事务的版本支持
- 在 MySQL 中只有使用了 Innodb 数据库引擎的数据库或表才支持事务, MyISAM 不支持
12.4 事务提交方式
默认的提交方式是自动提交
12.5 事务常见操作方式
12.5.1 证明事务的开始与回滚
12.5.2 commit对mysql数据的影响
- 终端A未commit,客户端崩溃,MySQL自动会回滚(隔离级别设置为读未提交)
- 终端A commit了,客户端崩溃,MySQL数据不会在受影响,已经持久化
12.5.3 begin操作会自动更改提交方式,不会受MySQL是否自动提交影响
小结-> 证明原子性 , 一致性
事务操作注意事项
12. 6事务隔离级别
-
读未提交【 Read Uncommitted 】
-
读提交【 Read Committed 】
-
-
12.6.1 查看与设置隔离性
12.6.2 读未提交【Read Uncommitted】
set global transaction isolation level read uncommitted ;
- 终端A事务在没有commit的时候,终端B也会拿到终端A事务的数据(脏读)
12.6.3 读提交【Read Committed】
set global transaction isolation level read committed;
- 终端A事务在没有commit的时候,终端B得不到终端A事务的数据
- 注意: 这可能引起在两个终端在两个事务中,数据重复的现象(幻读)-> 不可重复读
12.6.4 可重复读【Repeatable Read】
set global transaction isolation level repeatable read ;
- 可重复度本质其实就是在一个事务内部,不受任何事务操作的影响,每次查到的数据都是一致性
12.6.5 串行化【serializable】
set global transaction isolation level serializable;
- 对所有操作全部加锁,进行串行化,不会有问题,
- 它在每个读的数据行上面加上共享锁,。但是可能会导致超时和锁竞争效率很低,几乎完全不会被采用
12.6.6 小结
13. 视图
13.1 基本操作
- 创建视图: create view 视图名 as select语句;
- 修改了视图,对基表数据有影响
- 修改了基表,对视图有影响
- 删除视图: drop view 视图名
13.2 视图规则和限制
- 与表一样,必须唯一命名(不能出现同名视图或表名)
- 创建视图数目无限制,但要考虑复杂查询创建为视图之后的性能影响
- 视图不能添加索引,也不能有关联的触发器或者默认值
- 视图可以提高安全性,必须具有足够的访问权限
- order by 可以用在视图中,但是如果从该视图检索数据 select 中也含有 order by ,那么该视图 中的 order by 将被覆盖
- 视图可以和表一起使用
14. 用户管理
- 用户管理: 是普通用户只能管理某一个数据库,这样就增强了安全性
14.1 用户
14.1.1 用户信息
14.1.2 创建用户
create user '用户名'@'登陆主机/ip' identified by '密码';
14.1.3 删除用户
drop user ' 用户名 ' @ ' 主机名 '
14.1.4 用户登录
mysql -u用户 -h'登录方式' -p
13.1.5 修改用户密码
13.2 数据库的权限
13.2.1 给用户授权
grant 权限列表 on 库.对象名 to '用户名'@'登陆位置' [identified by '密码']
-
grant select on ...
grant select , delete , create on ....
grant all [privileges] on ... -- 表示赋予该用户在该对象上的所有权限
- *.* : 代表本系统中的所有数据库的所有对象(表,视图,存储过程等)
-
库.* : 表示某个数据库中的所有数据对象 ( 表,视图,存储过程等 )
-
identified by可选 。 如果用户存在,赋予权限的同时修改密码 , 如果该用户不存在,就是创建用户
注意:如果发现赋权限后,没有生效,执行如下指令:
14.2.2 回收权限
revoke 权限列表 on 库 . 对象名 from ' 用户名 ' @ ' 登陆位置 ' ;
15. mysql connect
- 保证mysql服务有效
- 在官网上下载合适自己平台的mysql connect库,以备后用
mysqlClient.cc
#include
#include
#include
#include
#include
#include
using namespace std;
string host = "127.0.0.1"; //'localhost'
string user = "whb";
string passwd = "123456";
string db = "104_105_db";
unsigned int port = 8080;
int main()
{
// cout << "mysql client version: " << mysql_get_client_info() << endl;
// 0. 初始化mysql对象
MYSQL *msql = mysql_init(nullptr);
if (msql == nullptr)
{
cerr << "mysql_init error" << endl;
exit(1);
}
// 1. 登陆认证
if (mysql_real_connect(msql, host.c_str(), user.c_str(), passwd.c_str(), db.c_str(), port, nullptr, 0) == nullptr)
{
cerr << "mysql_real_connect error" << endl;
exit(2);
}
mysql_set_character_set(msql, "utf8");
cout << "mysql_real_connect success" << endl;
// string sql = "insert into emp values (666, '张飞', 789.987)";
// string delSql = "delete from emp where id=666";
// string updateSql = "update emp set name='赵云' where id=666";
// string selectSql = "select * from emp";
char sql[1024];
while (true)
{
printf("mysql> ");
fgets(sql, sizeof sql, stdin); //' select * from user '
// 调用成功的时候,返回值是0, 否则就是1
int n = mysql_query(msql, sql);
if (strcasestr(sql, "select") && n == 0)
{
cout << "result: " << n << endl;
// 对结果进行解析
MYSQL_RES *res = mysql_store_result(msql);
if (res == nullptr)
exit(0);
int rows = mysql_num_rows(res);
int fields = mysql_num_fields(res);
MYSQL_FIELD *fname = mysql_fetch_fields(res);
for (int j = 0; j < fields; j++)
cout << fname[j].name << "\t|\t";
cout << endl;
MYSQL_ROW line;
for (int i = 0; i < rows; i++)
{
line = mysql_fetch_row(res); // 按行获取文件的内容,自动会更新行数
for (int j = 0; j < fields; j++)
cout << line[j] << "\t|\t";
cout << endl;
}
printf("%d rows in set\n", rows);
}
else
{
cout << "execl sql : " << sql << " done" << endl;
}
}
// 关闭mysql对象
mysql_close(msql);
return 0;
}
makefile
mysqlClient:mysqlClient.cc
g++ -o $@ $^ -std=c++11 -L/lib64/mysql -lmysqlclient
.PHONY:clean
clean:
rm -rf mysqlClient
-
初始化接口: MYSQL *mysql_init(MYSQL *mysql) ;
- 链接数据库接口: MYSQL *mysql_real_connect(MYSQL *mysql, const char *host,
const char * user , const char * passwd , const char * db , unsigned int port , const char *unix_socket , unsigned long clientflag )
-
发送mysql请求: int mysql_query ( MYSQL * mysql , const char * q );
sql 执行完以后,如果是 查询语句 ,我们当然还要读取数据,如果是 update , insert 等语句,那么就看下操 作成功与否即可。我们来看看如何获取查询结果: 如果mysql_query 返回成功,那么我们就通过 mysql_store_result这个函数来读取结果。原型如下:
另外,mysql C api还支持事务等常用操作
- my_boolSTDCALLmysql_autocommit(MYSQL*mysql,my_boolauto_mode);
- my_boolSTDCALLmysql_commit(MYSQL*mysql);
- my_boolSTDCALLmysql_rollback(MYSQL*mysql);