MySQL

不管现实多么惨不忍睹,都要持之以恒地相信,这只是黎明前短暂的黑暗而已。不要惶恐眼前的难关迈不过去,不要担心此刻的付出没有回报,别再花时间等待天降好运。真诚做人,努力做事!你想要的,岁月都会给你。MySQL,希望对大家有帮助,欢迎收藏,转发!站点地址:www.bmabk.com,来源:原文

1.MySQL
1.1.安装
  • 安装mysql5.7.26版本,按顺序安装
  • mysql5.7是一个较大的版本更新,新特性比较多。
1.2.卸载
  1. 打开任务管理器,选择服务,找到mysql,选择停止服务
  2. 去mysql的安装目录找到my.ini文件:找到并复制 datadir=“C:/ProgramData/MySQL/MySQL Server x.x/Data/” 路径到我的电脑
  3. 找到控制面板,将mysql相关联的全部卸载干净
  4. 将之前安装目录下的mysql目录删除,如果存在的话
  5. 删除C:/ProgramData隐藏目录下的MySQL文件夹。
  6. 运行regedit,删除HKEY_LOCAL_MACHINE\SYSTEM\ControlSet002\Services\Eventlog\Application\MySQL文件夹。(如果存在)
    删除HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\MySQL文件夹。(如果存在)
1.3.配置
  • MySQL服务启动
    1. 手动。
    2. cmd–> services.msc 打开服务的窗口
    3. 使用管理员打开cmd
      • net start mysql : 启动mysql的服务
      • net stop mysql : 关闭mysql服务
  • MySQL登录
    1. mysql -uroot -p密码
    2. mysql -hip -uroot -p连接目标的密码
    3. mysql –host=ip –user=root –password=连接目标的密码

      也可以省略密码,回车后再输入,避免被看到

  • MySQL退出
    1. exit
    2. quit
  • MySQL目录结构
    1. MySQL安装目录:basedir=”C:/Program Files/MySQL/MySQL Server 5.7/“
      • 配置文件 my.ini
    2. MySQL数据目录:datadir=“C:/ProgramData/MySQL/MySQL Server 5.7/Data/”
      • 数据库:文件夹
      • 表:文件
      • 数据:数据
1.4.SQL
1.4.1.什么是SQL?
  • Structured Query Language:结构化查询语言
  • 其实就是定义了操作所有关系型数据库的规则。每一种数据库操作的方式存在不一样的地方,称为“方言”。
1.4.2.SQL通用语法
  • SQL 语句可以单行或多行书写,以分号结尾。
  • 可使用空格和缩进来增强语句的可读性。
  • MySQL 数据库的 SQL 语句不区分大小写,关键字建议使用大写。
  • 3 种注释
    • 单行注释: – 注释内容 或 # 注释内容(mysql 特有)
  • 多行注释: /* 注释 */
    • sql语句后面+comment “注释内容”,也可以达到解释说明的效果
1.4.3.SQL分类
  1. DDL(Data Definition Language)数据定义语言:用来定义数据库对象:数据库,表,列等。关键字:create, drop,alter 等
  2. DML(Data Manipulation Language)数据操作语言:用来对数据库中表的数据进行增删改。关键字:insert, delete, update 等:
  3. DQL(Data Query Language)数据查询语言:用来查询数据库中表的记录(数据)。关键字:select, where 等
  4. DCL(Data Control Language)数据控制语言(了解):用来定义数据库的访问权限和安全级别,及创建用户。关键字:GRANT, REVOKE 等
  5. TPL(Transaction Processing Language)事务处理语言:作为一个单独单元的一条或者多条SQL语句组成这个单元的每一条SQL语句都是相互依赖的,必须每一条SQL语句都成功的执行,才可以说这个事务成功的执行了 如果有一条语句执行出错,那么整个事务就会回滚,回到事务开始以前的状态。
1.5.操作数据库(DDL)
1.5.1.C(Create):创建
# 创建数据库:
	create database 数据库名称;
# 创建数据库,判断不存在,再创建:
    create database if not exists 数据库名称;
# 创建数据库,并指定字符集
    create database 数据库名称 character set 字符集名;
# 创建数据库,并指定校对规则,校对规则指的就是是否需要区分大小写,用于数据排序
	create database 数据库名称 character set 字符集名 collate 校对规则
# for example:
    create database temp character set utf8 collate utf8_generic_ci;  -- 不区分大小写
1.5.2.R(Retrieve):查询
# 查询所有数据库的名称:
    show databases;
# 查询某个数据库的字符集:查询某个数据库的创建语句
    show create database 数据库名称;
1.5.3.U(Update):修改
# 修改数据库的字符集
	alter database 数据库名称 character set 字符集名称;
# 修改数据库的校对规则
	alter database 数据库名称 collate 校对规则;
# for example:
    alter database temp character set utf8 collate utf8_bin;  -- 区分大小写
1.5.4.D(Delete):删除
# 删除数据库
    drop database 数据库名称;
# 判断数据库存在,存在再删除
    drop database if exists 数据库名称;
1.5.5.使用数据库
# 查询当前正在使用的数据库名称
    select database();
# 使用数据库
    use 数据库名称;
1.6.操作表(DDL)
1.6.1.C(Create):创建
create table 表名(
	列名1 数据类型1,
	列名2 数据类型2,
	....
	列名n 数据类型n
);

create table student(
			id int,
			name varchar(32),
			age int ,
			score double(4,1),
			birthday date,
			insert_time timestamp
		)character set gbk;
		# 注意:最后一列,不需要加逗号(,)
		# 如果未指定表的字符集,那么默认与表所在的数据库相同
		
# 复制表:
	create table 表名 like 被复制的表名;
  • 数据库数据类型:
    1. 整数类型
      数据类型 占用字节 说明
      TINYINT 1 很小的整数
      SMALLINT 2 小的整数
      MEDIUMINT 3 中等大小的整数
      INT 4 普通大小的整数
      BIGINT 8 大整数
      • 如,age int,
    2. 小数类型
      类型名称 占用字节 说明
      FLOAT(M,D) 4 单精度浮点数
      DOUBLE(M,D) 8 双精度浮点数
      DECIMAL(M,D) M+2 定点数
      • 其中M为精度,表示一共可存储的位数,D为标度,表示小数的位数
      • float和double都是固定长度,会进行四舍五入
        • 如,score double(5,2),小数一共有五位,小数点后保留两位小数
      • decimal 类型不同于float或double,decimal 实际是以字符串存放的,它的存储空间并不固定,而是由精度 M 决定的。
        • 括号中的数字M表示该数据类型的显示宽度,指定能够显示的数值中数字的个数。显示宽度只是指明MySQL最大可能显示的数字个数,数值的位数小于指定的宽度时会由空格填充,如果大于显示宽度的值,只要该值不超过该类型的取值范围数值依然可以插入,而且能够显示出来。
    3. 日期和事件类型
      类型名称 日期格式 占用字节
      YEAR YYYY (2021) 1
      TIME HH:MM:SS (10:20:00) 3
      DATE YYYY-MM-DD (2021-3-2) 3
      DATETIME YYYY-MM-DD HH:MM:SS 8
      TIMESTAMP YYYY-MM-DD HH:MM:SS 4
      • year:是个整型,插入年份可以不加 ’ ‘,其余的都要加 ’ ’
      • date:日期,只包含年月日,yyyy-MM-dd
      • datetime:日期,包含年月日时分秒 yyyy-MM-dd HH:mm:ss
      • timestamp:时间戳类型 包含年月日时分秒 yyyy-MM-dd HH:mm:ss
        • 如果将来不给这个字段赋值,或赋值为null,则默认使用当前的系统时间,来自动赋值
        • datetime 和 timestamp 虽然显示的格式是一样的,但是它们有很大的区别
          1. datetime 的系统默认值是 NULL, 而 timestamp 的系统默认值是 当前时间 now()(now函数,表示当前时间);
          2. datetime 存储的时间与时区无关,而 timestamp 与时区有关
        create table time_test(
        	t1 year,
        	t2 time,
        	t3 date,
        	t4 datetime,
        	t5 timestamp
        );
        
        insert into time_test values(20221,'15:00:00','2021-03-05','2021-03-05 15:00:00','2021-03-05 15:00:00');
        select * from time_test;
        
        # now()函数,表示当前时间
        insert into time_test values(now(),now(),now(),now(),now());
        
        # 修改了时区以后,datetime没有变化,但是timestamp变了,增加了两个小时。
        set time_zone='+10:00'; # 东十区
        
    4. 字符串类型
      类型名称 占用字节 说明
      CHAR(M) M, 1 <= M <= 255 固定长度字符串
      VARCHAR(M) L+1, L <=M, 1 <=M <=255 变长字符串
      TINYTEXT L+1, L < 2^8 非常小的文本字符串
      TEXT L+2, L < 2^16 小的文本字符串
      MEDIUMTEXT L+3, L < 2^24 中等大小的文本字符串
      LONGTEXT L+4, L < 2^32 大的文本字符串
      ENUM 1 或者 2个字节,取决于枚举的数目,最大 65535个 枚举类型
      SET 1,2,3,4或8个字节 集合类型
      • 字符串大小
        • name varchar(20):姓名最大20个字符
        • zhangsan 8个字符
        • 张三 2个字符
      • ENUM 类型总有一个默认值,当ENUM 列声明为NULL,则默认值为NULL。如果 ENUM 列被声明为 NOT NULL,则其默认值为列表的第一个元素。
         # 枚举类型 只能取一个
        create table t_enum (
        	name enum('bob','ali','tony')
        );
        insert into t_enum values ('bob');
        insert into t_enum values ('jack');
        select * from t_enum;
        
        # 集合类型,可以取一个或者多个
        create table t_set (
        	name set('bob','ali','jack')
        );
        insert into t_set values ('bob');
        insert into t_set values ('bob,ali');
        insert into t_set values ('bob,tony');
        select * from t_set;
        
    5. 二进制类型
      类型名称 占用字节 说明
      BIT(M) [(m+7)/8] 位字节类型
      BINARY(M) M 固定长度的二进制字符串
      VARBINARY(M) M+1 可变长度的二进制字符串
      TINYBLOB(M) L+1, L < 2^8 非常小的 BLOB
      BLOB(M) L+2, L < 2^16 小的 BLOB
      MEDIUMBLOB(M) L+3, L < 2^24 中等大小的BLOB
      LONGBLOB(M) L+4, L < 2^32 非常大的BLOB
      • 字符串类型存储的是非二进制字符串(字符字符串)。
      • 二进制类型存储的是二进制字符串(字节字符串)。
1.6.2.R(Retrieve):查询
# 查询当前数据库中所有的表名称
    show tables;
# 查询表结构
    desc 表名;
    describe 表名; -- mysql专属
# 查询建表语句(详细信息,如编码格式,数据类型等)
	show creat table 表名;
1.6.3.U(Update):修改
# 修改表名
   rename table 表名 to 新的表名;  -- mysql专属
   alter table 表名 rename to 新的表名;
# 修改表的字符集
   alter table 表名 character set 字符集名称;
# 修改字符集以及校对规则
   alter table user2 character set utf8mb4 collate utf8mb4_general_ci;
# 添加一列
   alter table 表名 add 列名 数据类型;	# 添加到最后一列
   alter table 表名 add cloumn 列名 数据类型;	# 添加到最后一列
   alter table 表名 add 列名 数据类型 AFTER 已经存在的某列;	# 添加到某列后面
   alter table 表名 add 列名 数据类型 not null first;    # 添加到第一列
# 修改列名称 类型
   alter table 表名 modify 列名 新数据类型;   -- 只修改数据类型 
   alter table 表名 change 列名 新列名 新数据类型;  -- 既可以修改名称,又可以修改数据类型
# 修改列的字符集
   alter table 表名 change 列名 新列名 新数据类型 character set 字符集名称;
# 删除列
   alter table 表名 drop 列名;
1.6.4.D(Delete):删除
drop table 表名;
drop table if exists 表名 ;
1.7.增删改表中数据(DML)
1.7.1.添加数据:
语法:insert into 表名(列名1,列名2,...列名n) values(值1,值2,...值n);
    注意:
    1. 列名和值要一一对应。
    2. 如果表名后,不定义列名,则默认给所有列添加值
         insert into 表名 values(值1,值2,...值n);
    3. 除了数字类型,其他类型需要使用引号(单双都可以)引起来
1.7.2.删除数据:
语法:delete from 表名 [where 条件]
	注意:
    1. 如果不加条件,则删除表中所有记录。
    2. 如果要删除所有记录
       1. delete from 表名; -- 不推荐使用。有多少条记录就会执行多少次删除操作
       2. TRUNCATE TABLE 表名; -- 推荐使用,效率更高 先删除整张表,然后再创建一张一样的表。
1.7.3.修改数据:
语法:update 表名 set 列名1 = 值1, 列名2 = 值2,... [where 条件];
# 注:不加条件的话会修改所有的数据

# 修改表中数据默认值为0(表中无数据)
alter table 表名 alter column 字段 set default '0';

# 修改表中数据默认值为0(表中有数据)
# 先将已有数据全部修改为0
update 表名 set 字段=0;
# 再将以后添加进来的数据默认修改为0
alter table 表名 alter column 字段 set default '0';
1.8.查询表中的记录(DQL)
# 查询所有数据,工作中尽量避免
select * from  表名;
1.8.1.语法
select		-- 5
	字段列表  
from		-- 1
	表名列表
where		-- 2
	条件列表
group by	-- 3
	分组字段
having		-- 4
	分组之后的条件
order by	-- 6
	排序
limit
	分页限定

数字编号为执行顺序

1.8.2.基础查询
  1. 多个字段的查询:select 字段名1,字段名2… from 表名;
    注意:如果查询所有字段,则可以使用来替代字段列表。
  2. 去除重复:distinct
  3. 计算列
    • 一般可以使用四则运算计算一些列的值。(一般只会进行数值型的计算)
    • ifnull(表达式1,表达式2):null参与的运算,计算结果都为null
      • 表达式1:哪个字段需要判断是否为null
      • 表达式2:如果表达式1字段为null后的替换值。
  4. 起别名:as(as也可以省略)
# 过滤班级字段相同的数据
select distinct(class) from student;

# 起别名
select class as cls from student as stu;
1.8.3.条件查询
  1. where子句后跟条件
  2. 运算符
    • >、< 、<= 、>= 、=、!= 、<>
    • between … in
    • in (集合) ,not in
    • LIKE:模糊查询
      • not like:取反
      • 通配符:
        • _ : 匹配单个任意字符
        • % :匹配任意个数的任意字符
    • is null,is not null
    • and 或 &&
    • or 或 ||
    • not 或 !
  • 常用语句举例
-- 查询年龄大于20岁
select * from student where age > 20;
-- 查询年龄大于等于20岁
select * from student where age >= 20;
-- 查询年龄等于20岁
select * from student where age = 20;

-- 查询年龄不等于20岁
select * from student where age != 20;
select * from student where age <> 20;

-- 查询年龄大于等于20 小于等于30
select * from student where age >= 20 && age <=30;
select * from student where age >= 20 and age <=30;
select * from student where age between 20 and 30;

-- 查询年龄22岁,18岁,25岁的信息
select * from student where age = 22 or age = 18 or age = 25
select * from student where age in (22,18,25);
-- 查询年龄除22岁,18岁,25以外的信息,not in 表示筛选结果不在列表内
select * from student where age not in (22,18,25);

-- 查询英语成绩为null
-- select * from student where english = null; -- 不对的。null值不能使用 = (或!=) 判断
select * from student where english is null;

-- 查询英语成绩不为null
select * from student where english is not null;

-- 查询姓马的有哪些,模糊查询like
select * from student where name like '马%';

-- 查询姓名第二个字是化的人
select * from student where name like "_化%";

-- 查询姓名是3个字的人
select * from student where name like '___';

-- 查询姓名中包含德的人
select * from student where name like '%德%';
1.8.4.排序查询
  1. 语法:
    • order by 子句
    • order by 排序字段1 排序方式1 , 排序字段2 排序方式2…
  2. 排序方式:
    • asc:升序,默认的。
    • desc:降序。
# 按数学成绩排序查询
select * from student order by math asc;
# 按语文+数学成绩降序排序
select * from student order by (math + chinese) desc;
# 按语文升序,数学降序排序,语文相同时,才会按数学成绩排序
select * from student order by chinese asc, math desc;
# 查询英语成绩第一名的学生信息
select * from student order by english desc limit 1;

注意:如果有多个排序条件,则当前边的条件值一样时,才会判断第二条件

1.8.5.聚合函数
  • 将一列数据作为一个整体,进行纵向的计算。
    • count:计算个数
      1. 一般选择非空的列:主键
      2. 用法:count(*)
    • max:计算最大值
    • min:计算最小值
    • sum:计算和
    • avg:计算平均值

    注意:聚合函数的计算,排除null值。
    解决方案:

    1. 选择不包含非空的列进行计算
    2. IFNULL函数
-- 查询表中共计多少数据
select count(id) from student;
-- 查询姓黄的姓名为三个字的人数
select count(*) from student where name like "黄__";
-- 查询语文总分,数学总分
select sum(chinese),sum(math) from student;
-- 查询语文平均分
select avg(chinese) from student;
-- 查询数学最高分,最高低
select max(math) from student;
select min(math) from student;
1.8.6.分组查询
  • 语法:group by 分组字段;
  • 注意:
  1. 分组之后查询的字段:分组字段、聚合函数
  2. where 和 having 的区别:
    1. where 在分组之前进行限定,如果不满足条件,则不参与分组。having在分组之后进行限定,如果不满足结果,则不会被查询出来
    2. where 后不可以跟聚合函数,having可以进行聚合函数的判断。
-- 按照性别分组。分别查询男、女同学的平均分
select sex , avg(math) from student group by sex;

-- 按照性别分组。分别查询男、女同学的平均分,人数
select sex , avg(math),count(id) from student group by sex;

-- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人,不参与分组
select sex , avg(math),count(id) from student where math > 70 group by sex;

-- 按照性别分组。分别查询男、女同学的平均分,人数 要求:分数低于70分的人不参与分组, 分组之后,人数要大于2个人
select sex , avg(math),count(id) from student where math > 70 group by sex having count(id) > 2;
select sex , avg(math),count(id) 人数 from student where math > 70 group by sex having 人数 > 2;

-- 按班级分组查询
-- select * from student group by class;  -- 报错
select class from student group by class;
-- 按班级分组,把名字,语文分数,语文平均分,每个字段拼在一个单元格里
select group_concat(name),class,group_concat(chinese),avg(chinese) from student group by class;
1.8.7.分页查询
  • 语法:limit 开始的索引,每页查询的条数;
  • 公式:开始的索引 = (当前的页码 – 1) * 每页显示的条数
  • limit 是一个MySQL”方言”
-- 每页显示3条记录 

select * from student limit 0,3; -- 第1页
select * from student limit 3,3; -- 第2页
select * from student limit 6,3; -- 第3页

-- 默认,前的数组为0
select * from student limit 3;  -- 第1页
-- 动态配置
select * from student limit (pageIndex -1) *pigeSize, pageSize;
1.8.8.测试计算
  • SELECT 3*2; – 计算表达式3×2的值
  • SELECT NOW(); – 查看当前的时间
  • SELECT TRIM(’ ab cd ‘); – 修剪字符串’ ab cd ‘左右两边的空白
  • SELECT CONCAT(‘ab’,‘cd’); – 拼接字符串’ab’和’cd’
1.8.8.综合Example
CREATE TABLE student(
    id int, -- 编号
    name varchar(10), -- 姓名
    age int, -- 年龄
    sex varchar(5), -- 性别
    address varchar(20), -- 地址
    math int, -- 数学
    english int -- 英语
)character set utf8;

insert into student(id,name,age,sex,address,math,english) VALUES (1,'马云',55,'男','杭州',66,78),(2,'马化腾',45,'男','深圳',98,87),(3,'马涛',55,'男','香港',56,77),(4,'柳岩',20,'女','湖南',76,65),(5,'柳青',20,'男','湖南',86,NULL),
(6,'刘德华',57,'男','香港',99,99),(7,'马德',22,'女','香港',99,99),(8,'德玛西亚',18,'男','南京',56,65);


#基础查询

-- 计算math和English的和
select name,math,english,math+english from student;
-- 如果有null参与的计算
select name,math,english,math+ifnull(english,0) from student;
-- 起别名
select name,math,english,math+ifnull(english,0) as 总分 from student;
-- 起别名可以省略as
select name,math 数学,english 英语 ,math+ifnull(english,0) 总分 from student;


# 运算符
/* 
>、<、<=、>=、=、<>    <>在 SQL 中表示不等于,在 mysql 中也可以使用 != 没有 ==
BETWEEN...AND		 在一个范围之内,如:between 100 and 200相当于条件在 100 到 200 之间,包头又包尾
IN(集合)				集合表示多个值,使用逗号分隔
LIKE '张%'			模糊查询
IS NULL				 查询某一列为 NULL 的值,注:不能写=NULL
*/

-- 查询 math 分数大于 80 分的学生
select * from student where math>80;

-- 查询 english 分数小于或等于 80 分的学生
select * from student where english <=80;

-- 查询 age 等于 20 岁的学生
select * from student where age = 20;

-- 查询 age 不等于 20 岁的学生,注:不等于有两种写法
select * from student where age <> 20;
select * from student where age != 20;


# 逻辑运算符
/*
and 或 && 	与,SQL 中建议使用前者,后者并不通用。
or 或 ||		或
not 或 !		非
*/

-- 查询 age 大于 35 且性别为男的学生(两个条件同时满足)
select * from student where age>35 and sex='男';

-- 查询 age 大于 35 或性别为男的学生(两个条件其中一个满足)
select * from student where age>35 or sex='男';

-- 查询 id 是 1 或 3 或 5 的学生
select * from student where id=1 or id=3 or id=5;


# in 关键字
/*
SELECT 字段名 FROM 表名 WHERE 字段 in (数据 1, 数据 2...);
in 里面的每个数据都会作为一次条件,只要满足条件的就会显示
*/

-- 查询 id 是 1 或 3 或 5 的学生
select * from student where id in(1,3,5);

-- 查询 id 不是 1 或 3 或 5 的学生
select * from student where id not in(1,3,5);


# 范围查询
/*
BETWEEN 值 1 AND 值 2		表示从值 1 到值 2 范围,包头又包尾
比如:age BETWEEN 80 AND 100 相当于: age>=80 && age<=100
*/

-- 查询 english 成绩大于等于 75,且小于等于 90 的学生
select * from student where english between 75 and 90;


# like 关键字  表示模糊查询
select * from 表名 where 字段名 like '通配符字符串';


# MySQL 通配符
/*
%	匹配任意个数的任意字符
_	匹配一个字符
*/

-- 查询姓马的学生
select * from student where name like '马%';

-- 查询姓名是马的学生
select * from student where name like '马';

-- 查询姓名中包含'德'字的学生
select * from student where name like '%德%';

-- 查询姓马,且姓名有两个字的学生
select * from student where name like '马_';

-- 去除重复的结果集
select distinct address from studemt;
select distinct name,address from srudent;

1.9.约束
1.9.1.概念:
  • 对表中的数据进行限定,保证数据的正确性、有效性和完整性。
1.9.2.分类:
  1. 主键约束:primary key
  2. 非空约束:not null
  3. 唯一约束:unique
  4. 外键约束:foreign key
-- 非空约束:not null,值不能为null

    1. 创建表时添加约束
       creat table stu(
        id int,
        name varchar(20) not null -- name为非空
       );
    2. 创建表完后,添加非空约束
       alter table stu modify name varchar(20) not null;

    3. 删除name的非空约束
       alter table stu modify name varchar(20);


   
-- 唯一约束:unique,值不能重复

    1. 创建表时,添加唯一约束
       creat table stu(
        id int,
        phone_number varchar(20) unique -- phone_number为唯一约束
       );
    注意mysql中,唯一约束限定的列的值可以有多个null
    若:重复插入了被唯一约束的值,这个时候另一个字段是有自增长主键约束的,那么虽然插入失败,但是mysql计数器仍然会+1
    

    2. 删除唯一约束
    alter table stu drop index phone_number;

    3. 在创建表后,添加唯一约束
    alter table stu modify phone_number varchar(20) unique;



-- 主键约束:primary key。

	1. 注意:
		1. 含义:非空且唯一
		2. 一张表只能有一个字段为主键
		3. 主键就是表中记录的唯一标识

	2. 在创建表时,添加主键约束
		create table stu(
			id int primary key,-- 给id添加主键约束
			name varchar(20)
		);

	3. 删除主键
		-- 错误 alter table stu modify id int ;
		alter table stu drop primary key;
		
	4. 创建完表后,添加主键
		alter table stu modify id int primary key;

	5. 自动增长:
		1. 概念:如果某一列是数值类型的,使用 auto_increment 可以来完成值得自动增长
		2. 可以采用自动增长,赋值为null即可完成自动增长,也可以指定赋值。
		3. 在创建表时,添加主键约束,并且完成主键自增长
            create table stu(
                id int primary key auto_increment,-- 给id添加主键约束
                name varchar(20)
            );
		3. 删除自动增长
		alter table stu modify id int;
		4. 添加自动增长
		alter table modify id int auto_increment;
		
		如:
    		insert into stu values(null,'zs');
    	若:
    		insert into stu values(10,'ls');
    	那么下一个数据再赋值为null的时候,索引从11开始,即从已有的主键最大值开始+1.
    	且,如果添加失败的时候内部的计数器依旧会增加,下次添加成功的时候会直接按计数器来添加自增主键
		
		
-- 外键约束:foreign key,让表于表产生关系,从而保证数据的正确性。
-- 外键会使数据库在数据较多时性能变差,不推荐使用
-- 主表被关联的字段必须被主键约束

	1. 在创建表时,可以添加外键
			create table 表名(
				....
				-- 外键列
				constraint 自定外键名称 foreign key (外键列名称) references 主表名称(主表列名称)
			);
			
		如:
		create table province (
            id int primary key,
            name varchar(20) not null
        );
        
        create table city (
            id int primary key,
            name varchar(20) not null,
            province_id int,
            //一个城市必须属于一个省份
            constraint province_city_FK foreign key(province_id) references province(id)
        );	

	2. 删除外键
		alter table 表名 drop foreign 外键名称;
		注:外键关联主表的时候,若外键字段还有数据,主表被外键关联的字段不能被删除
		
	3. 创建表之后,添加外键
		alter table 表名 add constraint 外键名称 foreign key (外键字段名称) references 主表名称(主表列名称);
		
	4. 级联操作
		1. 添加级联操作
			语法:alter table 表名 add constraint 外键名称 
					foreign key (外键字段名称) references 主表名称(主表列名称) on delete cascade;
				 alter table 表名 add constraint 外键名称 
					foreign key (外键字段名称) references 主表名称(主表列名称) on update cascade on delete cascade;
		2. 分类:
			1. 级联更新:on update cascade --用于同步修改外键
			2. 级联删除:on delete cascade --用于同步删除外键
1.10.数据库的设计
1.10.1.多表之间的关系
  1. 分类:
    1. 一对一(了解):
      • 如:人和身份证
      • 分析:一个人只有一个身份证,一个身份证只能对应一个人
      • 实现方式:一对一关系实现,可以在任意一方添加唯一(加unique的约束条件实现唯一)外键指向另一方的主键。
    2. 一对多(多对一):
      • 如:部门和员工
      • 分析:一个部门有多个员工,一个员工只能对应一个部门
      • 实现方式:在多的一方建立外键,指向一的一方的主键
    3. 多对多:
      • 如:学生和课程
      • 分析:一个学生可以选择很多门课程,一个课程也可以被很多学生选择
      • 实现方式:多对多关系实现需要借助第三张中间表。中间表至少包含两个字段,这两个字段作为第三张表的外键,分别指向两张表的主键
  2. Example:
-- 创建旅游线路分类表 tab_category
-- cid 旅游线路分类主键,自动增长
-- cname 旅游线路分类名称非空,唯一,字符串 100
CREATE TABLE tab_category (
	cid INT PRIMARY KEY AUTO_INCREMENT,
	cname VARCHAR(100) NOT NULL UNIQUE
);
		
-- 创建旅游线路表 tab_route
/*
    rid 旅游线路主键,自动增长
    rname 旅游线路名称非空,唯一,字符串 100
    price 价格
    rdate 上架时间,日期类型
	cid 外键,所属分类
*/
CREATE TABLE tab_route(
	rid INT PRIMARY KEY AUTO_INCREMENT,
	rname VARCHAR(100) NOT NULL UNIQUE,
	price DOUBLE,
	rdate DATE,
	cid INT,
	FOREIGN KEY (cid) REFERENCES tab_category(cid)
);
		
/*
	创建用户表 tab_user
	uid 用户主键,自增长
	username 用户名长度 100,唯一,非空
	password 密码长度 30,非空
	name 真实姓名长度 100
	birthday 生日
	sex 性别,定长字符串 1
	telephone 手机号,字符串 11
	email 邮箱,字符串长度 100
*/
CREATE TABLE tab_user (
	uid INT PRIMARY KEY AUTO_INCREMENT,
	username VARCHAR(100) UNIQUE NOT NULL,
	PASSWORD VARCHAR(30) NOT NULL,
	NAME VARCHAR(100),
	birthday DATE,
	sex CHAR(1) DEFAULT '男',
	telephone VARCHAR(11),
	email VARCHAR(100)
);

/*
	创建收藏表 tab_favorite
	rid 旅游线路 id,外键
	date 收藏时间
	uid 用户 id,外键
	rid 和 uid 不能重复,设置复合主键,同一个用户不能收藏同一个线路两次
*/
CREATE TABLE tab_favorite (
	rid INT, -- 线路id
	DATE DATETIME,
	uid INT, -- 用户id
	-- 创建复合主键
	PRIMARY KEY(rid,uid), -- 联合主键
	FOREIGN KEY (rid) REFERENCES tab_route(rid),
	FOREIGN KEY(uid) REFERENCES tab_user(uid)
);
1.10.2.数据库设计的范式
  • 概念:设计数据库时,需要遵循的一些规范。要遵循后边的范式要求,必须先遵循前边的所有范式要求
    • 设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。
    • 目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
  • 分类:
    1. 第一范式(1NF):每一列都是不可分割的原子数据项
    2. 第二范式(2NF):在1NF的基础上,非码属性必须完全依赖于码(在1NF基础上消除非主属性对主码的部分函数依赖)
      1. 函数依赖:A–>B,如果通过A属性(属性组)的值,可以确定唯一B属性的值。则称B依赖于A
        • 例如:学号–>姓名。 (学号,课程名称) –> 分数
      2. 完全函数依赖:A–>B, 如果A是一个属性组,则B属性值得确定需要依赖于A属性组中所有的属性值。
        • 例如:(学号,课程名称) –> 分数
      3. 部分函数依赖:A–>B, 如果A是一个属性组,则B属性值得确定只需要依赖于A属性组中某一些值即可。
        • 例如:(学号,课程名称) – > 姓名
      4. 传递函数依赖:A–>B, B – >C . 如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称 C 传递函数依赖于A
        • 例如:学号–>系名,系名–>系主任
      5. 码:如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码
        • 例如:该表中码为:(学号,课程名称)
        • 主属性:码属性组中的所有属性
        • 非主属性:除过码属性组的属性
    3. 第三范式(3NF):在2NF基础上,任何非主属性不依赖于其它非主属性(在2NF基础上消除传递依赖)
1.11.数据库的备份和还原
1. 命令行:
   备份: mysqldump -u用户名 -p密码 数据库名称 > 保存的路径
   还原:
       1. 登录数据库
       2. 创建数据库
       3. 使用数据库
       4. 执行文件。source 文件路径
       
   如:
       备份:mysqldump -uroot -peternal3210 database1 > 路径  -- 注意>之前的空格问题
       还原:ues某个数据库后,键入命令: source 路径

2. 图形化工具:SQLYog
1.12.多表查询
# 查询语法:
	select
		列名列表
	from
		表名列表
	where....
	
# 准备sql

	# 创建部门表
	CREATE TABLE dept(
		id INT PRIMARY KEY AUTO_INCREMENT,
		NAME VARCHAR(20)
	);
	INSERT INTO dept (NAME) VALUES ('开发部'),('市场部'),('财务部');
	
	# 创建员工表
	CREATE TABLE emp (
		id INT PRIMARY KEY AUTO_INCREMENT,
		NAME VARCHAR(10),
		gender CHAR(1), -- 性别
		salary DOUBLE, -- 工资
		join_date DATE, -- 入职日期
		dept_id INT,
		FOREIGN KEY (dept_id) REFERENCES dept(id) -- 外键,关联部门表(部门表的主键)
	);
	INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('孙悟空','男',7200,'2013-02-24',1);
	INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('猪八戒','男',3600,'2010-12-02',2);
	INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('唐僧','男',9000,'2008-08-08',2);
	INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('白骨精','女',5000,'2015-10-07',3);
	INSERT INTO emp(NAME,gender,salary,join_date,dept_id) VALUES('蜘蛛精','女',4500,'2011-03-14',1);
	
# 笛卡尔积:
	# 有两个集合A,B .取这两个集合的所有组成情况。
	# 要完成多表查询,需要消除无用的数据
	
	交叉连接
		select * from tableA cross join tableB; 结果是笛卡尔积,实际意义不大,在工作中用的很少。
	
# 多表查询的分类:
	1. 内连接查询:
		1. 隐式内连接:使用where条件消除无用数据
			* 例子:
			-- 查询所有员工信息和对应的部门信息
			SELECT * FROM emp,dept WHERE emp.`dept_id` = dept.`id`;
			
			-- 查询员工表的名称,性别。部门表的名称
			SELECT emp.name,emp.gender,dept.name FROM emp,dept WHERE emp.`dept_id` = dept.`id`;
			
			SELECT 
				t1.name, -- 员工表的姓名
				t1.gender,-- 员工表的性别
				t2.name -- 部门表的名称
			FROM
				emp t1, -- 起别名
				dept t2
			WHERE 
				t1.`dept_id` = t2.`id`;
				
		2. 显式内连接:
			* 语法: select 字段列表 from 表名1 [inner] join 表名2 on 条件
			* 例如:
				* SELECT * FROM emp INNER JOIN dept ON emp.`dept_id` = dept.`id`;	
				* SELECT * FROM emp JOIN dept ON emp.`dept_id` = dept.`id`;	

		3. 内连接查询:
			1. 从哪些表中查询数据
			2. 条件是什么
			3. 查询哪些字段
			
	2. 外链接查询:
		1. 左外连接:
			* 语法:select 字段列表 from 表1 left [outer] join 表2 on 条件;
			* 查询的是左表所有数据以及其交集部分。
			* 例子:
				-- 查询所有员工信息,如果员工有部门,则查询部门名称,没有部门,则不显示部门名称
				-- 主要目的是保留left关键字左边的表的全部数据
				SELECT 	t1.*,t2.`name` FROM emp t1 LEFT JOIN dept t2 ON t1.`dept_id` = t2.`id`;
		2. 右外连接:
			* 语法:select 字段列表 from 表1 right [outer] join 表2 on 条件;
			* 查询的是右表所有数据以及其交集部分。
			* 例子:
				-- -- 主要目的是保留right关键字右边的表的全部数据
				SELECT 	* FROM dept t2 RIGHT JOIN emp t1 ON t1.`dept_id` = t2.`id`;
				
	3. 子查询:
		* 概念:查询中嵌套查询,称嵌套查询为子查询。
			-- 查询工资最高的员工信息
			-- 1 查询最高的工资是多少 9000
			SELECT MAX(salary) FROM emp;
			
			-- 2 查询员工信息,并且工资等于9000的
			SELECT * FROM emp WHERE emp.`salary` = 9000;
			
			-- 一条sql就完成这个操作。子查询
			SELECT * FROM emp WHERE emp.`salary` = (SELECT MAX(salary) FROM emp);

		* 子查询不同情况
		
			1. 子查询的结果是单行单列的:
				* 子查询可以作为条件,使用运算符去判断。 运算符: > >= < <= =
				* 
				-- 查询员工工资小于平均工资的人
				SELECT * FROM emp WHERE emp.salary < (SELECT AVG(salary) FROM emp);
				
			2. 子查询的结果是多行单列的:
				* 子查询可以作为条件,使用运算符in来判断
				-- 查询'财务部'和'市场部'所有的员工信息
				SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部';
				SELECT * FROM emp WHERE dept_id = 3 OR dept_id = 2;
				SELECT * FROM emp WHERE dept_id IN (3,2);-- 集合形式
				-- 子查询
				SELECT * FROM emp WHERE dept_id IN (SELECT id FROM dept WHERE NAME = '财务部' OR NAME = '市场部');


			3. 子查询的结果是多行多列的:
				* 子查询可以作为一张虚拟表参与查询
				-- 查询员工入职日期是2011-11-11日之后的员工信息和部门信息
				-- 子查询
				SELECT * FROM dept t1 ,(SELECT * FROM emp WHERE emp.`join_date` > '2011-11-11') t2
				WHERE t1.id = t2.dept_id;
				
				-- 普通内连接
				SELECT * FROM emp t1,dept t2 WHERE t1.`dept_id` = t2.`id` AND t1.`join_date` >  '2011-11-11'
				
	4.联合查询
		-- 查询的是所有开发部的人,和工资大于5000的人,union会自动去除重复数据
		select * from emp t1 where t1.id = 2 
		union 
		select * from dept t2 where t2.salary > 5000
	
	
	
	# 多表查询练习
			-- 部门表
			CREATE TABLE dept (
			  id INT PRIMARY KEY PRIMARY KEY, -- 部门id
			  dname VARCHAR(50), -- 部门名称
			  loc VARCHAR(50) -- 部门所在地
			);
			
			-- 添加4个部门
			INSERT INTO dept(id,dname,loc) VALUES 
			(10,'教研部','北京'),
			(20,'学工部','上海'),
			(30,'销售部','广州'),
			(40,'财务部','深圳');
			
			-- 职务表,职务名称,职务描述
			CREATE TABLE job (
			  id INT PRIMARY KEY,
			  jname VARCHAR(20),
			  description VARCHAR(50)
			);
			
			-- 添加4个职务
			INSERT INTO job (id, jname, description) VALUES
			(1, '董事长', '管理整个公司,接单'),
			(2, '经理', '管理部门员工'),
			(3, '销售员', '向客人推销产品'),
			(4, '文员', '使用办公软件');
			
			-- 员工表
			CREATE TABLE emp (
			  id INT PRIMARY KEY, -- 员工id
			  ename VARCHAR(50), -- 员工姓名
			  job_id INT, -- 职务id
			  mgr INT , -- 上级领导
			  joindate DATE, -- 入职日期
			  salary DECIMAL(7,2), -- 工资
			  bonus DECIMAL(7,2), -- 奖金
			  dept_id INT, -- 所在部门编号
			  CONSTRAINT emp_jobid_ref_job_id_fk FOREIGN KEY (job_id) REFERENCES job (id),
			  CONSTRAINT emp_deptid_ref_dept_id_fk FOREIGN KEY (dept_id) REFERENCES dept (id)
			);
			
			-- 添加员工
			INSERT INTO emp(id,ename,job_id,mgr,joindate,salary,bonus,dept_id) VALUES 
			(1001,'孙悟空',4,1004,'2000-12-17','8000.00',NULL,20),
			(1002,'卢俊义',3,1006,'2001-02-20','16000.00','3000.00',30),
			(1003,'林冲',3,1006,'2001-02-22','12500.00','5000.00',30),
			(1004,'唐僧',2,1009,'2001-04-02','29750.00',NULL,20),
			(1005,'李逵',4,1006,'2001-09-28','12500.00','14000.00',30),
			(1006,'宋江',2,1009,'2001-05-01','28500.00',NULL,30),
			(1007,'刘备',2,1009,'2001-09-01','24500.00',NULL,10),
			(1008,'猪八戒',4,1004,'2007-04-19','30000.00',NULL,20),
			(1009,'罗贯中',1,NULL,'2001-11-17','50000.00',NULL,10),
			(1010,'吴用',3,1006,'2001-09-08','15000.00','0.00',30),
			(1011,'沙僧',4,1004,'2007-05-23','11000.00',NULL,20),
			(1012,'李逵',4,1006,'2001-12-03','9500.00',NULL,30),
			(1013,'小白龙',4,1004,'2001-12-03','30000.00',NULL,20),
			(1014,'关羽',4,1007,'2002-01-23','13000.00',NULL,10);
			
			-- 工资等级表
			CREATE TABLE salarygrade (
			  grade INT PRIMARY KEY,   -- 级别
			  losalary INT,  -- 最低工资
			  hisalary INT -- 最高工资
			);
			
			-- 添加5个工资等级
			INSERT INTO salarygrade(grade,losalary,hisalary) VALUES 
			(1,7000,12000),
			(2,12010,14000),
			(3,14010,20000),
			(4,20010,30000),
			(5,30010,99990);
			
			-- 需求:
			
			-- 1.查询所有员工信息。查询员工编号,员工姓名,工资,职务名称,职务描述
			/*
				分析:
					1.员工编号,员工姓名,工资,需要查询emp表  职务名称,职务描述 需要查询job表
					2.查询条件 emp.job_id = job.id
			
			*/
			SELECT 
				t1.`id`, -- 员工编号
				t1.`ename`, -- 员工姓名
				t1.`salary`,-- 工资
				t2.`jname`, -- 职务名称
				t2.`description` -- 职务描述
			FROM 
				emp t1, job t2
			WHERE 
				t1.`job_id` = t2.`id`;
				
			-- 2.查询员工编号,员工姓名,工资,职务名称,职务描述,部门名称,部门位置
			/*
				分析:
					1. 员工编号,员工姓名,工资 emp  职务名称,职务描述 job  部门名称,部门位置 dept
					2. 条件: emp.job_id = job.id and emp.dept_id = dept.id
			*/
			
			SELECT 
				t1.`id`, -- 员工编号
				t1.`ename`, -- 员工姓名
				t1.`salary`,-- 工资
				t2.`jname`, -- 职务名称
				t2.`description`, -- 职务描述
				t3.`dname`, -- 部门名称
				t3.`loc` -- 部门位置
			FROM 
				emp t1, job t2,dept t3
			WHERE 
				t1.`job_id` = t2.`id` AND t1.`dept_id` = t3.`id`;
			   
			-- 3.查询员工姓名,工资,工资等级
			/*
				分析:
					1.员工姓名,工资 emp  工资等级 salarygrade
					2.条件 emp.salary >= salarygrade.losalary and emp.salary <= salarygrade.hisalary
						emp.salary BETWEEN salarygrade.losalary and salarygrade.hisalary
			*/
			SELECT 
				t1.ename ,
				t1.`salary`,
				t2.*
			FROM emp t1, salarygrade t2
			WHERE t1.`salary` BETWEEN t2.`losalary` AND t2.`hisalary`;
			
			-- 4.查询员工姓名,工资,职务名称,职务描述,部门名称,部门位置,工资等级
			/*
				分析:
					1. 员工姓名,工资 emp , 职务名称,职务描述 job 部门名称,部门位置,dept  工资等级 salarygrade
					2. 条件: emp.job_id = job.id and emp.dept_id = dept.id and emp.salary BETWEEN salarygrade.losalary and 								 salarygrade.hisalary
						
			*/
			SELECT 
				t1.`ename`,
				t1.`salary`,
				t2.`jname`,
				t2.`description`,
				t3.`dname`,
				t3.`loc`,
				t4.`grade`
			FROM 
				emp t1,job t2,dept t3,salarygrade t4
			WHERE 
				t1.`job_id` = t2.`id` 
				AND t1.`dept_id` = t3.`id`
				AND t1.`salary` BETWEEN t4.`losalary` AND t4.`hisalary`;
				
			-- 5.查询出部门编号、部门名称、部门位置、部门人数
			
			/*
				分析:
					1.部门编号、部门名称、部门位置 dept 表。 部门人数 emp表
					2.使用分组查询。按照emp.dept_id完成分组,查询count(id)
					3.使用子查询将第2步的查询结果和dept表进行关联查询
					
			*/
			SELECT 
				t1.`id`,t1.`dname`,t1.`loc` , t2.total
			FROM 
				dept t1,
				(SELECT
					dept_id,COUNT(id) total
				FROM 
					emp
				GROUP BY dept_id) t2
			WHERE t1.`id` = t2.dept_id;
			
			-- 6.查询所有员工的姓名及其直接上级的姓名,没有领导的员工也需要查询
			
			/*
				分析:
					1.姓名 emp, 直接上级的姓名 emp
						* emp表的id 和 mgr 是自关联
					2.条件 emp.id = emp.mgr
					3.查询左表的所有数据,和 交集数据
						* 使用左外连接查询
				
			*/
			/*
			select
				t1.ename,
				t1.mgr,
				t2.`id`,
				t2.ename
			from emp t1, emp t2
			where t1.mgr = t2.`id`;
			
			*/
			
			SELECT 
				t1.ename,
				t1.mgr,
				t2.`id`,
				t2.`ename`
			FROM emp t1
			LEFT JOIN emp t2
			ON t1.`mgr` = t2.`id`;
1.13.事务
2. 概念:如果一个包含多个步骤的业务操作,被事务管理,那么这些操作要么同时成功,要么同时失败。

3. 操作:
   + 开启事务: start transaction;
   + 回滚:rollback;
   + 提交:commit;

     4. 例子:
CREATE TABLE account (
	id INT PRIMARY KEY AUTO_INCREMENT,
	NAME VARCHAR(10),
	balance DOUBLE
);
-- 添加数据
INSERT INTO account (NAME, balance) VALUES ('zhangsan', 1000), ('lisi', 1000);
SELECT * FROM account;
UPDATE account SET balance = 1000;
-- 张三给李四转账 500 元
		
-- 0. 开启事务
START TRANSACTION;

-- 1. 张三账户 -500
UPDATE account SET balance = balance - 500 WHERE NAME = 'zhangsan';
-- 2. 李四账户 +500
-- 出错了...在此刻若出错误,则会停止执行,500元消失,但是若开启事物,则数据只会临时变化,关掉重开即可恢复,所以事物回滚即可
UPDATE account SET balance = balance + 500 WHERE NAME = 'lisi';
		
-- 发现执行没有问题,提交事务
COMMIT;
		
-- 发现出问题了,回滚事务
ROLLBACK;
  1. 数据库中事务默认自动提交
    • 事务提交的两种方式:
      • 自动提交:
        • mysql就是自动提交的
        • 一条DML(增删改)语句会自动提交一次事务。
      • 手动提交:
        • Oracle 数据库默认是手动提交事务
        • 需要先开启事务,再提交
      • 修改事务的默认提交方式:
      • 查看事务的默认提交方式:SELECT @@autocommit; – 1 代表自动提交 0 代表手动提交
        • 修改默认提交方式: set @@autocommit = 0;
  2. 事务的四大特征:
    1. 原子性:是不可分割的最小操作单位,要么同时成功,要么同时失败。
    2. 持久性:当事务提交或回滚后,数据库会持久化的保存数据。
    3. 隔离性:多个事务之间。相互独立。
    4. 一致性:事务操作前后,数据总量不变
  3. 事务的隔离级别(了解)
  • 概念:多个事务之间隔离的,相互独立的。但是如果多个事务操作同一批数据,则会引发一些问题,设置不同的隔离级别就可以解决这些问题。
  • 存在问题:
    1. 脏读:一个事务,读取到另一个事务中没有提交的数据
    2. 不可重复读(虚读):在同一个事务中,两次读取到的数据不一样。
    3. 幻读:一个事务操作(DML)数据表中所有记录,另一个事务添加了一条数据,则第一个事务查询不到自己的修改。
  • 隔离级别:
    1. read uncommitted:读未提交
      • 产生的问题:脏读、不可重复读、幻读
    2. read committed:读已提交 (Oracle)
      • 产生的问题:不可重复读、幻读
    3. repeatable read:可重复读 (MySQL默认)
      • 产生的问题:幻读
    4. serializable:串行化
      • 可以解决所有的问题
    • 注意:隔离级别从小到大安全性越来越高,但是效率越来越低
    • 数据库查询隔离级别:
      • select @@tx_isolation;
    • 数据库设置隔离级别:
      • set global transaction isolation level 级别字符串;
    • Example
    set global transaction isolation level read uncommitted;
    start transaction;
    -- 转账操作
    update account set balance = balance - 500 where id = 1;
    update account set balance = balance + 500 where id = 2;
    
1.14.数据控制语言(DCL)
1.14.1.管理用户
1. 添加用户:

    语法:CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';

2. 删除用户:

    语法:DROP USER '用户名'@'主机名';

3. 修改用户密码:

   UPDATE USER SET PASSWORD = PASSWORD('新密码') WHERE USER = '用户名';
   UPDATE USER SET PASSWORD = PASSWORD('abc') WHERE USER = 'lisi';
   SET PASSWORD FOR '用户名'@'主机名' = PASSWORD('新密码');
   SET PASSWORD FOR 'root'@'localhost' = PASSWORD('123');


   若在mysql中忘记了root用户的密码:

       1. cmd -- > net stop mysql 停止mysql服务:需要管理员运行该cmd
       2. 使用无验证方式启动mysql服务: mysqld --skip-grant-tables
       3. 打开新的cmd窗口,直接输入mysql命令,敲回车。就可以登录成功
       4. use mysql;
       5. update user set password = password('你的新密码') where user = 'root';
       6. 关闭两个窗口
       7. 打开任务管理器,手动结束mysqld.exe 的进程
       8. 启动mysql服务
       9. 使用新密码登录。
       
4. 查询用户:

   1. 切换到mysql数据库:USE myql;
   2. 查询user表:SELECT * FROM USER;
   3. 通配符: % 表示可以在任意主机使用用户登录数据库
1.14.2.权限管理
1. 查询权限:
    SHOW GRANTS FOR '用户名'@'主机名';
    SHOW GRANTS FOR 'lisi'@'%';

2. 授予权限:
    授予权限:grant 权限列表 on 数据库名.表名 to '用户名'@'主机名';
    给张三用户授予所有权限,在任意数据库任意表上:GRANT ALL ON *.* TO 'zhangsan'@'localhost';

3. 撤销权限:
	revoke 权限列表 on 数据库名.表名 from '用户名'@'主机名';
	REVOKE UPDATE ON db3.`account` FROM 'lisi'@'%';
1.15.Mysql索引及优化
1.15.1.索引
  • 索引可以帮助 mysql 高效获取数据的数据结构。即索引是数据结构。数据库在执行查询的时候,如何没有索引存在的情况下,会采用全表扫描的方式进行查找。如果存在索引,则会先去索引列表中定位到特定的行或者直接定位到数据,从而可以极大地减少查询的行数,增加查询速度。
1.15.1.数据结构
  • mysql数据库的存储数据的底层结构是B+树。
    • 优点:
      • 非叶子节点不存储 data,只存储 key
      • 所有的叶子节点存储完整的一份 key 信息以及 key 对应的 data
    • 每一个父节点都出现在子节点中,是子节点的最大或者最小的元素
    • 每个叶子节点都有一个指针,指向下一个数据,形成一个链表
    • 特点:B+ 树由于非叶子结点不存储数据,仅在叶子结点才存储数据,所以单个非叶子结点可以存储更多的索引字段
      • 如果是主键索引,那么叶子结点存放这一行的数据
      • 如果非主键索引,那么叶子结点存放主键的值
        -- 查看某张表的索引:
        show index from 表名;
        -- 创建普通索引:
        alter table 表名 add index 索引名(索引列);
        -- 创建复合索引:
        alter table 表名 add index 索引名(索引列 1,索引列 2);
        -- 删除某张表的索引:
        drop index 索引名 on 表名;
        

        一个表至少有一个索引树,如果没有创建索引,InnoDB会默认维护一列索引

  • 其他数据结构用于数据库存储数据的缺点
    • 平衡二叉树与红黑树:树的高度比较高
    • hash表:范围查找不方便,一次性加载很多数据,非常消耗内存空间。
    • B树:范围查找不方便,且若key与value的值比较大,或者占得空间比较大,则可能会出现某个结点存在的数据非常少,高度就会非常高
  • 索引的具体实现
    • Mysql 数据库的基本组成架构为:
      • 连接器:负责管理连接,权限的验证等。
      • 解析器:mysql 需要解析语句。对输入的 sql 进行解析。首先进行词法分析,识别出里面的字符串代表什么意思。比如 select 代表查询,T 代表某张表,ID 代表某张表的列字段叫 id;之后进行语法分析,根据语法规则,判断输入的 sql 语句是否符合mysql 语法。
      • 优化器:经过解析之后,mysql 解析出了语句的目的。但是在真正执行之前还需要经过优化器处理。比如当表中存在多个索引的时候,选择哪个索引来使用。或者多表关联的时候,选择各个表的连接先后顺序。
      • 执行器:开始执行之前首先确认对该表有无执行查询的权限。如果没有,则返回错误的信息。

        如果有权限,则开始执行。首先根据该表的引擎类型,使用这个引擎提供的接口。比如查询某表,然后利用某字段查找,如果没有添加索引,则调用引擎的接口取出第一行数据,判断结果是不是,如果不是,依次再调用引擎的下一行数据,直至取出这个表中所有的数据。如果该字段有索引,执行过程也大致相似,具体的数据是保存在引擎中的。

        Mysql 中,常见的引擎有 MyISAM 和 InnoDB。

1.15.3.mysql表的引擎
  • MyISAM 和 InnoDB 区别
    1. Innodb 支持事务,MyISAM 不支持事务,对于 Innodb 中的每条 sql 语句都自动封装成事务,自动提交,影响速度
    2. Innodb 支持外键,MyISAM 不支持外键
    3. Innodb 是聚集索引,数据文件和索引绑在一起。MyISAM 是非聚集索引,索引和数据文件是分开的
    4. Innodb 不保存表的行数,查询某张表的行数会全表扫描。MyISAM 会保存整个表的行数,执行速度很快
    5. Innodb 支持表锁和行锁(默认),而 MyISAM 支持表锁。但是 Innodb 的表锁是通过索引实现的,如果没有命中索引,则依然会使用表锁,Innodb 表必须要有一个主键(如果用户不设置,那么引擎会自行设定一列当做主键),MyISAM 则可以没有
    6. Innodb 的存储文件是 frm 和 ibd,而 MyISAM 是 frm、myd、myi 三个文件。Frm 是表定义文件,ibd 是数据文件;myd 是数据文件、myi 是索引文件

    选择方式:

    • 不需要事物,则可以使用 MyISAM
    • 如果绝大多数操作都是查询语句,可以选择 MyISAM,有读也有写,则选择 Innodb
1.15.4.MyISAM索引实现
  • MyISAM 的索引是非聚集索引,即索引文件和数据文件分开存放,MyISAM引擎有三个文件组成:
    • 表名.MYD:数据文件
    • 表名.MYI:索引文件
    • 表名.frm:表定义的文件
  • MYI 是索引文件。索引文件中存放的是对应数据的文件指针,接着会去 MYD 文件中去找对应指针的数据。
1.15.5.Innodb 的索引实现
  • Innodb 的文件只有一个表结构文件和数据文件。数据文件本身就是索引文件。Innodb 的索引是聚集索引形式。索引和文件数据是存放在一起的。
  • Innodb引擎有两个文件组成:
    • 表名.ibd:数据和索引的文件
    • 表名.frm:表定义的文件
  • Innodb 索引的特点:
    1. 数据文件本身就是索引文件
    2. 数据本身就是按照 B+ 树索引组织起来的一个索引文件
    3. 对于主键索引的 B+ 树的叶子节点包含了完整的数据信息,对于非主键索引,叶子节点存放的是主键的 id
1.16.内存溢出
1.16.1.原因
  • 引起内存溢出的原因有很多种,常见的有以下几种:
    1. 内存中加载的数据量过于庞大,如一次从数据库取出过多数据;
    2. 集合类中有对对象的引用,使用完后未清空,使得JVM不能回收;
    3. 代码中存在死循环或循环产生过多重复的对象实体;
    4. 使用的第三方软件中的BUG;
    5. 启动参数内存值设定的过小;
1.16.2.解决方案
  • 内存溢出的解决方案
    • 第一步,修改JVM启动参数,直接增加内存。(-Xms,-Xmx参数一定不要忘记加。)
    • 第二步,检查错误日志,查看“OutOfMemory”错误前是否有其它异常或错误。
    • 第三步,对代码进行走查和分析,找出可能发生内存溢出的位置。
      • 重点排查以下几点
        1. 检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
        2. 检查代码中是否有死循环或递归调用。
        3. 检查是否有大循环重复产生新对象实体。
        4. 检查对数据库查询中,是否有一次获得全部数据的查询。一般来说,如果一次取十万条记录到内存,就可能引起内存溢出。这个问题比较隐蔽,在上线前,数据库中 数据较少,不容易出问题,上线后,数据库中数据多了,一次查询就有可能引起内存溢出。因此对于数据库查询尽量采用分页的方式查询。
        5. 检查List、MAP等集合对象是否有使用完后,未清除的问题。List、MAP等集合对象会始终存有对对象的引用,使得这些对象不能被GC回收。
    • 第四步,使用内存查看工具动态查看内存使用情况

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181066.html

(0)
飞熊的头像飞熊bm

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!