SQL常用语句


😀如果对你有帮助的话😊
🌺为博主评论点个赞吧 👍
👍评论是对博主最大的鼓励😋
💓爱心发射~💓

MySQL目录(共7章)

一、初识MySQL

1.1 为什么学习数据库

  1. 岗位技能需求

  2. 现在的世界,得数据者得天下

  3. 存储数据的方法

  4. 程序,网站中,大量数据如何长久保存?

  5. 数据库是几乎软件体系中最核心的一个存在。

1.2 什么是数据库

数据库 ( DataBase , 简称 DB )

概念 : 长期存放在计算机内,有组织,可共享的大量数据的集合,是一个数据 “仓库”

作用 : 保存,并能安全管理数据(如:增删改查等),减少冗余…

数据库总览 :

  • 关系型数据库 ( SQL )
    • MySQL , Oracle , SQL Server , SQLite , DB2 , …

    • 关系型数据库通过外键关联来建立表与表之间的关系

  • 非关系型数据库 ( NOSQL ) not only
    • Redis , MongoDB , …

    • 非关系型数据库通常指数据以对象的形式存储在数据库中,而对象之间的关系通过每个对象自身的属性来决定

1.3 什么是DBMS

数据库管理系统 ( Data Base Management System )

数据库管理软件 , 科学组织和存储数据 , 高效地获取和维护数据

为什么要说这个呢?

因为我们要学习的MySQL应该算是一个数据库管理系统.

; 1.4 MySQL简介

概念 : 是现在 流行开源的, 免费关系型数据库

历史 : 由瑞典MySQL AB 公司开发,目前属于 Oracle 旗下产品。(甲骨文)

特点 :

  • 免费 , 开源数据库
  • 小巧 , 功能齐全
  • 使用便捷
  • 可运行于Windows或Linux操作系统
  • 可适用于中小型甚至大型网站应用

官网 : https://www.mysql.com/

1.5 安装MySQL

这里建议大家使用压缩版,安装快,方便.不复杂.

软件下载

mysql5.7 64位下载地址:

https://dev.mysql.com/get/Downloads/MySQL-5.7/mysql-5.7.19-winx64.zip

电脑是64位的就下载使用64位版本的!

1.6 安装步骤

1、下载后得到zip压缩包.

2、解压到自己想要安装到的目录,本人解压到的是D:\Environment\mysql-5.7.19

3、添加环境变量:我的电脑->属性->高级->环境变量

选择PATH,在其后面添加: 你的mysql 安装文件下面的bin文件夹

4、新建mysql配置文件,编辑 my.ini 文件 ,注意替换路径位置

[mysqld]
basedir=D:\software\Environment\mysql-5.7.27\
datadir=D:\software\Environment\mysql-5.7.27\data\
port=3306
skip-grant-tables

5、启动管理员模式下的CMD,并将路径切换至mysql下的 bin目录,然后输入 mysqld –install(安装mysql)

6、再输入 mysqld --initialize-insecure --user=mysql 初始化数据文件

7、然后再次启动mysql net start mysql然后用命令 mysql –u root –p 进入mysql管理界面(密码可为空)

8、进入界面后更改 root密码

update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';

9、刷新权限

flush privileges;

10、修改 my.ini文件删除最后一句 skip-grant-tables

11、重启mysql即可正常使用

net stop mysql
net start mysql

进入方法

12、连接上测试出现以下结果就安装好了

一步步去做 , 理论上是没有任何问题的 .

如果您以前装过,现在需要重装,一定要将环境清理干净 .

好了,到这里大家都装好了,因为刚接触,所以我们先不学习命令.

这里给大家推荐一个工具 : SQLyog .

即便有了可视化工具,可是基本的DOS命名大家还是要记住!

1.7 安装SQLyog

可手动操作,管理MySQL数据库的软件工具

特点 : 简洁 , 易用 , 图形化

使用SQLyog管理工具自己完成以下操作 :

  • 连接本地MySQL数据库
  • 新建MySchool数据库
    • 字段
    • GradeID : int(11) , Primary Key (pk)
    • GradeName : varchar(50)
    • 数据库名称MySchool
    • 新建数据库表(grade)

在历史记录中可以看到相对应的数据库操作的语句

; 我的操作

  1. 新建一个数据库 school

  1. 新建一张表

刷新保存

1.8 连接数据库

命令行连接

mysql -uroot -p123456

update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost';

flush privileges;

show databases;

use school
Database changed

show tables;
describe student;

create database westos;

exit;

打开MySQL命令窗口

  • 在DOS命令行窗口进入 安装目录\mysql\bin
  • 可设置环境变量,设置了环境变量,可以在任意目录打开!

连接数据库语句 : mysql -h 服务器主机地址 -u 用户名 -p 用户密码

注意 : -p后面不能加空格,否则会被当做密码的内容,导致登录失败 !

几个基本的数据库操作命令 :

update user set password=password('123456')where user='root';
flush privileges;
show databases; 显示所有数据库
use dbname;
show tables;
describe user;
create database name;
use databasename; 选择数据库

exit;
? 命令关键词 : 寻求帮助

二、 操作数据库

我的操作

操作数据库 > 操作数据库中的表 > 操作数据库表中的数据

mysql关键字不分区大小写

2.1 结构化查询语句分类

; 2.2 数据库操作

2.2.1 命令行操作数据库

  1. 创建数据库 :
create database [if not exists] westos
  1. 删除数据库 :
drop database [if exists] 数据库名;3.

  1. 使用数据库

USE `school`
  1. 查看数据库 :
show databases;
  1. 使用数据库 :
use 数据库名;
  1. 对比工具操作数据库

学习方法:

  • 对照SQLyog工具自动生成的语句学习
  • 固定语法中的单词需要记忆

2.3 创建数据表

属于DDL的一种,语法 :

create table [if not exists] `表名`(
'字段名1' 列类型 [属性][索引][注释],
'字段名2' 列类型 [属性][索引][注释],
#...

'字段名n' 列类型 [属性][索引][注释]
)[表类型][表字符集][注释];

说明 : 反引号用于区别MySQL保留字与普通字符而引入的 (键盘esc下面的键).

2.4 数据值和列类型

列类型 : 规定数据库中该列存放的数据类型

1. 数值类型

; 2. 字符串类型

3. 日期和时间型数值类型

; 4. NULL值

  • 理解为 “没有值” 或 “未知值”
  • 不要用NULL进行算术运算 , 结果仍为NULL

2.5 数据字段属性(重点)

UnSigned

  • 无符号的
  • 声明该数据列不允许负数 .

ZEROFILL —— zerofill

  • 0填充的
  • 不足位数的用0来填充 , 如int(3),5则为005

Auto_InCrement —— 自增

  • 自动增长的 , 每添加一条数据 , 自动在上一个记录数上加 1(默认)
  • 通常用于设置 主键 , 且为整数类型
  • 可定义起始值和步长
    • 当前表设置步长(AUTO_INCREMENT=100) : 只影响当前表
    • SET @@auto_increment_increment=5 ; 影响所有使用自增的表(全局)

NULL 和 NOT NULL

  • 默认为NULL , 即没有插入该列的数值
  • 如果设置为NOT NULL , 则该列必须有值

DEFAULT——默认

  • 默认的
  • 用于设置默认值
  • 例如,性别字段,默认为”男” , 否则为 “女” ; 若无指定该列的值 , 则默认值为”男”的值

扩展


CREATE TABLE IF NOT EXISTS `student` (
`id` int(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` varchar(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` varchar(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` varchar(2) NOT NULL DEFAULT '男' COMMENT '性别',
`birthday` datetime DEFAULT NULL COMMENT '生日',
`address` varchar(100) DEFAULT NULL COMMENT '地址',
`email` varchar(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8

SHOW CREATE DATABASE school;

SHOW CREATE TABLE student;

DESC student;

2.6 创建数据库表


CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

格式

CREATE TABLE [IF NOT EXISTS] `表名`(
`字段名` 列类型 [属性] [索引] [注释],
`字段名` 列类型 [属性] [索引] [注释],
······
`字段名` 列类型 [属性] [索引] [注释],
)[表类型][字符集设置][注释]

常用命令

SHOW CREATE DATABASE school
SHOW CREATE TABLE student
DESC student

2.7 数据表的类型

1. 设置数据表的类型

CREATE TABLE 表名(

)ENGINE = MyISAM (or InnoDB)

SHOW ENGINES;

MySQL的数据表的类型 : MyISAM , InnoDB , HEAP , BOB , CSV等…

常见的 MyISAM InnoDB类型:

经验 ( 适用场合 ) :

  • 适用 MyISAM : 节约空间及相应速度
  • 适用 InnoDB : 安全性高 , 事务处理及多用户操作数据表,多表多用户操作

2. 数据表的存储位置

所有的数据库文件都存在 data目录下
本质还是文件的存储!

MySQL 引擎在物理文件上的区别

  • 一个文件夹对应一个数据库

MySQL数据表以文件方式存放在磁盘中

  • 包括表文件 , 数据文件 , 以及数据库的选项文件
  • 位置 : Mysql安装目录 \data\下存放数据表 . 目录名对应数据库名 , 该目录下文件名对应数据表 . 注意 :
  • *. frm – 表结构定义文件
  • * . MYD – 数据文件 ( data )
  • *. MYI – 索引文件 ( index )
  • InnoDB类型在数据库表中只有一个 *.frm文件 , 以及上一级目录的 ibdata1文件
  • MyISAM类型数据表对应三个文件 :

; 3. 设置数据表字符集

mysql的默认字符编码的设置(my.ini设置字符编码) - 简书 (jianshu.com)

CHARSET=utf8

不设置的话,会是MySQL默认的字符集编码

MySQL的默认编码是Latin1,不支持中文

我们可为数据库,数据表,数据列设定不同的字符集,设定方法 :

  • 创建时通过命令来设置 , 如 : CREATE TABLE 表名()CHARSET = utf8;
  • 如无设定 , 则根据MySQL数据库配置文件 my.ini 中的参数设定 character-set-server=utf8

2.8 修改删除表


ALTER TABLE teacher RENAME AS teacher1

ALTER TABLE teacher1 ADD age INT(11)

ALTER TABLE teacher1 MODIFY age VARCHAR(11)
ALTER TABLE teacher1 CHANGE age1 INT(1)

ALTER TABLE teacher1 DROP age1

DROP TABLE IF EXISTS teacher1

所有的创建和删除操作尽量加上判断,以免报错

注意点:

  • `` 字段名 使用这个包裹!
  • 注释 - - /**/
  • sql 关键字大小写不敏感,建议大家写小写
  • 所有的符号全部用英文!

三、MySQL数据管理

3.1 外键(了解即可)

1. 外键概念

如果公共关键字在一个关系中是主关键字,那么这个公共关键字被称为另一个关系的外键。由此可见,外键表示了两个关系之间的相关联系。以另一个关系的外键作主关键字的表被称为 主表,具有此外键的表被称为主表的 从表

在实际操作中,将一个表的值放入第二个表来表示关联,所使用的值是第一个表的主键值(在必要时可包括复合主键值)。此时,第二个表中保存这些值的属性称为外键(foreign key)。

外键作用

保持数据 一致性完整性,主要目的是控制存储在外键表中的数据, 约束。使两张表形成关联,外键只能引用外表中的列的值或使用空值。

2. 创建外键

建表时指定外键约束


CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '',
`gradename` VARCHAR(50) NOT NULL COMMENT '',
PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '学生的年年级',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`),
KEY `FK_gradeid` (`gradeid`),
CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade`(`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

建表后修改


CREATE TABLE `grade`(
`gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '',
`gradename` VARCHAR(50) NOT NULL COMMENT '',
PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

CREATE TABLE IF NOT EXISTS `student`(
`id` INT(4) NOT NULL AUTO_INCREMENT COMMENT '学号',
`name` VARCHAR(30) NOT NULL DEFAULT '匿名' COMMENT '姓名',
`pwd` VARCHAR(20) NOT NULL DEFAULT '123456' COMMENT '密码',
`sex` VARCHAR(2) NOT NULL DEFAULT '女' COMMENT '性别',
`birthday` DATETIME DEFAULT NULL COMMENT '出生日期',
`gradeid` INT(10) NOT NULL COMMENT '学生的年年级',
`address` VARCHAR(100) DEFAULT NULL COMMENT '家庭住址',
`email` VARCHAR(50) DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY(`id`)
)ENGINE=INNODB DEFAULT CHARSET=utf8

ALTER TABLE `student`
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeid`) REFERENCES `grade` (`gradeid`);

以上的操作理外键,数据库级外键,我们不建议使用! (避免数据库过多造成困扰,这里了解即可)

最佳实践

  • 数据库就是单纯的表,只用来存数据,只有行(数据)和列(字段)
  • 我们想使用多张表的娄收据,想使用外键(程序去实现)-.

3. 删除外键

操作:删除 grade 表,发现报错

注意 : 删除具有主外键关系的表时 , 要先删子表 , 后删主表


ALTER TABLE student DROP FOREIGN KEY FK_gradeid;

ALTER TABLE student DROP INDEX FK_gradeid;

3.2 DML语言(全部记住)

数据库意义 : 数据存储、数据管理

管理数据库数据方法:

  • 通过SQLyog等管理工具管理数据库数据
  • 通过 DML语句管理数据库数据

DML语言 :数据操作语言

  • 用于操作数据库对象中所包含的数据
  • 包括 :
    • INSERT (添加数据语句)
    • UPDATE (更新数据语句)
    • DELETE (删除数据语句)

3.3 添加数据 insert

INSERT命令


INSERT INTO `grade`(`gradename`) VALUES('大四')

INSERT INTO `grade` VALUES(`大三`)
INSERT INTO `grade` VALUES(`大四`)

INSERT INTO `grade`(`gradename`) VALUES('大二'),('大一')

INSERT INTO `student`(`name`) VALUES('张三')

INSERT INTO `student`(`name`,`pwd`,`sex`)
VALUES('张三','aaaa','男')

INSERT INTO `student`(`name`,`pwd`,`sex`)
VALUES('李四','aaaaa','男'),('王五','bbbbbb','女')

语法:

INSERT INTO 表名[(字段1,字段2,字段3,...)] VALUES('值1','值2','值3')

注意 :

  • 字段或值之间用英文逗号隔开 .
  • ‘ 字段1,字段2…’ 该部分可省略 , 但添加的值务必与表结构,数据列,顺序相对应,且数量一致 .
  • 可同时插入多条数据 , values 后用英文逗号隔开 .

INSERT INTO grade(gradename) VALUES ('大一');

INSERT INTO grade VALUES ('大二');

Column count doesn`t match value count at row 1

INSERT INTO grade(gradename) VALUES ('大三'),('大四');

练习题目

自己使用INSERT语句为课程表subject添加数据 . 使用到外键.

3.4 修改数据

1. update命令


UPDATE `student` SET `name`='sk' WHERE id = 1;

UPDATE `student` SET `name`='长江7号'

UPDATE `student` SET `name`='sk',`email`='[email protected]' WHERE id = 2;

UPDATE `student` SET `name`='长江7号' WHERE `name`='sk' AND sex='男'

UPDATE `student` SET `birthday`=CURRENT_TIME WHERE `name`='sk' AND sex='女'

语法:

UPDATE 表名 SET column_name=value [,column_name2=value2,...] [WHERE condition];

注意 :

  • column_name 为要更改的数据列,尽量带 ``
  • value 为修改后的数据 , 可以为变量 , 具体指 , 表达式或者嵌套的SELECT结果
  • condition 为筛选条件 , 如不指定则修改该表的所有列数据
  • 多个设置的属性之间,使用英文逗号隔开

1. where条件子句

可以简单的理解为 : 有条件地从表中筛选数据,where子句运算符 id 等于某个值,大于某个值,在某个区间内修改

测试:


UPDATE grade SET gradename = '高中' WHERE gradeid = 1;

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-A6XQHiQF-1639569373642)(F:\Typora\数据库\图片\image-20211211215033552.png)]

3.5 删除数据

1. delete命令

语法:

DELETE FROM 表名 [WHERE condition];

DELETE FROM `student` WHERE id = 1;

注意: condition为筛选条件 , 如不指定则删除该表的所有列数据


DELETE FROM grade WHERE gradeid = 5

2. truncate命令

作用:用于完全清空表数据 , 但表结构 , 索引 , 约束等不变 ;

语法:

TRUNCATE [TABLE] table_name;

TRUNCATE grade

注意:truncate 区别于 delete 命令

  • 相同 : 都能删除数据 , 不删除表结构 , 但TRUNCATE速度更快
  • 不同 :
    • 使用TRUNCATE TABLE 重新设置AUTO_INCREMENT计数器
    • 使用TRUNCATE TABLE不会对事务有影响 (事务后面会说)
DELETE FROM `test`

TRUNCATE FROM `test`

了解即可: DELETE删除的问题,重启数据库,现象

  • InnoDB 自增列会重1开始(存在内存当中的,断电即失)
  • MyISAM 继续从上一个自增量开始(存在文件中的,不会丢失)

测试:


CREATE TABLE `test` (
`id` INT(4) NOT NULL AUTO_INCREMENT,
`coll` VARCHAR(20) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO test(coll) VALUES('row1'),('row2'),('row3');

DELETE FROM test;

TRUNCATE TABLE test;

四、 DQL查询数据(最重点)

4.1 DQL语言

1. DQL( Data Query Language 数据查询语言 )

  • 查询数据库数据 , 如 SELECT语句
  • 简单的单表查询或多表的复杂查询和嵌套查询
  • 是数据库语言中最核心,最重要的语句
  • 使用频率最高的语句

在数据库中创建这个表

CREATE DATABASE IF NOT EXISTS `school`;

USE `school`;
DROP TABLE IF EXISTS `student`;
CREATE TABLE `student`(
`studentno` INT(4) NOT NULL COMMENT '学号',
`loginpwd` VARCHAR(20) DEFAULT NULL,
`studentname` VARCHAR(20) DEFAULT NULL COMMENT '学生姓名',
`sex` TINYINT(1) DEFAULT NULL COMMENT '性别,0或1',
`gradeid` INT(11) DEFAULT NULL COMMENT '年级编号',
`phone` VARCHAR(50) NOT NULL COMMENT '联系电话,允许为空',
`address` VARCHAR(255) NOT NULL COMMENT '地址,允许为空',
`borndate` DATETIME DEFAULT NULL COMMENT '出生时间',
`email` VARCHAR (50) NOT NULL COMMENT '邮箱账号允许为空',
`identitycard` VARCHAR(18) DEFAULT NULL COMMENT '身份证号',
PRIMARY KEY (`studentno`),
UNIQUE KEY `identitycard`(`identitycard`),
KEY `email` (`email`)
)ENGINE=MYISAM DEFAULT CHARSET=utf8;

DROP TABLE IF EXISTS `grade`;
CREATE TABLE `grade`(
`gradeid` INT(11) NOT NULL AUTO_INCREMENT COMMENT '年级编号',
`gradename` VARCHAR(50) NOT NULL COMMENT '年级名称',
PRIMARY KEY (`gradeid`)
) ENGINE=INNODB AUTO_INCREMENT = 6 DEFAULT CHARSET = utf8;

DROP TABLE IF EXISTS `subject`;
CREATE TABLE `subject`(
`subjectno`INT(11) NOT NULL AUTO_INCREMENT COMMENT '课程编号',
`subjectname` VARCHAR(50) DEFAULT NULL COMMENT '课程名称',
`classhour` INT(4) DEFAULT NULL COMMENT '学时',
`gradeid` INT(4) DEFAULT NULL COMMENT '年级编号',
PRIMARY KEY (`subjectno`)
)ENGINE = INNODB AUTO_INCREMENT = 19 DEFAULT CHARSET = utf8;

DROP TABLE IF EXISTS `result`;
CREATE TABLE `result`(
`studentno` INT(4) NOT NULL COMMENT '学号',
`subjectno` INT(4) NOT NULL COMMENT '课程编号',
`examdate` DATETIME NOT NULL COMMENT '考试日期',
`studentresult` INT (4) NOT NULL COMMENT '考试成绩',
KEY `subjectno` (`subjectno`)
)ENGINE = INNODB DEFAULT CHARSET = utf8;

INSERT INTO `student` (`studentno`,`loginpwd`,`studentname`,`sex`,`gradeid`,`phone`,`address`,`borndate`,`email`,`identitycard`)
VALUES
(1000,'123456','张伟',0,2,'13800001234','北京朝阳','1980-1-1','[email protected]','123456198001011234'),
(1001,'123456','赵强',1,3,'13800002222','广东深圳','1990-1-1','[email protected]','123456199001011233');

INSERT INTO `result`(`studentno`,`subjectno`,`examdate`,`studentresult`)
VALUES
(1000,1,'2013-11-11 16:00:00',85),
(1000,2,'2013-11-12 16:00:00',70),
(1000,3,'2013-11-11 09:00:00',68),
(1000,4,'2013-11-13 16:00:00',98),
(1000,5,'2013-11-14 16:00:00',58);

INSERT INTO `grade` (`gradeid`,`gradename`) VALUES(1,'大一'),(2,'大二'),(3,'大三'),(4,'大四'),(5,'预科班');

INSERT INTO `subject`(`subjectno`,`subjectname`,`classhour`,`gradeid`)VALUES
(1,'高等数学-1',110,1),
(2,'高等数学-2',110,2),
(3,'高等数学-3',100,3),
(4,'高等数学-4',130,4),
(5,'C语言-1',110,1),
(6,'C语言-2',110,2),
(7,'C语言-3',100,3),
(8,'C语言-4',130,4),
(9,'Java程序设计-1',110,1),
(10,'Java程序设计-2',110,2),
(11,'Java程序设计-3',100,3),
(12,'Java程序设计-4',130,4),
(13,'数据库结构-1',110,1),
(14,'数据库结构-2',110,2),
(15,'数据库结构-3',100,3),
(16,'数据库结构-4',130,4),
(17,'C#基础',130,1);

2. SELECT语法

SELECT [ALL | DISTINCT]
{* | table.* | [table.field1[as alias1][,table.field2[as alias2]][,...]]}
FROM table_name [as table_alias]
[left | right | inner join table_name2]
[WHERE ...]
[GROUP BY ...]
[HAVING]
[ORDER BY ...]
[LIMIT {[offset,]row_count | row_countOFFSET offset}];

注意 : [ ] 括号代表可选的 , { }括号代表必选得

4.2 指定查询字段


SELECT * FROM student;

SELECT `studentno`,`studentname` FROM student;

1. AS 子句作为别名

作用:

  • 可给数据列取一个新别名
  • 可给表取一个新别名
  • 可把经计算或总结的结果用另一个新名称来代替

SELECT `studentno` AS 学号,`studentname` AS 姓名 FROM student;

SELECT `studentno` AS 学号,` studentname` AS 姓名 FROM student AS s;

SELECT CONCAT('姓名:',studentname) AS 新姓名 FROM student;

2. distinct 关键字的使用

distinct 去重

作用 : 去掉 select 查询返回的记录结果中重复的记录 ( 返回所有列的值都相同 ) , 只返回一条


SELECT * FROM result;
SELECT `studentno` FROM result;
SELECT DISTINCT `studentno` FROM result;

3. 使用表达式的列


SELECT @@auto_increment_increment;
SELECT VERSION();
SELECT 100*3-1 AS 计算结果;

SELECT `studentno`, `StudentResult`+1 AS '提分后' FROM result;

数据库中的表达式 : 一般由文本值 , 列值 , NULL , 函数和操作符等组成

应用场景 :

  • select 语句返回结果列中使用
  • select 语句中的ORDER BY , HAVING等子句中使用
  • DML语句中的 where 条件语句中使用表达式
  • 避免SQL返回结果中包含 ‘ . ‘ , ‘ * ‘ 和括号等干扰开发语言程序.

4.3 where条件语句

作用:用于检索数据表中 符合条件 的记录

搜索条件可由一个或多个逻辑表达式组成 , 结果一般为真或假.

1. 逻辑操作符

尽量用英文字母

测试


SELECT Studentno,StudentResult FROM result;

SELECT Studentno,StudentResult FROM result
WHERE StudentResult>=95 AND StudentResult100;

SELECT Studentno,StudentResult FROM result
WHERE StudentResult>=95 && StudentResult100;

SELECT Studentno,StudentResult FROM result
WHERE StudentResult BETWEEN 95 AND 100;

SELECT studentno,studentresult FROM result
WHERE studentno!=1000;

SELECT studentno,studentresult FROM result
WHERE NOT studentno=1000;

2. 模糊查询 :比较操作符

注意:

  • 数值数据类型的记录之间才能进行算术运算 ;
  • 相同数据类型的数据之间才能进行比较 ;

测试:


SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘%';

SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘_';

SELECT studentno,studentname FROM student
WHERE studentname LIKE '刘__';

SELECT studentno,studentname FROM student
WHERE studentname LIKE '%嘉%';

SELECT studentno,studentname FROM student
WHERE studentno IN (1000,1001,1002);

SELECT studentno,studentname,address FROM student
WHERE address IN ('北京','南京','河南洛阳');

SELECT studentname FROM student
WHERE BornDate IS NULL;

SELECT studentname FROM student
WHERE BornDate IS NOT NULL;

SELECT studentname FROM student
WHERE Address='' OR Address IS NULL;

4.4 连接查询(联表)

1. Join 对比

七种Join:

测试


SELECT * FROM student;
SELECT * FROM result;

SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno

SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
RIGHT JOIN result r
ON r.studentno = s.studentno

SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s , result r
WHERE r.studentno = s.studentno

SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
LEFT JOIN result r
ON r.studentno = s.studentno

SELECT s.studentno,studentname,subjectno,StudentResult
FROM student s
LEFT JOIN result r
ON r.studentno = s.studentno
WHERE StudentResult IS NULL

SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON sub.subjectno = r.subjectno

2. 自连接(了解)


CREATE TABLE `category` (
`categoryid` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT '主题id',
`pid` INT(10) NOT NULL COMMENT '父id',
`categoryName` VARCHAR(50) NOT NULL COMMENT '主题名字',
PRIMARY KEY (`categoryid`)
) ENGINE=INNODB AUTO_INCREMENT=9 DEFAULT CHARSET=utf8

INSERT INTO `category` (`categoryid`, `pid`, `categoryName`)
VALUES('2','1','信息技术'),
('3','1','软件开发'),
('4','3','数据库'),
('5','1','美术设计'),
('6','3','web开发'),
('7','5','ps技术'),
('8','2','办公信息');

SELECT a.categoryName AS '父栏目',b.categoryName AS '子栏目'
FROM category AS a,category AS b
WHERE a.`categoryid`=b.`pid`

SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON sub.subjectno = r.subjectno

SELECT studentno AS 学号,studentname AS 学生姓名,gradename AS 年级名称
FROM student s
INNER JOIN grade g
ON s.`GradeId` = g.`GradeID`

SELECT subjectname AS 科目名称,gradename AS 年级名称
FROM SUBJECT sub
INNER JOIN grade g
ON sub.gradeid = g.gradeid

SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'

4.5 排序和分页(经常用 )

测试


SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY StudentResult DESC

SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='数据库结构-1'
ORDER BY StudentResult DESC , studentno
LIMIT 0,5

SELECT s.studentno,studentname,subjectname,StudentResult
FROM student s
INNER JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno
WHERE subjectname='JAVA第一学年'
ORDER BY StudentResult DESC
LIMIT 0,10

4.6 子查询


SELECT studentno,r.subjectno,StudentResult
FROM result r
INNER JOIN `subject` sub
ON r.`SubjectNo`=sub.`SubjectNo`
WHERE subjectname = '数据库结构-1'
ORDER BY studentresult DESC;

SELECT studentno,subjectno,StudentResult FROM result
WHERE subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '数据库结构-1'
)
ORDER BY studentresult DESC;

SELECT s.studentno,studentname FROM student s
INNER JOIN result r
ON s.`StudentNo` = r.`StudentNo`
INNER JOIN `subject` sub
ON sub.`SubjectNo` = r.`SubjectNo`
WHERE subjectname = '高等数学-2' AND StudentResult>=80

SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80

SELECT r.studentno,studentname FROM student s
INNER JOIN result r ON s.`StudentNo`=r.`StudentNo`
WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject`
WHERE subjectname = '高等数学-2'
)

SELECT studentno,studentname FROM student WHERE studentno IN(
SELECT studentno FROM result WHERE StudentResult>=80 AND subjectno=(
SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2'
)
)

五、MySQL函数

官网手册:MySQL :: MySQL 8.0 Reference Manual

5.1 常用函数

数据函数


SELECT ABS(-8);
SELECT CEILING(9.4);
SELECT FLOOR(9.4);
SELECT RAND();
SELECT SIGN(0);

字符串函数

SELECT CHAR_LENGTH('狂神说坚持就能成功');
SELECT CONCAT('我','爱','程序');
SELECT INSERT('我爱编程helloworld',1,2,'超级热爱');
SELECT LOWER('KuangShen');
SELECT UPPER('KuangShen');
SELECT LEFT('hello,world',5);
SELECT RIGHT('hello,world',5);
SELECT REPLACE('狂神说坚持就能成功','坚持','努力');
SELECT SUBSTR('狂神说坚持就能成功',4,6);
SELECT INSTR('kuanghshen,h');
SELECT REVERSE('狂神说坚持就能成功');

SELECT REPLACE(studentname,'周','邹') AS 新名字
FROM student WHERE studentname LIKE '周%';

日期和时间函数(记住)

SELECT CURRENT_DATE();
SELECT CURDATE();
SELECT NOW();
SELECT LOCALTIME();
SELECT SYSDATE();

SELECT YEAR(NOW());
SELECT MONTH(NOW());
SELECT DAY(NOW());
SELECT HOUR(NOW());
SELECT MINUTE(NOW());
SELECT SECOND(NOW());

系统信息函数

SELECT VERSION();
SELECT USER();

5.2 聚合函数

函数名称描述
COUNT()

返回满足Select条件的记录总和数,如 select count(*) 【不建议使用 *,效率低】SUM()返回数字字段或表达式列作统计,返回一列的总和。AVG()通常为数值字段或表达列作统计,返回一列的平均值MAX()可以为数值字段,字符字段或表达式列作统计,返回最大的值。MIN()可以为数值字段,字符字段或表达式列作统计,返回最小的值。


SELECT COUNT(studentname) FROM student;
SELECT COUNT(*) FROM student;
SELECT COUNT(1) FROM student;

SELECT SUM(StudentResult) AS 总和 FROM result;
SELECT AVG(StudentResult) AS 平均分 FROM result;
SELECT MAX(StudentResult) AS 最高分 FROM result;
SELECT MIN(StudentResult) AS 最低分 FROM result;

题目:(分组和过滤)


SELECT subjectname,AVG(studentresult) AS 平均分,MAX(StudentResult) AS 最高分,MIN(StudentResult) AS 最低分
FROM result AS r
INNER JOIN `subject` AS s
ON r.subjectno = s.subjectno
GROUP BY r.subjectno
HAVING 平均分>80;

5.3 数据库级别得MD5加密(扩展)

1. MD5简介

MD5即Message-Digest Algorithm 5(信息-摘要算法5),用于确保信息传输完整一致。是计算机广泛使用的杂凑算法之一(又译摘要算法、哈希算法),主流编程语言普遍已有MD5实现。将数据(如汉字)运算为另一固定长度值,是杂凑算法的基础原理,MD5的前身有MD2、MD3和MD4。

  • 主要增强算法复杂度和不可逆性。
  • MD5不可逆,具体的值的md5是一样的
  • MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密的前值

2. 实现数据加密

新建一个表 testmd5


CREATE TABLE `testmd5` (
`id` INT(4) NOT NULL,
`name` VARCHAR(20) NOT NULL,
`pwd` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

明文密码


INSERT INTO testmd5 VALUES(1,'kuangshen','123456'),(2,'qinjiang','456789')

如果我们要对pwd这一列数据进行 加密,语法是:

UPDATE testmd5 SET pwd = MD5(pwd);

如果单独对某个用户(如kuangshen)的密码加密:

INSERT INTO testmd5 VALUES(3,'kuangshen2','123456')
update testmd5 set pwd = md5(pwd) where name = 'kuangshen2';

插入新的数据 自动加密

INSERT INTO testmd5 VALUES(4,'kuangshen3',md5('123456'));

查询登录用户信息(md5对比使用,查看用户输入加密后的密码进行 比对

SELECT * FROM testmd5 WHERE `name`='kuangshen' AND pwd=MD5('123456');

小结


abs(x)
format(x, d)
ceil(x)
floor(x)
round(x)
mod(m, n)
pi()
pow(m, n)
sqrt(x)
rand()
truncate(x, d)

now(), current_timestamp();
current_date();
current_time();
date('yyyy-mm-dd hh:ii:ss');
time('yyyy-mm-dd hh:ii:ss');
date_format('yyyy-mm-dd hh:ii:ss', '%d %y %a %d %m %b %j');
unix_timestamp();
from_unixtime();

length(string)
char_length(string)
substring(str, position [,length])
replace(str ,search_str ,replace_str)
instr(string ,substring)
concat(string [,...])
charset(str)
lcase(string)
left(string, length)
load_file(file_name)
locate(substring, string [,start_position])
lpad(string, length, pad)
ltrim(string)
repeat(string, count)
rpad(string, length, pad)
rtrim(string)
strcmp(string1 ,string2)

count()
sum();
max();
min();
avg();
group_concat()

md5();
default();

六、事务

6.1 什么是事务

  • 事务就是将一组SQL语句放在同一批次内去执行
  • 如果一个SQL语句出错,则该批次内的所有SQL都将被取消执行
  • MySQL事务处理只支持 InnoDBBDB数据表类型

6.2 事务——ACID原则(百度 ACID)

博客链接:事务ACID理解_dengjili的专栏-CSDN博客_acid

原子性(Atomic)

  • 整个事务中的所有操作,要么全部完成,要么全部不完成,不可能停滞在中间某个环节。事务在执行过程中发生错误,会被回滚(ROLLBACK)到事务开始前的状态,就像这个事务从来没有执行过一样。

一致性(Consistency)

  • 一个事务可以封装状态改变(除非它是一个只读的)。事务必须始终保持系统处于一致的状态,不管在任何给定的时间并发事务有多少。也就是说:如果事务是并发多个,系统也必须如同串行事务一样操作。其主要特征是保护性和不变性(Preserving an Invariant),以转账案例为例,假设有五个账户,每个账户余额是100元,那么五个账户总额是500元,如果在这个5个账户之间同时发生多个转账,无论并发多少个,比如在A与B账户之间转账5元,在C与D账户之间转账10元,在B与E之间转账15元,五个账户总额也应该还是500元,这就是保护性和不变性。

隔离性(Isolated)

  • 隔离状态执行事务,使它们好像是系统在给定时间内执行的唯一操作。如果有两个事务,运行在相同的时间内,执行相同的功能,事务的隔离性将确保每一事务在系统中认为只有该事务在使用系统。这种属性有时称为串行化,为了防止事务操作间的混淆,必须串行化或序列化请求,使得在同一时间仅有一个请求用于同一数据。

持久性(Durability)

  • 在事务完成以后,该事务对数据库所作的更改便持久的保存在数据库之中,并不会被回滚。

6.3 隔离所产生的问题:

1. 脏读:

2. 不可重复读

在一个事务内读取表中的某一行数据,多次读取结果不同。(这个不一定是错误,只是某些场合不对)

页面统计查询值:

A100B200C500

点击生成报表的时候,B有人转账进来300(事务已经提交)

A100B500C500

3. 虚读(幻读)

是指在一个事务内读取到了别的事务插入的数据,导致前后读取不—致。(一般是行影响,多了一行)

A100B500C500 A100B500C500D500

6.3 基本语法


SET autocommit = 0;
SET autocommit = 1;

SET autocommit =0

START TRANSACTION

COMMIT

ROLLBACK

SET autocommit =1;

SAVEPOINT 保存点名称
ROLLBACK TO SAVEPOINT 保存点名称
RELEASE SAVEPOINT 保存点名称

测试——转账


CREATE DATABASE `shop`CHARACTER SET utf8 COLLATE utf8_general_ci;
USE `shop`;

CREATE TABLE `account` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`name` VARCHAR(32) NOT NULL,
`cash` DECIMAL(9,2) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=utf8

INSERT INTO account (`name`,`cash`)
VALUES('A',2000.00),('B',10000.00)

SET autocommit = 0;
START TRANSACTION;
UPDATE account SET cash=cash-500 WHERE `name`='A';
UPDATE account SET cash=cash+500 WHERE `name`='B';
COMMIT;

SET autocommit = 1;

七、索引

MySQL官方对索引的定义为: 索引(Index)是帮助MySQL高效获取数据的数据结构
提取句子主干,可以得到索引的本质:索引是数据结构。

7.1 索引的作用

  • 提高查询速度
  • 确保数据的唯一性
  • 可以加速表和表之间的连接 , 实现表与表之间的参照完整性
  • 使用分组和排序子句进行数据检索时 , 可以显著减少分组和排序的时间
  • 全文检索字段进行搜索优化.

7.2 分类

  • 主键索引 (Primary Key)
    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引 (Unique Key)
    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识位唯一索引
  • 常规索引 (Index)
    • 默认的, index。key关键字来设置
  • 全文索引 (FullText)
    • 在特定的数据库引擎下才有, MyISAM
    • 快速定位数据

1. 主键索引

主键 : 某一个属性组能唯一标识一条记录

特点 :

  • 最常见的索引类型
  • 确保数据记录的唯一性
  • 确定特定数据记录在数据库中的位置

2. 唯一索引

作用 : 避免同一个表中某数据列中的值重复

与主键索引的区别

  • 主键索引只能有一个
  • 唯一索引可能有多个
CREATE TABLE `Grade`(
`GradeID` INT(11) AUTO_INCREMENT PRIMARYKEY,
`GradeName` VARCHAR(32) NOT NULL UNIQUE

)

3. 常规索引

作用 : 快速定位特定数据

注意 :

  • index 和 key 关键字都可以设置常规索引
  • 应加在查询找条件的字段
  • 不宜添加太多常规索引,影响数据的插入,删除和修改操作
CREATE TABLE `result`(

INDEX/KEY `ind` (`studentNo`,`subjectNo`)
)

ALTER TABLE `result` ADD INDEX `ind`(`studentNo`,`subjectNo`);

4. 全文索引

百度搜索:全文索引

作用 : 快速定位特定数据

注意 :

  • 只能用于MyISAM类型的数据表
  • 只能用于CHAR , VARCHAR , TEXT数据列类型
  • 适合大型数据集

ALTER TABLE `school`.`student` ADD FULLTEXT INDEX `studentname` (`StudentName`);

EXPLAIN SELECT * FROM student WHERE studentno='1000';

EXPLAIN SELECT *FROM student WHERE MATCH(studentname) AGAINST('love');

7.3 拓展:测试索引

建表app_user:

CREATE TABLE `app_user` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(50) DEFAULT '' COMMENT '用户昵称',
`email` varchar(50) NOT NULL COMMENT '用户邮箱',
`phone` varchar(20) DEFAULT '' COMMENT '手机号',
`gender` tinyint(4) unsigned DEFAULT '0' COMMENT '性别(0:男;1:女)',
`password` varchar(100) NOT NULL COMMENT '密码',
`age` tinyint(4) DEFAULT '0' COMMENT '年龄',
`create_time` datetime DEFAULT CURRENT_TIMESTAMP,
`update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'

批量插入数据:100w

DROP FUNCTION IF EXISTS mock_data;
DELIMITER $$
CREATE FUNCTION mock_data()
RETURNS INT
BEGIN
DECLARE num INT DEFAULT 1000000;
DECLARE i INT DEFAULT 0;
WHILE i < num DO
INSERT INTO app_user(`name`, `email`, `phone`, `gender`, `password`, `age`)
VALUES(CONCAT('用户', i), '[email protected]', CONCAT('18', FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2),UUID(), FLOOR(RAND()*100));
SET i = i + 1;
END WHILE;
RETURN i;
END;
SELECT mock_data();

索引效率测试

无索引

SELECT * FROM app_user WHERE name = '用户9999';
SELECT * FROM app_user WHERE name = '用户9999';
SELECT * FROM app_user WHERE name = '用户9999';

mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用户9999'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: app_user
partitions: NULL
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 992759
filtered: 10.00
Extra: Using where
1 row in set, 1 warning (0.00 sec)

创建索引

CREATE INDEX idx_app_user_name ON app_user(name);

测试普通索引

mysql> EXPLAIN SELECT * FROM app_user WHERE name = '用户9999'\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: app_user
partitions: NULL
type: ref
possible_keys: idx_app_user_name
key: idx_app_user_name
key_len: 203
ref: const
rows: 1
filtered: 100.00
Extra: NULL
1 row in set, 1 warning (0.00 sec)

mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)

mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)

mysql> SELECT * FROM app_user WHERE name = '用户9999';
1 row in set (0.00 sec)

7.4 索引准则

  • 索引不是越多越好
  • 不要对经常变动的数据加索引
  • 小数据量的表建议不要加索引
  • 索引一般应加在查找条件的字段

7.5 索引的数据结构


hash类型的索引:查询单条快,范围查询慢
btree类型的索引:b+树,层数越多,数据量指数级增长(我们就用它,因为innodb默认支持它)

InnoDB 支持事务,支持行级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
MyISAM 不支持事务,支持表级别锁定,支持 B-tree、Full-text 等索引,不支持 Hash 索引;
Memory 不支持事务,支持表级别锁定,支持 B-tree、Hash 等索引,不支持 Full-text 索引;
NDB 支持事务,支持行级别锁定,支持 Hash 索引,不支持 B-tree、Full-text 等索引;
Archive 不支持事务,支持表级别锁定,不支持 B-tree、Hash、Full-text 等索引;

阅读:CodingLabs - MySQL索引背后的数据结构及算法原理

全文阅读

八、用户管理

8.1 创建新用户

1. 创建用户

使用SQLyog 创建用户,并授予权限演示

; 2. 基本命令


用户信息表:mysql.user

FLUSH PRIVILEGES

CREATE USER blue IDENTIFIED BY '123456'

RENAME USER blue TO blue2

SET PASSWORD = PASSWORD('密码')
SET PASSWORD FOR 用户名 = PASSWORD('密码')

DROP USER 用户名

GRANT 权限列表 ON 表名 TO 用户名 [IDENTIFIED BY [PASSWORD] 'password']
- all privileges 表示所有权限
- *.* 表示所有库的所有表
- 库名.表名 表示某库下面的某表

SHOW GRANTS FOR 用户名

SHOW GRANTS; 或 SHOW GRANTS FOR CURRENT_USER; 或 SHOW GRANTS FOR CURRENT_USER();

REVOKE 权限列表 ON 表名 FROM 用户名
REVOKE 权限列表 ON 表名 FROM 用户名

REVOKE ALL PRIVILEGES ON *.* FROM blue2
REVOKE ALL PRIVILEGES, GRANT OPTION FROM 用户名

3. 权限解释


ALL [PRIVILEGES]
ALTER
ALTER ROUTINE
CREATE
CREATE ROUTINE
CREATE TEMPORARY TABLES
CREATE USER
CREATE VIEW
DELETE
DROP
EXECUTE
FILE
INDEX
INSERT
LOCK TABLES
PROCESS
REFERENCES
RELOAD
REPLICATION CLIENT
REPLICATION SLAVE
SELECT
SHOW DATABASES
SHOW VIEW
SHUTDOWN
SUPER
UPDATE
USAGE
GRANT OPTION

ANALYZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE 表名 ...

CHECK TABLE tbl_name [, tbl_name] ... [option] ...

option = {QUICK | FAST | MEDIUM | EXTENDED | CHANGED}

OPTIMIZE [LOCAL | NO_WRITE_TO_BINLOG] TABLE tbl_name [, tbl_name] ...

8.2 MySQL备份

数据库备份必要性

  • 保证重要数据不丢失
  • 数据转移

MySQL数据库备份方法

  • mysqldump备份工具
  • 数据库管理工具,如SQLyog
  • 直接拷贝数据库文件和相关配置文件

mysqldump客户端

作用 :

  • 转储数据库
  • 搜集数据库进行备份
  • 将数据转移到另一个SQL服务器,不一定是MySQL服务器


1. 导出一张表
  mysqldump -u用户名 -p密码 库名 表名 > 文件名(D:/a.sql)

2. 导出多张表
  mysqldump -u用户名 -p密码 库名 表123 > 文件名(D:/a.sql)

3. 导出所有表
  mysqldump -u用户名 -p密码 库名 > 文件名(D:/a.sql)

4. 导出一个库
  mysqldump -u用户名 -p密码 -B 库名 > 文件名(D:/a.sql)

可以-w携带备份条件

1. 在登录mysql的情况下:
  source 备份文件
2. 在不登录的情况下
  mysql -u用户名 -p密码 库名 < 备份文件

九、规范化数据库设计

9.1 为什么需要数据库设计

当数据库比较复杂时我们需要设计数据库

糟糕的数据库设计 :

  • 数据冗余,存储空间浪费
  • 数据库插入和删除都会麻烦、异常,数据更新和插入的异常
  • 程序性能差

良好的数据库设计 :

  • 节省数据的存储空间
  • 能够保证数据的完整性
  • 方便进行数据库应用系统的开发

软件项目开发周期中数据库设计 :

  • 需求分析阶段:分析客户的业务和数据处理需求
  • 概要设计阶段:设计数据库的E-R模型图 , 确认需求信息的正确和完整.

设计数据库步骤

  • 收集信息,分析需求

    • 与该系统有关人员进行交流 , 座谈 , 充分了解用户需求 , 理解数据库需要完成的任务.
  • 标识实体[Entity]

    • 标识数据库要管理的关键对象或实体,实体一般是名词
  • 标识每个实体需要存储的详细信息[Attribute]

  • 标识实体之间的关系[Relationship]

设计数据库步骤:(个人博客)

  • 收集信息,分析需求
    • 用户表(用户登录注销,用户个人信息,写博客,创建分类)
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 评论表
    • 友链表(友链信息)

  • 自定义表(系统信息,某个关键的字,或者一些主字段)key: value
  • 标识实体(把需求落地到每个字段)

; 9.2 三大范式

问题 : 为什么需要数据规范化?

不合规范的表设计会导致的问题:

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正确表示信息
  • 删除异常
    • 丢失有效信息

1. 三大范式

第一范式 (1st NF)

第一范式的目标是确保每列的原子性,如果每列都是不可再分的最小数据单元,则满足第一范式

第二范式(2nd NF)

第二范式(2NF)是在第一范式(1NF)的基础上建立起来的,即满足第二范式(2NF)必须先满足第一范式(1NF)。

第二范式要求每个表只描述一件事情

第三范式(3rd NF)

如果一个关系满足第二范式,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式.

第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。

规范化和性能的关系(规范数据库的设计)

关联查询的表不得超过三张表

  • 为满足某种商业目标 , 数据库性能比规范化数据库更重要
  • 在数据规范化的同时 , 要综合考虑数据库的性能
  • 通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间
  • 通过在给定的表中插入计算列,以方便查询

10、JDBC

10.1 数据库驱动(重点)

驱动:声卡,显卡、数据库

我们的程序会通过数据库驱动,和数据库打交道

; 10.2 JDBC

SUN公司为了简化开发人员的(对数据库的统一)操作,提供了一个〔ava操作数据库的)规范,俗称JDBC,这些规范的实现由具体的厂商去做

对于开发人员来说, 我们只需要掌握 JDBC 接口的操作即可!

Java.sq
Javax.sq
还需要导入一个数据库驱动包

10.3 第一个JDBC程序

创建测试数据库

CREATE DATABASE `jdbcStudy` CHARACTER SET utf8 COLLATE utf8_general_ci;

USE `jdbcStudy`;

CREATE TABLE `users`(
`id` INT PRIMARY KEY,
`NAME` VARCHAR(40),
`PASSWORD` VARCHAR(40),
`email` VARCHAR(60),
birthday DATE
);

INSERT INTO `users`(`id`,`NAME`,`PASSWORD`,`email`,`birthday`)
VALUES('1','zhangsan','123456','[email protected]','1980-12-04'),
('2','lisi','123456','[email protected]','1981-12-04'),
('3','wangwu','123456','[email protected]','1979-12-04')

1、创建一个普通项目

2、导入数据库驱动

点击 Add as library

3、编写测试代码

String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

jdbc:mysql://localhost:3306/jdbcstudy?支持中文编码 &设置中文字符集 &使用安全连接

步骤总结:

  1. 加载驱动
  2. 连接数据库 DriverManager
  3. 获得执行SQL的对象 Statement
  4. 获得返回的结果集 ResultSet
  5. 释放连接

DriverManager


Class.forName("com.mysql.jdbc.Driver");

Connection connection = DriverManager.getConnection(url, username, password);

connection.rollback();
connection.commit();
connection.setAutocommito();

URL

String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";

Statement 执行SQL的对象 PrepareStatement 执行SQL的对象

 String sql = "SELECT * FROM users";

statement.executeQuery();
statement.execute();
statement.executeUpdate();

ResultSet 查询的结果集:封装了所有的查询结果

获得指定的数据类型

resultset. getobjectO;

resultset.getString();
resultse. getInt();
resultset.getFloat();
resultset.getDate();
resultset.getObject();
......

遍历,指针

resultset.beforefirst();
resultset.aftertaste();
resultset.next();
resultset.previous();
resultset.absolute(row);

释放资源


resultSet.close();
statement.close();
connection.close();

总代码:

package com.kuang.lesson01;

import java.sql.*;

public class JdbcFirstDemo {
public static void main(String[] args) throws ClassNotFoundException, SQLException {

Class.forName("com.mysql.jdbc.Driver");

String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
String username ="root";
String password = "123456";

Connection connection = DriverManager.getConnection(url, username, password);

Statement statement = connection.createStatement();

String sql = "SELECT * FROM users";

ResultSet resultSet = statement.executeQuery(sql);

while(resultSet.next()){
System.out.println("id=" + resultSet.getObject("id"));
System.out.println("name=" + resultSet.getObject("NAME"));
System.out.println("pwd=" + resultSet.getObject("PASSWORD"));
System.out.println("email=" + resultSet.getObject("email"));
System.out.println("birth=" + resultSet.getObject("birthday"));
System.out.println("==================================================");
}

resultSet.close();
statement.close();
connection.close();

}

}

10.4 statement 对象

Jdbc中的 statement对象用于向数据库发送sqL语句,想完成对数据库的增删改査,只需要通过这个对象向数据库发送増删改查语句即可

Statement对象的 executeUpdate方法,用于向数据库发送增、删、改的sql语句,executeUpdate执行完后,将会返回一个整数(即增删改语句导致了数据库几行数据发生了变化)

Statement.executeQuery方法用于向数据库发送查询语句, executeQuery方法返回代表查询结果的 Resultset对象

CRUD操作- create

使用 executeUpdate(String sql) 方法完成数据添加操作,示例操作:

Statement st = conn. createStatement();
String sql = " insert into user(...) values(...)"
int num= st.executeUpdate(sq1);
if(num>0){
system.out. printIn("插入成功!!!")
}

CRUD操作 - delete

使用 executeUpdate( String sql) 方法完成数据删除操作,示例操作:

Statement st = conn.createStatement();
String sql = "delete from user where id=l";
int num = st.executeUpdate(sql);
if(num > 0){
system.out.printIn("删除成功!!!");
}

CRUD操作 - update

executeUpdate( String sql) 方法完成数据修改操作,示例操作

Statement st = conn.createStatement();
String sql = "update user set name='' where name =''";
int num = st.executeUpdate(sql)
if(num > 0){
system.out.printIn("修改成功!!!");
}

CRUD操作 - read

吏用 executeQuery( String sq方法完成数据查询操作,示例操作

Statement st = conn.createStatement();
String sql = "select * from user where id=l";
ResultSet rs = st.executeQuery(sql)
while(rs.next()){

}

1. 代码实现

  • 提取工具类
  • 编写增删改的方法, executeUpdate

package com.kuang.lesson02;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TextInsert {
public static void main(String[] args) {

Connection conn = null;
Statement st = null;
ResultSet rs = null;

try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) " +
"VALUES(4,'blue','123456','[email protected]','2020-01-01')";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("插入成功!");
}

} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}

}
}

package com.kuang.lesson02;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TextDelete {
public static void main(String[] args) {

Connection conn = null;
Statement st = null;
ResultSet rs = null;

try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "DELETE FROM users WHERE id = 4";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("删除成功!");
}

} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}

}
}

package com.kuang.lesson02;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TextUpdate {

public static void main(String[] args) {

Connection conn = null;
Statement st = null;
ResultSet rs = null;

try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "UPDATE users SET `name` = 'blue',`email`='[email protected]`jdbcstudy`' WHERE id=1";
int i = st.executeUpdate(sql);
if (i>0){
System.out.println("更新成功!");
}

} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}

}

}
  • 查询
package com.kuang.lesson02;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class TextSelect {
public static void main(String[] args) {

Connection conn = null;
Statement st = null;
ResultSet rs = null;

try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "select * from users where id = 1";

rs = st.executeQuery(sql);
if (rs.next()){
System.out.println(rs.getString("NAME"));
}

} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}

}
}

2. SQL注入问题

sql存在漏洞,会被攻击导致数据泄露,SQL会被拼接or

package com.kuang.lesson02;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

public class SQL注入 {

public static void main(String[] args) {
login("blue","123456");
}

public static void login(String username, String password){

Connection conn = null;
Statement st = null;
ResultSet rs = null;

try {
conn = JdbcUtils.getConnection();
st = conn.createStatement();
String sql = "select * from users where `NAME`= '"+username+"' AND `password`='"+password+"'";

rs = st.executeQuery(sql);
if (rs.next()){
System.out.println(rs.getString("NAME"));
System.out.println(rs.getString("password"));
}

} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}

}

}

10.5 PreparedStatement 对象

  • PreparedStatement可以防止SQL注入。
  • 效率更好

1、增加

package com.kuang.lesson03;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TextInsert {

public static void main(String[] args) {

Connection conn = null;
PreparedStatement st = null;

try {
conn = JdbcUtils.getConnection();

String sql = "insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)";
st = conn.prepareStatement(sql);

st.setInt(1,4);
st.setString(2,"blue");
st.setString(3,"123456");
st.setString(4,"[email protected]");

st.setDate(5,new java.sql.Date(new Date().getTime()));

int i = st.executeUpdate();
if (i>0){
System.out.println("插入成功!");
}

} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(conn,st,null);
}

}

}

2、删除

package com.kuang.lesson03;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TextDelete {

public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;

try {
conn = JdbcUtils.getConnection();

String sql = "delete from users where id=?";
st = conn.prepareStatement(sql);

st.setInt(1,4);

int i = st.executeUpdate();
if (i>0){
System.out.println("删除成功!");
}

} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(conn,st,null);
}

}

}

3、修改

package com.kuang.lesson03;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.Date;

public class TextUpdate {

public static void main(String[] args) {

Connection conn = null;
PreparedStatement st = null;
try {
conn = JdbcUtils.getConnection();

String sql = "update users set `NAME` =? where id=? ; ";
st = conn.prepareStatement(sql);

st.setString(1 ,"blue");
st.setInt(2,1);

int i = st.executeUpdate();
if (i>0){
System.out.println("更新成功!");
}

} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(conn,st,null);
}

}

}

4、查询

package com.kuang.lesson03;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class TextSelect {

public static void main(String[] args) {
Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();

String sql = "select * from users where id=?";

st = conn.prepareStatement(sql);

st.setInt(1,1);

rs = st.executeQuery();

if (rs.next()){
System.out.println(rs.getString("NAME"));
}

} catch (SQLException throwables) {
throwables.printStackTrace();
} finally {
JdbcUtils.release(conn,st,rs);
}
}

}

5、防止SQL注入

package com.kuang.lesson03;

import com.kuang.lesson02.utils.JdbcUtils;

import java.sql.*;

public class SQL注入 {

public static void main(String[] args) {

login("lisi","123456");
login("'' or 1=1","'' or 1=1");
}

public static void login(String username, String password){

Connection conn = null;
PreparedStatement st = null;
ResultSet rs = null;
try {
conn = JdbcUtils.getConnection();

String sql = "select * from users where `NAME`=? and `PASSWORD`=?";

st = conn.prepareStatement(sql);
st.setString(1,username);
st.setString(2,password);

rs = st.executeQuery();
while (rs.next()){
System.out.println(rs.getString("NAME"));
System.out.println(rs.getString("password"));
}

} catch (SQLException throwables) {
throwables.printStackTrace();
}finally {
JdbcUtils.release(conn,st,rs);
}

}

}

10.6 连接数据库

; 10.7 事务

要么都成功,要么都失败

ACID原则

原子性:要么全部完成,要么都不完成

一致性:总数不变

隔离性:多个进程互不干扰

持久性:一旦提交不可逆,持久化到数据库了

隔离性的问题

脏读:事务读取了另一个没有提交的事务

不可重复读:在同一个事务内,重复读取表中的数据,表数据发生了改变

虚读(幻读):在一个事务内,读取到了别人插入的数据,导致前后读出来结果不一致

代码实现

1、开启事务 conn.setAutoCommit(false)

2、一组业务执行完毕,提交事务

3、可以在 catch 语句中显示的定义回滚语句,但默认失败就会回滚

10.8 数据库连接池

数据库连接 — 执行完毕 — 释放

连接 — 释放十分浪费系统资源

池化技术:准备一些预先的资源,过来就连接预先准备好的

——- 开门 – 业务员:等待 - 服务 - 关门

最小连接数:10

最大连接数:15

等待超时:100ms

编写连接池,实现一个接口 Data Source

开源数据源实现

DBCP

C3PO

Druid:阿里巴巴

使用了这些数据库连接池之后,我们在项目开发中就不需要编写连接数据库的代码了

DBCP

需要用到的jar包

commons-dbcp-1.4,commons-pool-16

C3P0

需要用到的jar包

c3p0-0.9.5.5、 mchange-commons-java-0 2.19

结论

无论使用什么数据源,本质还是一样的, Data Source接口不会变,方法就不会变

Druid
Apache


文章作者: CJ菌
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 CJ菌 !
评论
  目录