MySQL和数据库总结

  • 第01章-WEB技术-MySQL基础语法
    • 启动MySQL
      • 服务模式
      • 修改密码
    • 数据库操作
    • 表操作
      • 显示表结构
      • 修改表
      • 复制表
      • 临时表
    • 常用的数据类型
      • 数据类型
      • 约束注意
      • 约束
    • 表的增删改查
      • 插入数据
      • 从查询结果插入数据
      • 查询表中的数据
      • 查询数据插入新表
      • 查询条件
        • 条件运算符
        • 模糊查询通配符
      • 删除表中数据
      • 修改表中数据
    • 视图
    • 查询视图:
  • 第02章-WEB技术-MySQL进阶语法
    • 数据库
      • 数据完整性
    • 数据库的三大范式
    • 数据库设计之E-R图
    • 关键词
      • SQL别名【AS】
      • 去重【DISTINCT】
      • 排序【ORDER BY】
      • 分页【LIMIT】
      • 分组【GROUP BY】
        • Aggregate合计函数:(聚合函数,报表函数)
        • Scalar标量函数:
        • Date 函数:
      • 扩展条件【HAVING】
      • 合并【UNION】
      • 连接【JOIN】
      • 条件【IF】
      • 分支【CASE】
    • 外键
      • 语法
      • 级联删除、更新
    • 索引
      • 查看索引
      • 简单的索引
      • 短索引
      • 唯一索引
      • 主索引(唯一)
      • 复合索引
      • 全文索引
    • 事务
      • 事务特性:
      • 事务控制
      • 示例:
        • SAVEPOINT:
        • ROLLBACK
    • 数据库的引擎
    • 数据库的隔离级别
    • 锁机制
      • 共享锁
      • 排它锁
        • 表锁
        • 行锁
  • 第03章-WEB技术-MySQL高级语法
    • ALTER语句
      • 修改表名
      • 修改数据库默认字符集
      • 修改表数据引擎
      • 添加表的列
      • 修改表的列
      • 删除表的列
      • 修改索引
      • 修改外键
    • 自定义函数【FUNCTION】
    • 存储过程【PROCEDURE】
      • 参数
      • 光标
      • 案例
    • 事件【EVENT】
    • 触发器【TRIGGER】
    • SQL 注入
      • 注入中常用的函数与语法
      • 判断是否存在sql注入漏洞。
      • 判断字段数:
      • 判断回显点:
      • 获取信息
      • 查询当前数据库以及表名称。
      • 查询表admin中的字段名。
      • 查询用户名称
      • 查询密码:
    • SQL优化
      • explain
        • 参数说明
          • id
          • select_type
          • partitions
          • type
          • possible_keys
          • key
          • key_len
          • extra
          • filtered
      • 优化分析
        • 1、初步优化:创建索引
        • 2、再次优化:覆盖索引
        • 3、涉及到排序
        • 4、排序字段加复合索引
        • 5、再次覆盖索引
        • 6、强制使用指定索引
      • MySql_float类型字段查询不出来

第01章-WEB技术-MySQL基础语法

启动MySQL

服务模式

# 命令安装服务
mysqld -install
# 移除服务
mysqld -remove
# 启动该服务
net start MySQL
# 停止服务
net stop MySQL

修改密码

# 连接数据库
mysql -u root -p
# 修改数据
ALTER USER 'root'@'localhost' IDENTIFIED  BY '你的新密码';# 或者:SQL工具进行远程连接的密码
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY '你的新密码';# 刷新
flush privileges;

数据库操作

创建一个名字叫 mydb 的数据库

CREATE DATABASE mydb;当再次执行时会报错,数据库 mydb 已经存在Can't create database 'mydb';database exists

显示数据库

SHOW DATABASES [LIKE '数据库名'];

删除数据库

DROP DATABASE mydb;

使用(进入)数据库

USE mydb;

表操作

显示表结构

DESC table_name;

修改表

#创建表
CREATE TABLE mytb (id INT,name CHAR(5)
);
#删除字段
ALTER TABLE mytb DROP id;
#增加字段
ALTER TABLE mytb ADD ids INT;
#添加一个字段在最前面
ALTER TABLE mytb ADD id INT FIRST;
#增加一个字段在 name 后
ALTER TABLE mytb ADD sex INT AFTER name;
#修改 name 字段的长度为 10
ALTER TABLE mytb MODIFY name CHAR(10);
#修改 ids 字段的属性为 long 不为空默认值为 100
ALTER TABLE mytb MODIFY ids BIGINT NOT NULL DEFAULT 100;

修改表名为mytable

ALTER TABLE mytb RENAME TO mytable;

删除表mytable

DROP TABLE mytable

删除表有drop,truncate,delete三种操作,它们的区别如下:

drop:删除表数据和表结构

DROP TABLE user;

truncate:保留表结构,删除数据,释放空间

TRUNCATE TABLE user;

delete:保留表结构,删除数据,释放空间

DELETE FROM user;

三种的执行速度,一般来说:drop>truncate>delete

释放空间可以体现在:

1.通过 delete 删除的行数据是不释放空间的,如果表 id 是递增式的话,那么表数据的 id 就可能不是连续的;而通过 truncate 删除数据是释放空间的,如果表 id 是递增式的话,新增数据的 id 又是从头开始,而不是在已删数据的最大 id 值上递增。2.使用 delete 删除数据时,mysql 并没有把数据文件删除,而是将数据文件的标识位删除,没有整理文件,因此不会彻底释放空间。被删除的数据将会被保存在一个链接清单中,当有新数据写入的时候,mysql 会利用这些已删除的空间再写入。即,删除操作会带来一些数据碎片,正是这些碎片在占用硬盘空间

复制表

复制表结构

CREATE TABLE `copy_user` LIKE `user`;

复制结构和数据,将查询出来的结果创建成新的表

CREATE TABLE IF NOT EXISTS `tablename` [AS] SELECT * FROM …;

只复制表结构:

CREATE TABLE `tablename` SELECT * FROM `tablename2` WHERE 1=0;

临时表

MySQL 临时表在我们需要保存一些临时数据时是非常有用的。

临时表只在当前连接可见,当关闭连接时,Mysql会自动删除表并释放所有空间。

CREATE TEMPORARY TABLE IF NOT EXISTS `tablename`
(列1 数据类型(数据大小) 约束,列2 数据类型(数据大小) 约束,列3 数据类型(数据大小) 约束,....
)ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

临时表还可以使用“#”开头来表示

常用的数据类型

数据类型

常用数据类型 类型 描 述
bit 整型 bit 数据类型是整型,其值只能是0、1或空值。
bigint 整型 介于 -9,223,372,036,854,775,808 与 9,223,372,036,854,775,807 之间的所有数字。这种数据类型在数据库里占用8个字节
int 整型 int 数据类型可以存储从- 231(-2147483648)到231 (2147483 647)之间的整数。存储到数据库的几乎所有数值型的数据都可以用这种数据类型。这种数据类型在数据库里占用4个字节
smallint 整型 smallint 数据类型可以存储从- 215(-32768)到215(32767)之间的整数。这种数据类型对存储一些常限定在特定范围内的数值型数据非常有用。这种数据类型在数据库里占用2 字节空间
tinyint 整型 tinyint 数据类型能存储从0到255 之间的整数。它在你只打算存储有限数目的数值时很有用。 这种数据类型在数据库中占用1 个字节
numeric 精确数值 numeric数据类型与decimal 型相同
decimal 精确数值 decimal 数据类型能用来存储从-1038-1到1038-1的固定精度和范围的数值型数据。使用这种数据类型时,必须指定范围和精度。 范围是小数点左右所能存储的数字的总位数。精度是小数点右边存储的数字的位数
money 货币型 money 数据类型用来表示钱和货币值。这种数据类型能存储从-9220亿到9220 亿之间的数据,精确到货币单位的万分之一
smallmoney 货币型 smallmoney 数据类型用来表示钱和货币值。这种数据类型能存储从-214748.3648 到214748.3647 之间的数据,精确到货币单位的万分之一
float 近似数值 float 数据类型是一种近似数值类型,供浮点数使用。说浮点数是近似的,是因为在其范围内不是所有的数都能精确表示。浮点数可以是从-1.79E+308到1.79E+308 之间的任意数
real 近似数值 real 数据类型像浮点数一样,是近似数值类型。它可以表示数值在-3.40E+38到3.40E+38之间的浮点数
datetime 日期时间 datetime数据类型用来表示日期和时间。这种数据类型存储从1753年1月1日到9999年12月3 1日间所有的日期和时间数据, 精确到三百分之一秒或3.33毫秒
Smalldatetime 日期时间 smalldatetime 数据类型用来表示从1900年1月1日到2079年6月6日间的日期和时间,精确到一分钟
cursor 游标 cursor 数据类型是一种特殊的数据类型,它包含一个对游标的引用。这种数据类型用在存储过程中,而且创建表时不能用
timestamp 时间戳 timestamp 数据类型是一种特殊的数据类型,用来创建一个数据库范围内的唯一数码。 一个表中只能有一个timestamp列。每次插入或修改一行时,timestamp列的值都会改变。尽管它的名字中有“time”, 但timestamp列不是人们可识别的日期。在一个数据库里,timestamp值是唯一的
Uniqueidentifier 特殊数据型 Uniqueidentifier数据类型用来存储一个全局唯一标识符,即GUID。GUID确实是全局唯一的。这个数几乎没有机会在另一个系统中被重建。可以使用NEWID 函数或转换一个字符串为唯一标识符来初始化具有唯一标识符的列
char 字符型 char数据类型用来存储指定长度的定长非统一编码型的数据。当定义一列为此类型时,你必须指定列长。当你总能知道要存储的数据的长度时,此数据类型很有用。例如,当你按邮政编码加4个字符格式来存储数据时,你知道总要用到10个字符。此数据类型的列宽最大为8000 个字符
varchar 字符型 varchar数据类型,同char类型一样,用来存储非统一编码型字符数据。与char 型不一样,此数据类型为变长。当定义一列为该数据类型时,你要指定该列的最大长度。 它与char数据类型最大的区别是,存储的长度不是列长,而是数据的长度
text 字符型 text 数据类型用来存储大量的非统一编码型字符数据。这种数据类型最多可以有231-1或20亿个字符
nchar 字符型 nchar 数据类型用来存储定长统一编码字符型数据。统一编码用双字节结构来存储每个字符,而不是用单字节(普通文本中的情况)。它允许大量的扩展字符。此数据类型能存储4000种字符,使用的字节空间上增加了一倍
nvarchar 字符型 nvarchar 数据类型用作变长的统一编码字符型数据。此数据类型能存储4000种字符,使用的字节空间增加了一倍
ntext 字符型 ntext 数据类型用来存储大量的统一编码字符型数据。这种数据类型能存储230 -1或将近10亿个字符,且使用的字节空间增加了一倍
binary 二进制 binary数据类型用来存储可达8000 字节长的定长的二进制数据。当输入表的内容接近相同的长度时,你应该使用这种数据类型
varbinary 二进制 varbinary 数据类型用来存储可达8000 字节长的变长的二进制数据。当输入表的内容大小可变时,你应该使用这种数据类型
image 二进制 image 数据类型用来存储变长的二进制数据,最大可达231-1或大约20亿字节

约束注意

!注意
1.在DECIMAL(P,D) 的语法中:
P 是表示有效数字数的精度。
P 范围为 1〜65。
D 是表示小数点后的位数。
D 的范围是 0~30。MySQL 要求 D 小于或等于(<=)P。如:DECIMAL(6,2)中最多可以存储 6 位数字,小数位数为 2 位;因此,列的范围是从-9999.99 到 9999.99。2.char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。char 是一种定长字符串。它一旦声明后无论存储的值是否达到该长度,都占有相应的字节长度。varchar 是一种变长字符串,它的长度由存储的内容决定,为存满的时以实际存储内容为主。3.BLOB 是一个二进制大对象,可以容纳可变数量的二进制数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。4.TEXT 同样也有 4 种类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。它们的区别也是可存储的最大长度不同。具体使用哪种类型可根据实际情况选择。

约束

约束用于规定表中的数据规则

在 SQL 中,有如下约束:

  • NOT NULL - 指示某列不能存储 NULL 值。
  • UNIQUE - 保证某列的每行必须唯一,不能有相同的值。
  • UNIQUE KEY - 必须唯一键,不能有相同的值。如:UNION KEY (id,name)
  • PRIMARY KEY - NOT NULL 和 UNIQUE 的结合。确保某列(或多个列的结合)有唯一标识。如:PRIMARY KEY (id,name)
  • FOREIGN KEY - 保证一个表中的数据匹配另一个表中的值的参照完整性。
  • CHECK - 保证列中的值符合指定的条件**(MySql无效)**。如:CHECK (id>0)
  • DEFAULT - 规定没有给列赋值时的默认值。如:DEFAULT b'1'
  • UNSIGNED - 无符号整数

AUTO_INCREMENT - 自增

COMMENT - 表示注释

表的增删改查

插入数据

INSERT INTO 语句可以有两种编写形式。

第1种

INSERT INTO `tablename`
VALUE
(value1,value2,value3,...);

第2种

INSERT INTO `tablename`
VALUES
(value1,value2,value3,...),
(value1,value2,value3,...);

第3种

INSERT INTO `tablename` (column1,column2,column3,...)
VALUES
(value1,value2,value3,...),
(value1,value2,value3,...);

如:

INSERT  INTO `users`(`id`,`nickname`,`name`,`pswd`,`sex`,`birthday`,`register`,`status`)
VALUES
(1,'小三','张三','123456',0,'0000-00-00 00:00:00','0000-00-00 00:00:00',0),
(2,'小四','李四','123456',0,'0000-00-00 00:00:00','0000-00-00 00:00:00',0),
(3,'小五','王五','123456',1,'0000-00-00 00:00:00','0000-00-00 00:00:00',0);

从查询结果插入数据

INSERT INTO IF EXISTS `tablename` [AS] SELECT * FROM …;

查询表中的数据

SELECT 语句用于从数据库中选取数据。

结果被存储在一个结果表中,称为结果集。

结果集。也是一张数据库表,只不过这张表是临时的,用完就销毁

SELECT column_name,column_name
FROM `tablename`
WHERE condition;# 或者SELECT *
FROM `tablename`
WHERE condition;

在表中,一个列可能会包含多个重复值,如果要排除重复的值,可以使用DISTINCT 关键词用于返回唯一不同的值

SELECT DISTINCT column_name,column_name
FROM table_name;
WHERE condition;

查询数据插入新表

SELECT INTO 语句从一个表中选取数据,然后把数据插入另一个表中。

SELECT INTO 语句常用于创建表的备份复件或者用于对记录进行存档。

语法:

SELECT *
INTO new_table_name [IN externaldatabase]
FROM old_tablename;# 或者只把希望的列插入新表:SELECT column_name(s) INTO new_table_name [IN externaldatabase] FROM old_tablename

查询条件

条件运算符

运算符 描述
= 等于 where id=45
<>!= 不等于。在一些版本中,被写成 != where id<>45
> 大于 where id>45
< 小于 where id>45
>= 大于等于 where id>=45
<= 小于等于 where id=<45
BETWEEN 在某个范围内 where id BETWEEN 1 AND 10
LIKE RLIKE 搜索某种模式
IN或者NOT IN 指定针对某个列的多个可能值 where id in (1,3,7)
AND 第一个条件和第二个条件都成立 where id>=45 AND id<60
OR 第一个条件和第二个条件中只要有一个成立 where id>=45 AND (id<60 OR name='李四')

模糊查询通配符

通配符 描述
% 替代 0 个或多个字符
_ 替代一个字符
[charlist] 字符列中的任何单一字符
[^charlist][!charlist] 不在字

示例:

name LIKE ‘_a%'    表示第二个字符为 a 的人
name like '张%'     姓张的所有人
name like '_伟'     所有姓名为两个字且第二个字为 “伟”
name like '%商%'    姓名中包含 “商”字
name like '%友'     姓名以“友”结尾

删除表中数据

DELETE 语句用于删除表中的记录。

DELETE FROM table_name WHERE some_column=some_value;

如:

DELETE FROM `users` WHERE id='3';

删除所有数据

可以在不删除表的情况下,删除表中所有的行。这意味着表结构等保持不变:

DELETE FROM table_name;# 或DELETE * FROM table_name;

修改表中数据

UPDATE 语句用于更新表中的记录。

UPDATE table_name
SET column1=value1,column2=value2,...
WHERE some_column=some_value;

如:

UPDATE `users` SET nickname='wangwu',NAME='ww' WHERE id='2';

视图

视图其实就是一张虚拟表,一张从别的表中导出的一张不完整或经过运算的虚拟表。

视图有什么用,当我们经常查询一个表中的某几个字段的时候,我们可以把这几个字段单独导出一个视图,以后查询的时候直接可以 select *,在数据库中只存放了视图的定义,没有存放视图的数据,视图是依赖原来表中的数据的,原表中的数据一旦发生变化,视图查询出的结果也会跟着变化。下面进行创建一个视图。

视图是一个虚拟的表,是一个表中的数据经过某种筛选后的显示方式,视图由一个预定义的查询select语句组成。

视图是基于 SQL 语句的结果集的可视化的表

  • 视图中的数据并不属于视图本身,而是属于基本的表,对视图可以像表一样进行insert,update,delete操作。
  • 视图不能被修改,表修改或者删除后应该删除视图再重建。
  • 视图的数量没有限制,但是命名不能和视图以及表重复,具有唯一性。
  • 视图可以被嵌套,一个视图中可以嵌套另一个视图。
  • 视图不能索引,不能有相关联的触发器和默认值

语法

CREATE VIEW view_name AS
SELECT column_name1, column_name2
FROM table_name
WHERE condition;

案例

创建用户表:

create table user(id int(10) unsigned primary key auto_increment,name varchar(60) unique not null,pswd varchar(255)not null,class_id int(10)
);

插入用户数据:

insert into user (name,pswd class_id) values('zhangsan','123456','1'),('lishi','123456','1'),('wangwu','123456','2');

创建班级表:

create table class (id int(10) unsigned primary key auto_increment,name varchar(255) not null unique
);

插入班级数据:

insert into class (name) values ('class1'),('class2'),('class3');

创建视图:

create view user_class as
select u.*,c.id c_id,c.name c_name
from user u,class c
where u.class_id=c.id;

查询视图:

select * from user_class;

更新视图:

create or replace view user_class as
select u.*,c.id c_id,c.name c_name
from user u,class c;

第02章-WEB技术-MySQL进阶语法

数据库

数据库就是存储数据的一个仓库 DBS
数据库管理系统:是一种操纵和管理数据库的大型软件 DBMS ,对数据库进行管理和控制,以保证数据库的安全性和完整性,用来管理数据以及用户操作数据库的软件 DBMS
数据库定义语言:DDL 创建或删除
数据操作语言:DML 修改或查询
数据库控制语言:DCL,用来设置或更改数据库用户或角色权限的语句

数据完整性

数据的完整性有以下几类存在于每个RDBMS:

  • 实体完整性: 指表中行必须有唯一的标识,没有重复行
  • 域完整性: 指列的值域的完整性。如数据类型、格式、值域范围、是否允许空值等。
  • 参考完整性: 用于约束外关键字和主关键字的关系,被其他记录使用的行不能被删除,
  • 用户定义的完整性: 强制执行不属于实体,域和参照完整性一些具体的业务规则

数据库的三大范式

第一范式:强调的是列的原子性,即数据库表中的每一个字段都是不可分割的原子数据项。
– 数据库表中的字段都是单一属性的,不可再分。例如,姓名字段,其中的姓和名必须作为一个整体,无法区分哪部分是姓,哪部分是名,如果要区分出姓和名,必须设计成两个独立的字段。

第二范式:要求实体的属性完全依赖于主关键字。所谓完全依赖是指不能存在仅依赖主关键字一部分的属性。
– 数据库表中的每个实例或者行必须可以唯一地区分,唯一属性的列被称为主键,实体的属性完全依赖于主关键字。

第三范式:任何非主属性不依赖于其它非主属性。
– 数据库中不包含已在其他表中包含的非关键字信息。
第三范式必须满足第二范式和第一范式

数据库设计之E-R图

E-R图分为实体、属性、关系三个核心部分

  1. 实体(entity):数据模型中的数据对像,每个实体都有自己的实体成员或者说实体对象,例如学生实体包括张三,李四
  2. 属性(attribute):实体所具有的属性,例如学生具有姓名、学号、年级等属性,用椭圆形表示,属性分为唯一属性( unique attribute)和非唯一属性,唯一属性指的是唯一可用来标识该实体实例或者成员的属性,用下划线表示,一般来讲实体都至少有一个唯一属性。
  3. 关系(relationship):用来表现数据对象与数据对象之间的联系,例如学生的实体和成绩表的实体之间有一定的联系,每个学生都有自己的成绩表,这就是一种关系,关系用菱形来表示。

E-R图的图形表示是:实体【长方形】,属性【椭圆形】,关系【菱形】

E-R图的关联关系有三种:

  1. 1对1(1:1):指对于实体集A与实体集B,A中的每一个实体至多与B中一个实体有关系;反之,在实体集B中的每个实体至多与实体集A中一个实体有关系。
  2. 1对多(1:N):1对多关系是指实体集A与实体集B中至少有N(N>0)个实体有关系;并且实体集B中每一个实体至多与实体集A中一个实体有关系。
  3. 多对多(M:N):多对多关系是指实体集A中的每一个实体与实体集B中至少有M(M>0)个实体有关系,并且实体集B中的每一个实体与实体集A中的至少N(N>0)个实体有关系。

关键词

SQL别名【AS】

SQL中使用【as】关键词连定义数据表或者字段的别名。

查询语句:

SELECT nickname AS nn
FROM user AS u;
WHERE u.id=’2’;

AS可以省略不写。

去重【DISTINCT】

关键词 DISTINCT 用于返回唯一不同的值。

SELECT DISTINCT 列名称 FROM 表名称;

如:

SELECT DISTINCT Company FROM Orders;

排序【ORDER BY】

排序有升序【ASC】和降序【DESC】两种.

SELECT column_name,column_name
FROM table_name
WHERE condition
ORDER BY column_name,column_name ASC|DESC;

分页【LIMIT】

所有的数据库都可以通过between and 语句实现分页查询。

SELECT * FROM  users WHERE id BETWEEN 1 AND 2;

而对于MySQL数据库,还可以使用limit 来实现这个功能

SELECT * FROM  users LIMIT n,m;

如:

SELECT * FROM  users LIMIT 1,2;

分组【GROUP BY】

分组使用【GROUP BY】关键词。

MySQL默认开启only_full_group_by的分组模式。

查看所有的分组模式:

select @@sql_mode;

设置

SET sql_mode = '';

如果要使用分组,需要修改参数:修改my.ini配置文件:

mysqld:
sql_mode = STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION

分组聚合:group_concat(sore Separator ';') 返回在指定列的组合值

函数【FUNCTION】

Aggregate合计函数:(聚合函数,报表函数)
函数 描述
AVG(column) 返回某列的平均值
COUNT(column) 返回某列的行数(不包括 NULL 值)
COUNT(*) 返回被选行数
GROUP_CONCAT(sore separator ‘;’) 返回在指定列的组合值
LAST(column) 返回在指定的域中最后一个记录的值
MAX(column) 返回某列的最高值
MIN(column) 返回某列的最低值
SUM(column) 返回某列的总和
Scalar标量函数:
Concat(a,b,c,d,…) 连接多个字符串
UCASE© 将某个域转换为大写
LCASE© 将某个域转换为小写
MID(c,start[,end]) 从某个文本域提取字符
INSTR(c,char) 返回在某个文本域中指定字符的数值位置
LEFT(c,number_of_char) 返回某个被请求的文本域的左侧部分
RIGHT(c,number_of_char) 返回某个被请求的文本域的右侧部分
ROUND(c,decimals) 对某个数值域进行指定小数位数的四舍五入
MOD(x,y) 返回除法操作的余数
NOW() 返回当前的系统日期
FORMAT(c,format) 改变某个域的显示方式Y_M_D hⓂ️s
Date 函数:
函数 描述
NOW() 返回当前的日期和时间
CURDATE() 返回当前的日期
CURTIME() 返回当前的时间
DATE(‘Y-M-D hⓂ️s’) 提取日期或日期/时间表达式的日期部分
EXTRACT(MONTH FROM ’ Y-M-D hⓂ️s ') 返回日期/时间按的单独部分
DATE_ADD(date,INTERVAL expr type) 给日期添加指定的时间间隔
DATE_SUB(date,INTERVAL x type) 从日期减去指定的时间间隔
DATEDIFF(date-part, date 1, date2) date-part : year | quarter | month | week | day | hour | minute | second | millisecond 返回两个日期之间的天数
DATE_FORMAT(date,format) 用不同的格式显示日期/时间

扩展条件【HAVING】

SQL中使用HAVING 子句来扩展WHERE 关键字无法实现的功能。

WHERE无法与聚合函数一起使用。

HAVING 子句可以让我们处理筛选分组后的各组数据。如:使用函数

合并【UNION】

UNION 操作符合并两个或多个 SELECT 语句的结果。

UNION 操作符默认选取不同的值。如果允许重复的值,请使用 UNION ALL。

UNION 结果集中的列名总是等于 UNION 中第一个 SELECT 语句中的列名。

连接【JOIN】

SQL join 用于把来自两个或多个表的行结合起来。

SQL JOIN 类型:

  • INNER JOIN - 如果表中有至少一个匹配,则返回行(默认)
  • LEFT JOIN - 即使右表中没有匹配,也从左表返回所有的行
  • RIGHT JOIN - 即使左表中没有匹配,也从右表返回所有的行
  • FULL JOIN - 只要其中一个表中存在匹配,则返回行left和right的组合

条件【IF】

条件【IF(TRUE|FALSE,VALUE1,VALUE2)】

SELECT IF(false,id,name) as filed from student;

分支【CASE】

1. 分支【CASE WHEN THEN ELSE END】

语法:

CASE [col_name] WHEN [value1] THEN [result1]…ELSE [default] END

案例:

case 列名when  条件值1  then  选项1when  条件值2   then  选项2.......else   默认值
end

外键

外键是用于两个表链接在一起的键。这有时被称为一个参考项。

外键创建条件:

  • 使用外键约束的表必须是InnoDB引擎
  • 两个字段的类型或者大小必须严格匹配,如,INT(10), INT(11),就不匹配。
  • 被引用的外键必须是主键或者建立起索引。
  • 外键的名字不能和其他字段名重复

外键的特点:

  • 插入数据时,外键引用的列的值必须是在被引用表中已经存在的值
  • 删除数据时,被外键引用的表和这一条数据不能被删除,除非先删除引用的表数据。

外键的作用:

  • 预防破坏表之间连接的动作。
  • 防止非法数据插入外键列
alter table `student` add constraint class_fk foreign key(class_id) references course(`cid`) on DELETE set null ON UPDATE CASCADE;

语法

创建语法1:

CREATE TABLE table_name(id int NOT NULL PRIMARY KEY,f_id int [CONSTRAINT <外键名>] FOREIGN KEY REFERENCES table_name 2(id)
);

创建语法2:

CREATE TABLE table_name (id int NOT NULL PRIMARY KEY,f_id int,PRIMARY KEY (id),[CONSTRAINT <外键名>] FOREIGN KEY (f_id) REFERENCES table_name 2(id)
);

创建语法3:

ALTER TABLE table_name ADD FOREIGN KEY (f_id) REFERENCES table_name 2(id);

删除外键:

ALTER TABLE table_name DROP FOREIGN KEY fk_name;

级联删除、更新

在创建索引的时候,可以指定在删除、更新父表时,对子表进行的相应操作。

包括RESTRICT、NO ACTION、SET NULL和CASCADE。

  • **RESTRICT -**指在子表有关联记录的情况下父表不能更新;
  • CASCADE - 表示父表在更新或者删除时,更新或者删除子表对应记录;
  • SET NULL - 则是表示父表在更新或者删除的时候,子表的对应字段被SET NULL。
  • NO ACTION 不做任何操作,和NO ACTION相同。

修改学生表如下:其他表不变,插入数据不变

CREATE TABLE student (id INT UNSIGNED NOT NULL,name VARCHAR(60) NOT NULL,pswd VARCHAR(255) NOT NULL,class_id INT UNSIGNED,PRIMARY KEY (id),FOREIGN KEY (class_id) REFERENCES class(id) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=INNODB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;

执行删除操作,删除后查询,相关数据会同步删除。

索引

在不读取整个表的情况下,索引使数据库应用程序可以更快地查找数据。

用户无法看到索引,它们只能被用来加速搜索/查询。

注释:更新一个包含索引的表需要比更新一个没有索引的表花费更多的时间,这是由于索引本身也需要更新。因此,理想的做法是仅仅在常常被搜索的列(以及表)上面创建索引。

查看索引

SHOW INDEX FROM tblname;
# OR
SHOW INDEX FROM tblname;

显示结果:

  • Table:表的名称。
  • Non_unique:如果索引不能包括重复词,则为0。如果可以,则为1。
  • Key_name:索引的名称。
  • Seq_in_index:索引中的列序列号,从1开始。
  • Column_name:列名称。
  • Collation:列以什么方式存储在索引中。在MySQL中:‘A’(升序)或NULL(无分类)。
  • Cardinality:索引中唯一值的数目的估计值。
  • Sub_part:如果列只是被部分地编入索引,则为被编入索引的字符的数目。如果整列被编入索引,则为NULL。
  • Packed:指示关键字如何被压缩。如果没有被压缩,则为NULL。
  • Null:如果列含有NULL,则含有YES。如果没有,则该列含有NO。
  • Index_type:用过的索引方法(BTREE, FULLTEXT, HASH, RTREE)。

简单的索引

在表上创建一个简单的索引。允许使用重复的值:

CREATE INDEX index_name ON tablename (columnname);

创建表的时候同时创建索引

CREATE TABLE `tablename` (  `id` int(11) NOT NULL AUTO_INCREMENT ,  `title` char(255) NOT NULL ,  INDEX indexname (title(20))
) ENGINE=InnoDB  DEFAULT CHARSET=utf8;

Key和index的区别

  • Key:包含两层意义,一是约束(偏重于约束和规范数据库的结构完整性),二是索引(辅助查询用的)。包括primary key, unique key, foreign key 等
  • Index:是数据库的物理结构,它只是辅助查询的,它创建时会在另外的表空间(mysql中的innodb表空间)以一个类似目录的结构存储。索引要分类的话,分为前缀索引、全文本索引等; 因此,索引只是索引,它不会去约束索引的字段的行为(那是key要做的事情)。

短索引

CREATE INDEX index_name ON tablename (title(20));

INDEX indexname (title(20)):将title前面20个字符作为索引。

唯一索引

与普通索引类似,不同的就是:索引列的值必须唯一,但允许有空值(注意和主键不同)。

如果是组合索引,则列值的组合必须唯一,创建方法和普通索引类似。

好处:

  • 一是简化了MySQL对这个索引的管理工作,这个索引也因此而变得更有效率;
  • 二是MySQL会在有新记录插入数据表时,自动检查新记录的这个字段的值是否已经在某个记录的这个字段里出现过了;如果是,MySQL将拒绝插入那条新记录。

创建唯一索引

CREATE UNIQUE INDEX index_name ON table_name(column_name);

创建表的时候直接指定

CREATE TABLE `table_name` (  `id` int(11) NOT NULL AUTO_INCREMENT ,  `title` char(255) NOT NULL ,  UNIQUE index_name (title)
);

主索引(唯一)

必须为主键字段创建一个索引,这个索引就是所谓的"主索引"。

主索引与唯一索引的唯一区别是:前者在定义时使用的关键字是PRIMARY而不是UNIQUE,但是包含UNIQUE的特征。

创建主索引

CREATE PRIMARY INDEX index_name ON table_name(column_name);

创建表的时候直接指定

CREATE TABLE `table_name` (  `id` int(11) NOT NULL AUTO_INCREMENT ,  `title` char(255) NOT NULL ,  PRIMARY KEY (`id`),
);

复合索引

复合索引就是使用多个列作为索引,当某一个列出现相同值的时候,使用另一个列来检索。

因此,作为复合索引的多个列的组合一定是不能重复的,如班级和姓名一起作为复合主键。

KEY (`role_id`,`permission_id`)
UNIQUE KEY (`role_id`,`permission_id`)
INDEX (`role_id`,`permission_id`)
UNIQUE INDEX (`role_id`,`permission_id`)

全文索引

文本字段上的普通索引只能加快对出现在字段内容最前面的字符串(也就是字段内容开头的字符)进行检索操作。

如果字段里存放的是由几个、甚至是多个单词构成的较大段文字,普通索引就没什么作用了。

这种检索往往以LIKE %word%的形式出现,这对MySQL来说很复杂,如果需要处理的数据量很大,响应时间就会很长。

这类场合正是全文索引(full-text index)可以大显身手的地方。在生成这种类型的索引时,MySQL将把在文本中出现的所有单词创建为一份清单,查询操作将根据这份清单去检索有关的数据记录。

CREATE FULLTEXT INDEX index_name ON table_name (column_name);

也可以在创建索引的时候指定索引的长度:

CREATE FULLTEXT INDEX index_name ON table_name (column_name);

如:

CREATE TABLE article ( id INT AUTO_INCREMENT NOT NULL PRIMARY KEY, title VARCHAR(200), body TEXT, FULLTEXT(title, body)
) ENGINE =MYISAM;

事务

事务就是对数据库执行的最小的工作单元(执行的多个操作)。

事务是完成逻辑顺序的工作,无论是在手动方式由用户或者自动地通过某种数据库程序的序列的单元。

事务特性:

事务具有以下四个标准属性,通常由首字母缩写ACID简称:

事务需要使用INNODB数据引擎

  • 原子性: 一个事务(transaction)中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被回滚(Rollback)到事务开始前的状态,就像这个事务从来没有执行过一样。
  • 一致性: 确保数据库正确后成功提交事务更改状态。
  • 隔离性: 数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。
  • 持久性: 事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

事务控制

用来控制事务有如下命令:

  • set autocommit=0:设置事务非自动提交。
  • BEGIN | START transaction : 开启事务
  • COMMIT : 提交事务。
  • ROLLBACK : 事物回滚。
  • SAVEPOINT : 创建回滚事务点
  • SET TRANSACTION : 放置事务的名称。

set autocommit=0指事务非自动提交,自此句执行以后,每个SQL语句或者语句块所在的事务都需要显示"commit"才能提交事务。

  1. 不管autocommit 是1还是0 START TRANSACTION 后,只有当commit数据才会生效,ROLLBACK后就会回滚。

  2. 当autocommit 为 0 时 不管有没有START TRANSACTION。 只有当commit数据才会生效,ROLLBACK后就会回滚。

  3. 如果autocommit 为1 ,并且没有START TRANSACTION 。 调用ROLLBACK是没有用的。即便设置了SAVEPOINT。

示例:

set autocommit=0;
start transaction;
insert into borrow value(2,1,1,'2020-12-30',12,null);
update book set count=count-1 where id=2;
commit;

SAVEPOINT:

保存点SAVEPOINT是,可以回滚事务到某一事务节点,而不回滚整个事务。

SAVEPOINT命令的语法如下:

set autocommit=0;
BEGIN;
SAVEPOINT SAVEPOINT_NAME;
DELETE FROM CUSTOMERS WHERE AGE = 25;
ROLLBACK TO SAVEPOINT_NAME;
COMMIT;

ROLLBACK

ROLLBACK命令是用来撤消尚未被保存到数据库事务的事务命令。

set autocommit=0;
BEGIN
DELETE FROM CUSTOMERS WHERE AGE = 25;
ROLLBACK;

删除操作将会失效。

数据库的引擎

数据库提供的引擎如下:

MyISAM:默认的 MySQL 插件式存储引擎,它是在 Web、数据仓储和其他应用环境下最常使用的存储引擎之一。

InnoDB:用于事务处理应用程序,具有众多特性,包括 ACID 事务支持,提供行级锁。

Memory:将所有数据保存在内存中,在需要快速查找引用和其他类似数据的环境下,可提供极快的访问。

数据库的隔离级别

对于同时运行的多个事务,当这些事务访问数据库中相同的数据时,如果没有采取必要的隔离机制,就会导致各种并发问题:
脏读:对于两个事务 T1,T2,T1 读取了已经被 T2 更新但还没有被提交的字段之后,若 T2 回滚,T1 读取的内容就是临时且无效的。
不可重复读:对于两个事务 T1,T2,T1 读取了一个字段,然后 T2 更新了该字段. 之后,T1 再次读取同一个字段,值就不同了。
幻读:对于两个事务 T1,T2,T1 从一个表中读取了一个字段,然后 T2 在该表中插入了一些新的行。之后,如果 T1 再次读取同一个表,就会多出几行。
数据库事务的隔离性:数据库系统必须具有隔离并发运行各个事务的能力,使它们不会相互影响,避免各种并发问题. 一个事务与其他事务隔离的程度称为隔离级别. 数据库规定了多种事务隔离级别,不同隔离级别对应不同的干扰程度,隔离级别越高,数据一致性就越好,但并发性越弱。

数据库共定义了四种隔离级别:

Serializable:可避免脏读、不可重复读、幻读情况的发生。(串行化) 读写加排他锁
Repeatable read:可避免脏读、不可重复读情况的发生。
Read committed:可避免脏读情况发生。
Read uncommitted:最低级别,以上情况均无法保证。(读未提交)

Oracle 支持 2 种事务隔离级别:READ COMMITED,SERIALIZABLE。Oracle 默认的事务隔离级别为: READ COMMITED

Mysql 支持 4 种事务隔离级别。Mysql 默认的事务隔离级别为: REPEATABLE READ

锁机制

共享锁

由读表操作加上的锁,加锁后其他用户只能获取该表或行的共享锁,不能获取排它锁,也就是说只能读不能写

排它锁

由写表操作加上的锁,加锁后其他用户不能获取该表或行的任何锁,典型是mysql事务

根据锁的范围,可以分为

表锁

给整张表加锁

行锁

给行数据加锁

因此锁可以分为表级共享锁行级共享锁表级排它锁行级排它锁

第03章-WEB技术-MySQL高级语法

ALTER语句

语法:

ALTER TABLE <表名> [修改选项]

修改选项的语法格式如下:

{ ADD COLUMN <列名> <类型>
| CHANGE COLUMN <旧列名> <新列名> <新列类型>
| ALTER COLUMN <列名> { SET DEFAULT <默认值> | DROP DEFAULT }
| MODIFY COLUMN <列名> <类型>
| DROP COLUMN <列名>
| RENAME TO <新表名>
| CHARACTER SET <字符集名>
| COLLATE <校对规则名> }

修改表名

ALTER TABLE <旧表名> RENAME [TO] <新表名>;

说明:TO 为可选参数,使用与否均不影响结果。

先创建一个数据库:

create database databasename DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

可以看见默认的字符集是UTF-8

修改数据库默认字符集

查看数据库的字符集

show create database `databasename`;

修改字符集为gbk:

alter database `databasename` DEFAULT CHARACTER SET gbk COLLATE gbk_chinese_ci;

修改字符集为utf-8:

alter database `databasename` DEFAULT CHARACTER SET utf8 COLLATE utf8_general_ci;

修改表数据引擎

使用数据库:

use databasename;

创建数据表:

create table if not exists tabename(id int(5) primary key auto_increment,name varchar(60) not null,pswd varchar(60) not null
);

查看表的创建结构:

show create table tabename;

或者:

show table status from databasename where name='tabename';

可见表的数据引擎是MyISAM

修改数据引擎:

alter table tabename engine=innodb;

这样表的数据引擎已经变成InnoDB了

添加表的列

alter table tabename add sex varchar(10) not null;

修改表的列

alter table tabename modify column name varchar(255);

删除表的列

alter table tabename drop column sex;

修改索引

先创建索引:

create [UNIQUE|FULLTEXT|PRIMARY|SPATIAL] index indexname on tabename(name,pswd);

如:

create index indexname on tabename(name,pswd);
show index from tabename;

修改索引应该先删除再创建:

alter table tabename drop index indexname;
alter table tabename add index indexname(name(8));

修改外键

先创建新表:表类型tabletype

create table tabletype(id int(5) primary key not null,type varchar(60) not null,status int(1) not nuldefault 1
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

再给tabename表添加type_id字段:

alter table tabename add column type_id int(5) not null;

再添加外键:

alter table tabename add constraint foreignkeyname foreign key(type_id) references tabletype(id);

再查看表创建结构:

show create table tabename;

再查看外键:

show index from tabename;

alter删除外键:

alter table tabename drop foreign key foreignkeyname;

自定义函数【FUNCTION】

自定义函数也分为二种,一种是标量值函数,另一种是表格值函数。

需要设置

SET GLOBAlog_bin_trust_function_creators=TRUE;

语法:

set global log_bin_trust_function_creators=true;
delimiter$$
create function mypow(number int)
returns int
begin
return number*number;
end;$$
delimiter;
insert into course value(3,'Java4',mypow(3));

存储过程【PROCEDURE】

通常情况,大多数使用的SQL语句都是针对一个或多个表的单条语句。

但是并非所有操作都这么简单,经常会有一个完整的操作需要多条语句才能完成。

存储过程简单来说,就是为以后的使用而保存的一条或多条MySQL语句的集合。

存储过程可视为批处理,虽然它们的作用不仅限于批处理。

存储过程思想上很简单,就是数据库 SQ语言层面的代码封装与重用。

优点

  • 存储过程可封装,并隐藏复杂的商业逻辑。
  • 存储过程可以回传值,并可以接受参数。
  • 存储过程无法使用 SELECT 指令来运行,因为它是子程序,与查看表,数据表或用户定义函数不同。
  • 存储过程可以用在数据检验,强制实行商业逻辑等。

缺点

  • 存储过程,往往定制化于特定的数据库上,因为支持的编程语言不同。当切换到其他厂商的数据库系统时,需要重写原有的存储过程。

  • 存储过程的性能调校与撰写,受限于各种数据库系统。

  • 查询全部存储过程

    SHOW PROCEDURE STATUS;
    

    查询自定义存储过程

    SHOW PROCEDURE STATUS LIKE 'g%';
    

    语法

    DELIMITER $$CREATE [DEFINER = { user | CURRENT_USER }]PROCEDURE 存储过程名 ([[IN|OUT|INOUT] 参数名 数据类形[,...]]) [LANGUAGE SQL| [NOT] DETERMINISTIC| {CONTAINS SQ| NO SQ| READS SQDATA | MODIFIES SQDATA} | SQSECURITY {DEFINER | INVOKER}]valid SQroutine statementBEGIN#1、变量DECLARE 变量名 数据类形[;...]SET 变量名=值;#2、IF语句IF 变量名=值 THEN[语句...;]ELSEIF[语句...;] ELSE[语句...;]END IF;#3、CASE语句CASE 变量名WHEN 值1 THEN [语句1...;] WHEN 值2 THEN [语句2...;]END CASE;#3、WHILE语句WHILE 条件 DO[语句...;]END WHILE;END$$#将语句的结束符号恢复为分号
    DELIMITER ;
    

    参数

    存储过程有3种参数类型:

    • **IN 输入参数:**表示调用者向过程传入值(传入值可以是字面量或变量)
    • **OUT 输出参数:**表示过程向调用者传出值(可以返回多个值)(传出值只能是变量)
    • **INOUT 输入输出参数:**既表示调用者向过程传入值,又表示过程向调用者传出值(值只能是变
create procedure a1(in a int,out b varchar(20),inout c decimal(4,2))
begindeclare x int;declare y varchar(20);declare m decimal(4,2);set a=x;set b=y;set c=m;if a<60 then set b='不及格';elseif a>=60 and a<80 then set b='良好';elseif a>=80 and a<=100 then set b='优秀';end if;case bwhen '不及格' then set c= '还需要努力';when '良好' then set c= '继续加油';when '优秀' then set c= '学霸真帅';end case;while b>80 do set c= '学霸';end while;
end;set @a=80;
set @b=90;
set @c=21.43;
select @a,@b,@c;
call a1(80,23,43);
select @a,@b,@c;

光标

MYSQL里叫光标,SQLSERVER里叫游标,实际上一样的

查询语句可能查询出多条记录,在存储过程和函数中使用光标来逐条读取查询结果集中的记录。

光标的使用包括声明光标、打开光标、使用光标和关闭光标。光标必须声明在处理程序之前,并且声明在变量和条件之后。

声明光标:

DECLARE cursor_name CURSOR FOR select_statement ;

打开光标:

OPEN  cursor_name ;

使用光标:

FETCH next from cursor_name INTO var_name[,var_name…] ;

关闭光标:

CLOSE  cursor_name ;

注意:MYSQL中,光标只能在存储过程和函数中使用!

案例

查询【所有课程的成绩第2名到第3名】的学生【名字及该课程和成绩】

每次查询一门课程的第2、3名,

循环多次,把所有的结果合并起来

结束

DELIMITER $$#创建root用户的存储过程,存储过程的名称为:topic19,没有参数CREATE DEFINER = 'root' @'localhost' PROCEDURE `topic20` ()
#存储过程的开头,相当于java的“{”BEGIN#创建存储查询结果的变量DECLARE courseName NVARCHAR (100);#创建存储光标结束标记的变量DECLARE done BOOLEAN DEFAULT TRUE;#根据`course`表的所有`name`值创建一个游标DECLARE cursor1 CURSOR FORSELECT`name`FROM`course`;#当游标中内容执行完之后,设置done为trueDECLARE CONTINUE HANDLER FOR NOT FOUND SET done = FALSE;#打开游标OPEN cursor1;#创建一张临时表,用于存储每次循环查出来的内容CREATE TEMPORARY TABLE IF NOT EXISTS `newtable` (`stuname` VARCHAR (10),`souname` VARCHAR (10),`score` DECIMA(4, 2));#开始循环,循环条件是游标是否结束WHILEdone = TRUE DO #获取数据,游标下移一行FETCH NEXT FROM cursor1 INTO courseName;#将查询出来的内容直接插入到`newtable`表中INSERT INTO `newtable`(SELECT`student`.`name` AS 'stuname',`course`.`name` AS 'souname',`score`FROM`score`JOIN `course`ON `course`.`id` = `score`.`courseID`JOIN `teacher`ON `course`.`teacherID` = `teacher`.`id`JOIN `student`ON `score`.`studentID` = `student`.`id`WHERE `course`.`name` = courseNameORDER BY `score` DESCLIMIT 1, 2);#结束循环END WHILE;#关闭游标CLOSE cursor1;#上面所有代码都没有查数据,所以没有任何显示内容,必须手动查所需要的内容SELECT DISTINCT*FROM`newtable`ORDER BY `souname`;#存储过程的结尾,相当于java的“}”END $$DELIMITER ;
#调用存储过程
CALtopic19();

示例:

createdefiner = root@localhost procedure test2()
begindeclare student_id int(10);declare done boolean default true;declare cur cursor for select id from student;declare continue handler for not found set done=false;open cur;while done dofetch next from cur into student_id;select student_id;end while;
end;

事件【EVENT】

创建事件任务

创建事件使用CREATE EVENT database.even_name语句

语法:


DELIMITER $$
-- SET GLOBAevent_scheduler = ON$$     -- 开起数据库公共事件执行器
DROP EVENT IF EXISTS `uniadmin`.`test`$$
CREATE  EVENT `uniadmin`.`test`
ON SCHEDULE EVERY 1 SECONDDOBEGINUPDATE uni_menu SET `sort` = `sort`+1 WHERE `id`='1';END$$DELIMITER ;

开起事件任务

alter event `uniadmin`.`test` ON COMPLETION PRESERVE ENABLE;

关闭事件任务

alter event `uniadmin`.`test` ON COMPLETION PRESERVE DISABLE;

查看事件开起状态


SHOW VARIABLES LIKE '%sche%';# 或者SHOW GLOBAVARIABLES LIKE 'event%';

关闭事件执行器

SET GLOBAevent_scheduler = 0;

触发器【TRIGGER】

MySQ数据库中触发器是一个特殊的存储过程,不同的是执行存储过程要使用 CAL语句来调用,而触发器的执行不需要使用 CAL语句来调用,也不需要手工启动,只要一个预定义的事件发生就会被 MySQL自动调用。

引发触发器执行的事件一般如下:

  • 增加一条学生记录时,会自动检查年龄是否符合范围要求。
  • 每当删除一条学生信息时,自动删除其成绩表上的对应记录。
  • 每当删除一条数据时,在数据库存档表中保留一个备份副本。

触发程序的优点如下:

  • 触发程序的执行是自动的,当对触发程序相关表的数据做出相应的修改后立即执行。
  • 触发程序可以通过数据库中相关的表层叠修改另外的表。
  • 触发程序可以实施比 FOREIGN KEY 约束、CHECK 约束更为复杂的检查和操作。

触发器与表关系密切,主要用于保护表中的数据。特别是当有多个表具有一定的相互联系的时候,触发器能够让不同的表保持数据的一致性。

在 MySQ中,只有执行 INSERT、UPDATE 和 DELETE 操作时才能激活触发器。

三种触发器的执行时间如下。

  • INSERT:将新行插入表时激活触发器。例如,INSERT 的 BEFORE 触发器不仅能被 MySQ的 INSERT 语句激活,也能被 LOAD DATA 语句激活。新插入的行用new来表示,行中的每一列的值用new.列名来表示
  • DELETE: 从表中删除某一行数据时激活触发器,例如 DELETE 和 REPLACE 语句。被删除的旧行用old用来表示,行中的每一列的值用old.列名来表示
  • UPDATE:更改表中某一行数据时激活触发器,例如 UPDATE 语句。可以使用new和old

查看触发器

show triggers from databaseName;

删除触发器

drop trigger if exists databaseName.tri_Name;

语法

DELIMITER $$CREATE/*[DEFINER = { user | CURRENT_USER }]*/TRIGGER `schooldata`.`name` BEFORE/AFTER INSERT/UPDATE/DELETEON `schooldata`.`<Table Name>`FOR EACH ROW BEGINEND$$DELIMITER ;

案例1

CREATE DEFINER=`root`@`localhost` TRIGGER `onupdate` BEFORE UPDATE ON `a` FOR EACH ROW BEGINinsert into log(`type`,`desc`) values('update',concat('更新前:[',old.id,'],更新后:[',new.id,']'));
END;

案例2

DELIMITER $$CREATE TRIGGER `schooldata`.`wwww` BEFORE INSERT
ON `schooldata`.`score` FOR EACH ROW
BEGINUPDATE score SET NEW.`score` = 5+ NEW.`score`;
END $$DELIMITER ;

触发器使用场景

可以监视某表的变化,当发生某种变化时,触发某个操作

触发器应用场景:

  1. 当向一张表中添加或删除记录时,需要在相关表中进行同步操作。

    1. 比如,当一个订单产生时,订单所购的商品的库存量相应减少。
  2. 当表上某列数据的值与其他表中的数据有联系时。
    1. 比如,当某客户进行欠款消费,
  3. 可以在生成订单时通过设计触发器判断该客户的累计欠款是否超出了最大限度。
  4. 当需要对某张表进行跟踪时。
    1. 比如,当有新订单产生时,需要及时通知相关人员进行处理,
    2. 此时可以在订单表上设计添加触发器加以实现

SQL 注入

SQL注入是通过SQL语法的漏洞,盗取数据、修改数据等的操作。

假设有如下查询语法:

SELECT ? FROM  ? WHERE  ? LIKE  '%好%';

其中'%好%'为搜索的关键词,表示搜索带有好字的内容

假如把搜索的关键词改为:'%';--好%',就能查询全部数据。

案例

举一个比较常见的例子来简要说明一下sql注入的原理。

假如我们有一个users表,里面有两个字段username和password。在我们的java代码中我们初学者都习惯用sql拼接的方式进行用户验证。

String sql = "select id from users where username = '" + username + "' and password = '" + password + "'"

这里的username和password都是我们存取从web表单获得的数据。

下面我们来看一下一种简单的注入,如果我们在表单中username的输入框中输入' or 1=1-- ,password的表单中随便输入一些东西,假如这里输入123。此时我们所要执行的sql语句就变成了

select id from users where username = '' or 1=1-- and password = '123'

我们来看一下这个sql,因为1=1是true,后面 and password = '123’被注释掉了。所以这里完全跳过了sql验证。

注入中常用的函数与语法

  • Group_concat():将select的查询结果全部显示出来,占一个显示位
  • select version():查询MySQL版本
  • select user():查询数据库用户名
  • select database()):查询数据库名
  • select @@datadir():查询数据库的绝对路径
  • select @@version_compile_os:查询操作系统版本
  • select current_user():查询当前用户
  • Order by: 找列的数量
  • Union select:联合查询(联合查询的条件是前一条语句查询不到且字段数与前一条语句的查询字段数一致)
  • limit:限制显示个数(如:limit 0 2 表示从第一个开始显示两个)

判断是否存在sql注入漏洞。

  • 构建sql语句:?id=1 and 1=2 查看页面是否正常。结果页面显示不正常。

  • 注释:因为id=1为真(可正常访问页面),且1=2为假,所以and条件永远不会成立。对于web应用不会返回结果给用户。则攻击者能看到的是一个错误的界面或者页面结果为空。当然,如果攻击者构造的请求异常,也会导致页面访问不正常。

  • 构建新的sql语句,确定是否存在语句逻辑错误导致页面不正常。?id=1 and 1=1 结果页面正常,初步判断存在sql漏洞。

    注释:1=1 为真,and条件语句成立。

判断字段数:

  • 构建sql语句:

    • ?id=1 and 1=1 order by 1 判断网页是否正常。
    • ?id=1 and 1=1 order by 2 判断网页是否正常。
    • ?id=1 and 1=1 order by 3 判断网页是否正常。
    • 结果:?id=1 and 1=1 order by 3 网页显示不正常,可以判断字段数为2
    • 注释:“order by 1”表示对第一栏位进行排序,

判断回显点:

  • 构建sql语句:

    ?id=1 and 1=2 union select 1,2
    

    (之后的查询结果将显示在下图红框位置)

    • 注释:union 操作符用于合并两个或多个select语句的结果集,union内部的select语句必须拥有相同数量的列。

获取信息

查看当前数据库名以及数据库版本。

  • 构建sql语句:

    ?id=1 and 1=2 union select 1,database();?id=1 and 1=2 unio select 1, version()
    
    • 注释:

      • union select 1 ,database(),其中数字1占一列,凑数,用来满足union定义。
      • database():表示网站使用的数据库,version():表示当前mysql的版本,usr():当前mysql的用户。

查询当前数据库以及表名称。

  • 构建sql语句:

    ?id=1 and 1=2 union select 1,table_name from information_schema.tables where table_schema=database() limit 0,1
    
    • 注释:

      • information_schema数据库用于存储数据库元数据,例如:数据库名,表名,列的数据类型,访问权限等。
      • tables用来存储数据库中的表的信息,包括表属于哪个数据库,表的类型,存储引擎,创建时间等。t
      • able_schema和table_schema是表tables中的数据库库名和表名。
      • limit 0,1 表示第一行显示一行数据。
      • limit 1,1表示第二行显示一行数据。

查询表admin中的字段名。

查询三个字段:id、username 、password

  • 构建SQL语句:?id=1 and 1=2 union select 1,column_name from information_schema.columns where table_schema=database() and table_name='admin' limit 0,1
  • 构建SQL语句:?id=1 and 1=2 union select 1,column_name from information_schema.columns where table_schema=database() and table_name='admin' limit 1,1
  • 构建SQL语句:?id=1 and 1=2 union select 1,column_name from information_schema.columns where table_schema=database() and table_name='admin' limit 2,1
  • 注释:
    • columns表存储表中的列的信息。
    • 其中包含数据库库名table_schema,表名table_name ,字段名column_name。

查询用户名称

  • ?id=1 and 1=2 union select 1,username from admin

查询密码:

  • ?id=1 and 1=2 union select 1,password from admin

SQL优化

explain

通过explain命令可以清楚看到MySQL是如何处理sql语句的

如下SQL

explain select * from itdragon_order_list where transaction_id = "81X97310V32236260E";

结构如下:

+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | SIMPLE | itdragon_order_list | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 33.33 | Using where | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+

打印的内容分别表示:

  • id : 查询序列号为1。
  • select_type : 查询类型是简单查询,简单的select语句没有union和子查询。
  • table : 表是 itdragon_order_list。
  • partitions : 没有分区NULL 。
  • type : 连接类型,all表示采用全表扫描的方式。
  • possible_keys : 可能用到索引为null。
  • key : 实际用到索引是null。
  • key_len : 索引长度当然也是null。
  • ref : 没有哪个列或者参数和key一起被使用。
  • rows : 行数
  • filtered : 被过滤
  • Extra : 使用了where查询。

这里需要重点了解的是type为ALL,全表扫描的性能是最差的,假设数据库中有几百万条数据,在没有索引的帮助下会异常卡顿。

参数说明

id

select 查询的序列号,包含一组可以重复的数字,表示查询中执行sql语句的顺序。

一般有三种情况:

  1. 第一种:id全部相同,sql的执行顺序是由上至下;
  2. 第二种:id全部不同,sql的执行顺序是根据id大的优先执行;
  3. 第三种:id既存在相同,又存在不同的。先根据id大的优先执行,再根据相同id从上至下的执行。
select_type

select 查询的类型,主要是用于区别普通查询,联合查询,嵌套的复杂查询

  • simple:简单的select 查询,查询中不包含子查询或者union
  • primary:查询中若包含任何复杂的子查询,最外层查询则被标记为primary
  • subquery:在select或where 列表中包含了子查询
  • derived:在from列表中包含的子查询被标记为derived(衍生)MySQL会递归执行这些子查询,把结果放在临时表里。
  • union:若第二个select出现在union之后,则被标记为union,若union包含在from子句的子查询中,外层select将被标记为:derived
  • union result:从union表获取结果的select
partitions

表所使用的分区,如果要统计十年公司订单的金额,可以把数据分为十个区,每一年代表一个区。这样可以大大的提高查询效率。

type

这是一个非常重要的参数,连接类型。

常见的有:all , index , range , ref , eq_ref , const , system , null 八个级别。

性能从最优到最差的排序:system > const > eq_ref > ref > range > index > all

对java程序员来说,若保证查询至少达到range级别或者最好能达到ref则算是一个优秀而又负责的程序员。

  • all:(full table scan)全表扫描无疑是最差,若是百万千万级数据量,全表扫描会非常慢。
  • index:(full index scan)全索引文件扫描比all好很多,毕竟从索引树中找数据,比从全表中找数据要快。
  • range:只检索给定范围的行,使用索引来匹配行。范围缩小了,当然比全表扫描和全索引文件扫描要快。sql语句中一般会有between,in,>,< 等查询。
  • ref:非唯一性索引扫描,本质上也是一种索引访问,返回所有匹配某个单独值的行。比如查询公司所有属于研发团队的同事,匹配的结果是多个并非唯一值。
  • eq_ref:唯一性索引扫描,对于每个索引键,表中有一条记录与之匹配。比如查询公司的CEO,匹配的结果只可能是一条记录,
  • const:表示通过索引一次就可以找到,const用于比较primary key 或者unique索引。因为只匹配一行数据,所以很快,若将主键至于where列表中,MySQL就能将该查询转换为一个常量。
  • system:表只有一条记录(等于系统表),这是const类型的特列,平时不会出现,了解即可
possible_keys

显示查询语句可能用到的索引(一个或多个或为null),不一定被查询实际使用。仅供参考使用。

key

显示查询语句实际使用的索引。若为null,则表示没有使用索引。

key_len

显示索引中使用的字节数,可通过key_len计算查询中使用的索引长度。在不损失精确性的情况下索引长度越短越好。key_len 显示的值为索引字段的最可能长度,并非实际使用长度,即key_len是根据表定义计算而得,并不是通过表内检索出的。

ref

显示索引的哪一列或常量被用于查找索引列上的值。

rows

根据表统计信息及索引选用情况,大致估算出找到所需的记录所需要读取的行数,值越大越不好。

extra
  • Using filesort: 说明MySQL会对数据使用一个外部的索引排序,而不是按照表内的索引顺序进行读取。MySQL中无法利用索引完成的排序操作称为“文件排序” 。出现这个就要立刻优化sql。
  • Using temporary: 使用了临时表保存中间结果,MySQL在对查询结果排序时使用临时表。常见于排序 order by 和 分组查询 group by。 出现这个更要立刻优化sql。
  • Using index: 表示相应的select 操作中使用了覆盖索引(Covering index),避免访问了表的数据行,效果不错!如果同时出现Using where,表明索引被用来执行索引键值的查找。如果没有同时出现Using where,表示索引用来读取数据而非执行查找动作。 覆盖索引(Covering Index) :也叫索引覆盖,就是select 的数据列只用从索引中就能够取得,不必读取数据行,MySQL可以利用索引返回select 列表中的字段,而不必根据索引再次读取数据文件。
  • Using index condition: 在5.6版本后加入的新特性,优化器会在索引存在的情况下,通过符合RANGE范围的条数 和 总数的比例来选择是使用索引还是进行全表遍历。
  • Using where: 表明使用了where 过滤
  • Using join buffer: 表明使用了连接缓存
  • impossible where: where 语句的值总是false,不可用,不能用来获取任何元素
  • distinct: 优化distinct操作,在找到第一匹配的元组后即停止找同样值的动作。
filtered

一个百分比的值,和rows 列的值一起使用,可以估计出查询执行计划(QEP)中的前一个表的结果集,从而确定join操作的循环次数。小表驱动大表,减轻连接的次数。

通过explain的参数介绍,我们可以得知:

  • 表的读取顺序(id)
  • 数据读取操作的操作类型(type)
  • 哪些索引被实际使用(key)
  • 表之间的引用(ref)
  • 每张表有多少行被优化器查询(rows)

优化分析

1、初步优化:创建索引

-- 创建索引
create unique index idx_order_transaID on itdragon_order_list (transaction_id);
-- 分析
explain select * from itdragon_order_list where transaction_id = "81X97310V32236260E";

结果

+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | SIMPLE | itdragon_order_list | NULL | const | NULL | NULL | NULL | NULL | 3 | 33.33 | NULL | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+

这里创建的索引是唯一索引,而非普通索引。

唯一索引打印的type值是const。表示通过索引一次就可以找到。即找到值就结束扫描返回查询结果。

普通索引打印的type值是ref。表示非唯一性索引扫描。找到值还要继续扫描,直到将索引文件扫描完为止。

显而易见,const的性能要远高于ref。并且根据业务逻辑来判断,创建唯一索引是合情合理的。

2、再次优化:覆盖索引

select * from 改为了 select transaction_id from

explain select transaction_id from itdragon_order_list where transaction_id = "81X97310V32236260E";

结果

+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+| 1 | SIMPLE | itdragon_order_list | NULL | const | NULL | NULL | NULL | NULL | 3 | 33.33 | Using index | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+-------------+

Extra 显示 Using index,表示该查询使用了覆盖索引,这是一个非常好的消息,说明该sql语句的性能很好。若提示的是Using filesort(使用内部排序)和Using temporary(使用临时表)则表明该sql需要立即优化了。

根据业务逻辑来的,查询结构返回transaction_id 是可以满足业务逻辑要求的。

3、涉及到排序

既然是排序,首先想到的应该是order by, 还有一个可怕的 Using filesort 等着你。

explain select * from itdragon_order_list order by order_level,input_date;

结果

+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+----------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+----------------+
| 1 | SIMPLE | itdragon_order_list | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100 | Using filesort | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+----------------+

首先,采用全表扫描就不合理,还使用了文件排序Using filesort,更加拖慢了性能。

MySQL在4.1版本之前文件排序是采用双路排序的算法,由于两次扫描磁盘,I/O耗时太长。后优化成单路排序算法。其本质就是用空间换时间,但如果数据量太大,buffer的空间不足,会导致多次I/O的情况。其效果反而更差。与其找运维同事修改MySQL配置,还不如自己乖乖地建索引。

4、排序字段加复合索引

为order_level,input_date 创建复合索引

-- 创建复合索引
create index idx_order_levelDate on itdragon_order_list (order_level,input_date);
-- 分析
explain select * from itdragon_order_list order by order_level,input_date;

结果

+----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+----------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+----------------+ | 1 | SIMPLE | itdragon_order_list | NULL | ALL | NULL | NULL | NULL | NULL | 3 | 100 | Using filesort | +----+-------------+---------------------+------------+------+---------------+------+---------+------+------+----------+----------------+

创建复合索引后你会惊奇的发现,和没创建索引一样???都是全表扫描,都用到了文件排序。是索引失效?还是索引创建失败?

5、再次覆盖索引

将select * from 换成了 select order_level,input_date from

explain select order_level,input_date from itdragon_order_list order by order_level,input_date;

结果

+----+-------------+---------------------+------------+-------+---------------+---------------------+---------+------+------+----------+-------------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+-------+---------------+---------------------+---------+------+------+----------+-------------+
| 1 | SIMPLE | itdragon_order_list | NULL | index | NULL | idx_order_levelDate | 68 | NULL | 3 | 100 | Using index | +----+-------------+---------------------+------------+-------+---------------+---------------------+---------+------+------+----------+-------------+

type从all升级为index,表示(full index scan)全索引文件扫描,Extra也显示使用了覆盖索引。

可是不对啊!!!!检索虽然快了,但返回的内容只有order_level和input_date 两个字段,让业务同事怎么用?难道把每个字段都建一个复合索引?

MySQL没有这么笨,可以使用force index 强制指定索引。

6、强制使用指定索引

在原来的sql语句上修改 force index(idx_order_levelDate) 即可。

explain select * from itdragon_order_list force index(idx_order_levelDate) order by order_level,input_date;

结果

+----+-------------+---------------------+------------+-------+---------------+---------------------+---------+------+------+----------+-------+
| id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+---------------------+------------+-------+---------------+---------------------+---------+------+------+----------+-------+
| 1 | SIMPLE | itdragon_order_list | NULL | index | NULL | idx_order_levelDate | 68 | NULL | 3 | 100 | NULL | +----+-------------+---------------------+------------+-------+---------------+---------------------+---------+------+------+----------+-------+

好处是使用索引,坏处是没有覆盖索引,会回表查询。

MySql_float类型字段查询不出来

当一个table表中有个字段(如:point)为Float类型,查询匹配时,查询结果为null。如下sql:

select count(1) from table1 where point='15.11';

结果为:0

原因是:FLOAT不标准,先查询一下所有值就看得出来了,转成VARCHAR再比较试试。如下sql:

select count(1) from table1 where LTRIM(point)=LTRIM('15.11');

结果为:1

原因是:在mysql中,float是浮点数,Mysql存储的时候是近似值,所以用精确查找无法匹配;但可以用like去匹配。

解决方法:

  • 如果只用到Mysql数据库,不需要多库关联,针对小数类型的字段,可以使用decimal字段类型,decimal数据类型最多可存储 38 个数字,它存储了一个准确(精确)的数字表达法,不存储值的近似值。
  • 也可以在创建字段时指定float的长度和小数点位数。
  • numeric和decimal同义,numeric将自动转成decimal。

对于Decimal(M,N)的取值范围,因为它是以串的形式存放数字,他占用的字节为M+2字节。小数点和负数各占用一个字节,所以他的理论取值范围是这样的。

decimal(2,1) 的取值范围,一共占用4字节,负数和小数点占用2字节,负数最小为-9.9,同理正数符号可以隐藏,最大的正数为99.9.

MySQL和数据库总结相关推荐

  1. Mysql创建数据库用户

    Mysql为数据库创建用户 通常情况下我们在编写代码的过程中(也就是在开发过程中),一直使用的是我们本地的mysql,而且用户都是root用户,最高权限的用户,但是我们如果在公司上班的时候,公司的领导 ...

  2. MySQL新建数据库+用Navicat查看MySQL的方法

    MySQL新建数据库 数据库启动有问题的,见本人另外一篇博客:启动MySQL:net start mysql出现问题+本地Mysql忘记密码的修改方法 目前的用户名和密码都是root(因为好记!) 打 ...

  3. php mysql source_Mysql数据库导入命令Source详解

    Mysql数据库导入命令Source详解 几个常用用例: 1.导出整个数据库 mysqldump -u 用户名 -p 数据库名 > 导出的文件名mysqldump -u root -p data ...

  4. mysql ldap_OpenLDAP 使用MySQL作为数据库

    一.安装依赖包 yum -y install unixODBC.x86_64 unixODBC-devel.x86_64 libdbi-devel.x86_64 libdbi.x86_64 libdb ...

  5. MariaDB/MySQL从数据库中选择随机的行

    MariaDB/MySQL从数据库中选择随机的行 一个比较传统的做法是使用sql自带的rand函数,从而达到随机排序的目的. SELECT column FROM table ORDER BY RAN ...

  6. MySQL主从数据库同步延迟问题解决

    MySQL主从数据库同步延迟问题 摘要: MySQL的主从同步是一个很成熟的架构,优点为:①在从服务器可以执行查询工作(即我们常说的读功能),降低主服务器压力;②在从主服务器进行备份,避免备份期间影响 ...

  7. mysql导出数据库数据及表结构

    mysql导出数据库数据及表结构 1,导出远程数据库数据到本地 mysql -A wj_sms -h192.168.1.105 -uroot -p4321 -ss -e "set NAMES ...

  8. 如何不停机迁移一个mysql INNODB 数据库?

    2019独角兽企业重金招聘Python工程师标准>>> 如何不停机迁移一个mysql INNODB 数据库? http://www.itpub.net/thread-1776724- ...

  9. linux mysql设置数据库utf_Linux系统下MySQL数据库服务器字符集设置

    Linux认证考试:Linux系统下的MySQL数据库服务器字符集设置 启动MySQL后,以root登录mysql isher@isher-ubuntu:~$ mysql -u root >sh ...

  10. centos sqldeveloper 连接mysql,Oracle SQL Developer 连接 Mysql 等数据库

    Oracle SQL Developer 个人感觉是比较好用的工具,因此除了连接oracle之外,还可以连接其他的数据库,如:MySQL,Access等.但是,它默认情况下只能连接Oracle和Acc ...

最新文章

  1. Matlab与线性代数--广义逆矩阵
  2. 工作169:vue项目报错[Vue warn]: Property “visible“ must be accessed with “$data.visible“ because properties
  3. 高质量JAVA代码编写规范
  4. 工作流之流程定义存储表
  5. 【概率论与数理统计】1.2 概率的定义及其确定方法
  6. String 类的常用方法
  7. 800家电子元器件供应商及代理商
  8. Fast Non-Bayesian Poisson Factorization for Implicit-Feedback Recommendations
  9. 百度导航引擎初始化失败问题解决
  10. Unity 3d Homework 5 打飞碟游戏实现
  11. 实战——Linux定时执行Kettle的kjb文件
  12. 国科大数据挖掘课程总结
  13. 交互设计人员什么阶段介入
  14. 解决VirtualBox增强功能异常
  15. java 二进制最大值_java int型最大值/最小值,最大值+1,最小值-1
  16. 销售数据的多维度交叉分析
  17. 【React】做一个百万答题小项目
  18. hadoop的小疑问:Map执行未结束便开始执行Reduce操作?
  19. 华为机试—手机号码验证
  20. “0xc000007b无法正常启动”我的解决方案

热门文章

  1. 笔记本电脑摄像头无故不能使用的问题解决方法
  2. 科罗拉多州立大学计算机科学,科罗拉多州立大学
  3. python求不规则图形面积_使用Python生成不规则形状的图形
  4. Linux文件打包与压缩
  5. 搭建以太坊私链(单节点,多节点,windows,linux)
  6. 小型数据集卷积神经网络CNN训练策略
  7. CocosCreator矢量绘图组件(1)
  8. X度网盘大文件使用浏览器或迅雷下载的方法之一
  9. 初级计算机英语,初级英语口语怎么学?
  10. office2010安装过程出错(解决方法整合)