mysql

1.7、连接数据库

命令行连接!

mysqp -uroot -p123456 --连接数据库

update mysql.user set authentication_string=password('123456') where user='root' and Host = 'localhost'; --刷新权限

flush privileges; --刷新权限

----------------------------------------------

-- 所有的语句都是用;结尾

show databases;  --查看所有的数据库

 

mysql> use school;  -- 切换数据库 use 数据库名
Database changed

 

show tables;  -- 查看数据库所有的表

describe student;; -- 显示数据库中所有的表的信息

 

create database westos; -- 创建一个数据库

 

exit; --退出连接

-- 单行注释(SQL的本来的注释)

/*    (SQL的多行注释)

hello

asdf

*/

 

数据库 XXX 语言 CRUD 增删改查! CV 程序猿  API程序猿  CRUD 程序猿! (业务!)

DDL  定义

DML 操作

DQL 查询

DCL 控制

2、操作数据库

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

==mysql关键字不区分大小写==

2.1、操作数据库(了解)

1、创建数据库

CREATE DATABASE [IF NOT EXISTS] westos;

2、删除数据库

DROP DATABASE IF EXISTS westos;

3、使用数据库

-- tab 键的上面,如果你的表名或者字段名是一个特殊字符,就需要带``--
USE `school`

4、查看数据库

SHOW DATABASES -- 查看所有的数据库

对比:SQLyog的可视化操作

 

 

 学习思路:

  • sqlyou可视化历史记录查看sql
  • 固定的语法或关键字必须要强行记住!

2.2、数据库的列类型

数据

  • tinyint    十分小的数据  1个字节大小
  • smallint  较小的数据     2个字节
  • mediumint  中等大小的数据  3个字节
  • int           标准的字节    4个字节    常用的
  • bigint           较大的数据    8个字节
  • float         浮点数           4个字节  
  • double     浮点数           8个字节
  • decimal   字符串形式的浮点数    金融计算的时候,一般是使用decimal

字符串

  • char        字符串固定大小       0~255
  • varchar   可变字符串              0~65535    常用的变量   String
  • tinytext    微型文本                 2^8-1
  • text          文本串                    2^16-1         保存大文本

时间日期

java.util.Date

  • date     YYYY-MM-DD,日期
  • time     HH: mm: ss 时间格式
  • datetime     YYYY-MM-DD HH: mm: ss   最常用的时间格式
  • timestamp   时间戳       1970.1.1 到现在的毫秒数!也较为常用!
  • year    年份表示

null

  • 没有值,未知
  • ==注意,不要使用NULL进行运算,结果为NULL==

2.3、数据库的字段属性(重点)

Unsigned:

  • 无符号的整数
  • 声明为该列不能声明为负数

zerofill:

  • 0填充的
  • 不足的位数,使用0来填充,  int(3)    ,    5  ---  005

自增:

  • 通常理解为自增,自动在上一条记录的基础上 + 1 (默认)
  • 通常用来设计唯一的主键~   index,必须是整数类型
  • 可以自定义设计主键自增的其始值和步长

非空 NULL not null

  • 假设设置为 not null,如果不给它赋值,就会报错!
  • NULL,如果不填写值,默认就是null!

默认:

  • 设置默认的值!
  • sex,默认值为男,如果不指定该列的值,则会有默认的值!

拓展:

/*   每一个表,都必须存在以下五个字段!未来做项目用的,表示一个记录存在意义!
id   主键
`version`    乐观锁
is_delete    伪删除
gmt_create   创建时间
gmt_update   修改时间
*/

2.4、创建数据库表

-- 注意点,使用英文(),表的名称和字段尽量使用``括起来 
-- auto_increment 自增 
-- 字符串使用单引号括起来!
-- 所有的数据后面加 , (英文的),最后一个不用加
-- primary key 主键,一般一个表只有一个唯一的主键!
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 -- 查看student数据表的定义语句 
DESC student -- 可以显示表的结构

2.5、数据表的类型

-- 关于数据引擎
/*
INNODB 默认使用~
MYISAM 早些年使用的
*/

  MYISAM  INNODB
事务支持 不支持 支持
数据行锁定 不支持  支持
外键约束 不支持 支持
全文索引 支持 不支持
表空间大小 较小 较大,约为2倍

 

 

 

 

 

 

 

 

 

常用使用操作:

  • MYSAM    节约空间,速度快
  • INNODB    安全性高,事务的处理,多表多用户操作

在物理空间存在的位置

所有的数据库文件都存在data目录下,一个文件夹就对应一个数据库

本质还是文件的存储!

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

  • INNODB  在数据库表中只有一个*.frm文件,以及上级目录的bdata1文件
  • MYISAM 对应文件
    •   *.frm - 表结构的定义文件
    • *.MYD 数据文件 (data)
    • *.MYI   索引文件  (index)

 

设置数据库表的字符集编码

1 CHARSER=utf8

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

在my.ini中配置默认的编码

1 character-set-server=utf8

2.6、修改和删除表

修改

-- 修改表名  ALTER TABLE 旧表名 RENAME AS 新表名
ALTER TABLE teacher RENAME AS teacher1
-- 增加表的字段  ALTER TABLE 表名 ADD 字段名 列属性
ALTER TABLE teacher1 ADD age INT(11)

-- 修改表的字段(重命名,修改约束)
-- ALTER TABLE 表名 MODIFY 字段名 列属性[]
ALTER TABLE teacher1 MODIFY age VARCHAR(11) -- 修改约束

-- ALTER TABLE 表名 CHANGE 旧字段名 新字段名 列属性[] ALTER TABLE teacher1 CHANGE age age1 INT(1) -- 修改字段重名 -- 删除表的字段 ALTER TABLE 表名 DROP 字段名
 ALTER TABLE teacher1 DROP age1

 

删除

-- 删除表 (如果表存在再删除)
DROP TABLE IF EXISTS teacher1

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

注意点:

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

 

3、MySQL数据管理

3.1、外键(了解即可)

方式一、在创建表的时候,填加约束(麻烦,比较复杂)

CREATE TABLE IF NOT EXISTS `grade`(
    `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年纪id',
    `gradename` VARCHAR(50) NOT NULL COMMENT '年纪名称',
    PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8


-- 学生表的 gradeid 字段 要去引用年级表的 gradeid
-- 定义外键key
-- 给这个外键添加约束 (执行引用) references 引用
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 IF NOT EXISTS `grade`(
    `gradeid` INT(10) NOT NULL AUTO_INCREMENT COMMENT '年纪id',
    `gradename` VARCHAR(50) NOT NULL COMMENT '年纪名称',
    PRIMARY KEY (`gradeid`)
)ENGINE=INNODB DEFAULT CHARSET=utf8


-- 学生表的 gradeid 字段 要去引用年级表的 gradeid
-- 定义外键key
-- 给这个外键添加约束 (执行引用) references 引用
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`) ;

-- ALTER TABLE 表 ADD CONSTRAINT 约束名 FOREING KEY(作为外键的列) REFERENCES 那个表(哪个字段)

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

最佳实践

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

 

 

3.2、DML语言(全部记住,背下来)

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

DML语言:数据操作语言

  • insert
  • update
  • delete

 

3.3、添加

insert

-- 插入语句(添加)
-- insert into 表名([字段名1,字段名2,字段名3]) values('值1'),('值2'),('值3',...)
INSERT INTO `grade`(`gradename`) VALUES('大四')

-- 由于主键自增我们可以省略主键(如果不写表的字段,它就会一一匹配)
INSERT INTO `grade` VALUES('大三')

-- 一般写入的语句,我们一定有数据和字段一一对应

-- 查入多个字段
INSERT INTO `grade`(`gradename`) VALUES('大二'),('大一')



INSERT INTO `student`(`name`) VALUES('张山')
INSERT INTO `student`(`name`,`pwd`,`sex`) VALUES('张三','aaaaaa','')
INSERT INTO `student`(`name`,`pwd`,`sex`)
 VALUES('李四','aaaaaa',''),('王五','aaaaaa','')

语法:insert into 表名([字段名1,字段名2,字段名3]) values('值1'),('值2'),('值3',...)

注意事项:

  1. 字段和字段之间用英文逗号隔开
  2. 字段是可以省略的,但是后面的值必须要一一对应,不能少
  3. 可以同时插入多条数据VALUES后面的值,需要使用,隔开即可VALUES(),(),...

 

 

3.4、修改

update    修改谁    (条件)    set原来的值=新值

 1 -- 修改学员的名字,带了条件
 2 UPDATE `student` SET `name`='狂神' WHERE id = 1;
 3 
 4 -- 不指定条件下的情况,会改动所有的表!
 5 UPDATE `student` SET `name`='长江七号'
 6 
 7 -- 语法:
 8 -- UPDATE 表名 set colnum_name = value,[colnum_num = value,....] where [条件]
 9 
10 -- 修改多个属性,逗号隔开
11 UPDATE `student` SET `name`='菲儿',`email`='234613412@qq.com' WHERE id = 1;

条件:where子句 运算符 id等于某个值,大于某个值,在某个区间内修改...

操作符 含义 范围 结果
= 等于 5=6 false
<>或!= 不等于 5<>6 true
>      
<      
<=      
>=      
between...and ... 在某个范围内   [2,5]
AND 我和你&& 5>1 and 1>2 false
OR 我或你|| 5>1 and 1>2 true

 

 

 

 

 

 

 

 

 

-- 通过多个条件定位数据,无上限!
UPDATE `student` SET `name`='长江二号' WHERE `name`='长江七号' AND sex='';

语法:UPDATE 表名 set colnum_name = value,[colnum_num = value,....] where [条件]

注意:

  • colnum_name 是数据库的列,尽量带上``
  • 条件,筛选的条件,如果没有指定,则会修改所有的列
  • value,是一个值,也可以是一个变量
  • 多个设置的属性之间使用逗号隔开
1 UPDATE `student` SET `birthday`=CURRENT_TIME WHERE `name`='菲儿' AND sex='';

 

3.5、删除

delete命令

语法: delete from 表名 [where 条件]

1 -- 删除数据(避免这样写,全部删除)
2 DELETE FROM `student`
3 -- 删除指定数据
4 DELETE FROM `student` WHERE id=2;

TRUNCATE 命令

作用:完全清空一个数据库表,表的结构和索引约束不会变!

 

delete 和TRUNCATE 区别

  • 相同点都能删除数据,都不会删除表结构
  • 不同
    • TRUNCATE 重新设置 自增列 计数器会归零
    • TRUNCATE 不会影响事务  
 1 -- 测试delete 和 CRUNCATE 区别
 2 CREATE TABLE `test`(
 3     `id` INT(4) NOT NULL AUTO_INCREMENT,
 4     `cool` VARCHAR(20) NOT NULL,
 5     PRIMARY KEY(`id`)
 6 )ENGINE=INNODB DEFAULT CHARSET=utf8
 7 
 8 
 9 INSERT INTO `test`(`cool`) VALUES('1'),('2'),('3')
10 
11 
12 DELETE FROM `test` -- 不会影响自增
13 
14 TRUNCATE TABLE `test` -- 自增会归零

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

  • INNODB 自增列会重1开始(存在内存当中,断电及消失)
  • MYISAM 继续从上一个自增两开始 (存在文件中的,不会消失)

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

4.1、DQL

(Data Query Language:数据查询语言)

  • 所有的查询操作都用它  Select
  • 简单的查询,复杂的查询它都能做~
  • 数据库中最核心的语言,最重要的语句
  • 使用平频率最高

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、指定查询字段

 1 -- 查询全部的学生,   SELECT 字段 FROM 表
 2 SELECT * FROM student
 3 
 4 -- 查询指定字段
 5 SELECT `studentno`,`studentname` FROM student
 6 
 7 -- 别名,给给结果起一个名字 AS  可以给字段起别名,也可以给表起别名
 8 SELECT `studentno` AS 学号,`studentname`AS 学生名字 FROM student AS s
 9 
10 -- 函数 Concat (a,b)
11 SELECT CONCAT('姓名:',studentname) AS 新名字 FROM student

语法: SELETCT 字段,...  FROM 表

有时候,列明不是那么的见名知意。我们起别名    AS       字段名  AS  别名     表名  AS 别名

去重  distinct

1 -- 查询一下有哪些哪些同学参加了考试,成绩
2 SELECT * FROM result -- 查询全部的考试成绩
3 SELECT `studentno` FROM result -- 查询有哪些同学参加了考试
4 SELECT DISTINCT `studentno` FROM result -- 发现重复数据,去重

数据库的列(表达式)

1 SELECT VERSION() -- 查询系统版本  (函数)
2 SELECT 100*3-1 AS 计算结果 -- 用来计算  (表达式)
3 SELECT @@auto_increment_increment -- 查询自增的步长  (变量)
4 
5 SELECT `studentno`,`studentresult`+1 AS '提分后' FROM result

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

selct 表达式 from 表

4.3、where 条件子句

作用:检索数据中符合条件的值

搜索条件由一个或者多个表达式组成!结果 布尔值

逻辑运算符

运算符 语法 描述
and  && a and b  a&&b 逻辑与,两个都为真,结果为真
or   || a or b   a||b 逻辑或,其中一个为真,则结果为真
not   ! not a     ! a 逻辑非,真为假,假为真

 

 

 

 

 

尽量使用英文字母

 1 -- ==========================  where  =============================
 2 SELECT `studentno`,`studentresult` FROM result
 3 
 4 -- 查询考试成绩在 95~100 分之间
 5 SELECT `studentno`,`studentresult` FROM result WHERE studentresult>=95 AND studentresult<=100
 6 
 7 
 8 -- and    &&
 9 SELECT `studentno`,`studentresult` FROM result 
10 WHERE studentresult>=95 && studentresult<=100
11 
12 -- 模糊查询(区间)
13 SELECT `studentno`,`studentresult` FROM result 
14 WHERE studentresult BETWEEN 95 AND 100
15 
16 -- 除了1000号学生之外的同学的成绩
17 SELECT `studentno`,`studentresult` FROM result
18 WHERE studentno != 1000;

 

模糊查询:比较运算符

运算符 语法 描述
IS NULL a is null 如果操作符为NULL,结果为真
IS NOT NULL a is not null 如果操作符不为null,结果为真
BETWEEN a between b and c 诺a在b和c之间,则结果为真
Like a like b SQL匹配,如果a匹配b,则结果为真
In a in(a1,a2,a3......) 假设a在a1,或者a2.....其中的某一个之中,结果为真

 

 

 

 

 

 

 

 1 -- ==========================  模糊查询  =============================
 2 
 3 -- 查询姓刘的同学
 4 -- like结合   %(代表0到任意个字符)  _(一个字符)
 5 SELECT `studentno`,`studentname` FROM student 
 6 WHERE `studentname` LIKE '刘%'
 7 
 8 -- 查询姓刘的同学,,名字后面只有一个字的
 9 SELECT `studentno`,`studentname` FROM student 
10 WHERE `studentname` LIKE '刘_'
11 
12 -- 查询名字中间有嘉字的同学 %嘉%
13 SELECT `studentno`,`studentname` FROM student 
14 WHERE `studentname` LIKE '%嘉%'
15 
16 -- =========  in(具体的一个或者多个值)  =========
17 -- 查询 1001,1002,1003号学员
18 SELECT `studentno`,`studentname` FROM student 
19 WHERE studentno IN (1001,1002,1003);
20 
21 -- 查询在北京的学生
22 SELECT `studentno`,`studentname` FROM student
23 WHERE `address` IN ('江苏南通','江苏南京')
24 
25 
26 -- ==== null   not null====
27 
28 -- 查询地址为空的同学 null ''
29 SELECT `studentno`,`studentname` FROM student
30 WHERE address='' OR address IS NULL
31 
32 -- 查询有出身日期的同学  不为空
33 SELECT `studentno`,`studentname` FROM student
34 WHERE `borndate` IS NOT NULL
35 
36 -- 查询没有出生日期的同学  为空
37 SELECT `studentno`,`studentname` FROM student
38 WHERE `borndate` IS NULL

4.4、联表查询

JOIN 对比

操作 描述
Inner join

如果表中至少有一个匹配,就返回行

left join 会从左表中返回所有的值,即使右表中没有匹配
right join 会从右表中返回所有的值,即使左表中没有匹配

 

 

 

 

 

 

七种Join:

 

 

 

 

 1 -- ======================  联表查询  =====================
 2 
 3 -- 查询参加考试的同学(学号,姓名,科目编号,分数)
 4 
 5 SELECT * FROM  student
 6 SELECT * FROM  result
 7 
 8 /* 思路:
 9 1.分析需求,分析查询的字段来自哪些表,(连接查询)
10 2.确定使用哪种连接查询? 7种
11 确定交叉点(这两个表中哪个数据是相同的)
12 判断的条件:学生表中的 studentno = 成绩表 studentno
13 */
14 
15 SELECT s.studentno,studentname,subjectno,studentresult
16 FROM student AS s 
17 INNER JOIN result AS r
18 ON s.studentno = r.studentno
19 
20 
21 -- Right Join
22 SELECT s.studentno,studentname,subjectno,studentresult
23 FROM student s 
24 RIGHT JOIN result r
25 ON s.studentno = r.studentno
26 
27 -- Left Join
28 SELECT s.studentno,studentname,subjectno,studentresult
29 FROM student s 
30 LEFT JOIN result r
31 ON s.studentno = r.studentno

 

 1 -- ======================  联表查询  =====================
 2 
 3 -- 查询参加考试的同学(学号,姓名,科目编号,分数)
 4 
 5 SELECT * FROM  student
 6 SELECT * FROM  result
 7 
 8 /* 思路:
 9 1.分析需求,分析查询的字段来自哪些表,(连接查询)
10 2.确定使用哪种连接查询? 7种
11 确定交叉点(这两个表中哪个数据是相同的)
12 判断的条件:学生表中的 studentno = 成绩表 studentno
13 */
14 
15 
16 -- join (连接的表) on(判断的条件) 连接查询
17 -- where   等值查询
18 
19 
20 
21 SELECT s.studentno,studentname,subjectno,studentresult
22 FROM student AS s 
23 INNER JOIN result AS r
24 ON s.studentno = r.studentno
25 
26 
27 -- Right Join
28 SELECT s.studentno,studentname,subjectno,studentresult
29 FROM student s 
30 RIGHT JOIN result r
31 ON s.studentno = r.studentno
32 
33 -- Left Join
34 SELECT s.studentno,studentname,subjectno,studentresult
35 FROM student s 
36 LEFT JOIN result r
37 ON s.studentno = r.studentno
38 
39 -- 查询缺考的同学
40 SELECT s.studentno,studentname,subjectno,studentresult
41 FROM student s 
42 LEFT JOIN result r
43 ON s.studentno = r.studentno
44 WHERE studentresult IS NULL
45 
46 
47 -- 思考题(查询了参加考试的同学信息:学号,学生姓名,科目名,分数)
48 /* 思路:
49 1.分析需求,分析查询的字段来自哪些表,(连接查询)
50 2.确定使用哪种连接查询? 7种
51 确定交叉点(这两个表中哪个数据是相同的)
52 判断的条件:学生表中的 studentno = 成绩表 studentno
53 */
54 
55 SELECT s.studentno,studentname,subjectname,studentresult
56 FROM student s
57 RIGHT JOIN result r
58 ON s.studentno = r.studentno 
59 INNER JOIN `subject` sj
60 ON r.subjectno = sj.subjectno
61 
62 
63 -- 我要查询哪些数据  select ...
64 -- 从几个表中查 FROM 表   XXX Join 连接的表 on  交叉条件
65 -- 假设存在一种多张表查询,慢慢来,先查询两张表然后再慢慢增加
66 
67 -- From a left join b
68 -- From b left join a

 

自连接(了解)

自己的表和自己的表连接,核心:一张表拆为两张一样的表即可

父类

categoryid categoryname
2 信息技术
3 软件开发
5 美术设计
   

 

 

 

 

 

 

子类

pid categoryid categoryname
3 4 数据库
2 8 办公信息
3 6 web开发
5 7 ps设计

 

 

 

 

 

 

 

操作:查询父类对应的子类关系

 

父类 子类
信息技术 办公信息
软件开发 数据库
软件开发 web开发
美术设计 ps设计

 

 

 

 

 

 

 1 -- 查询父类信息 :把一张表看为两个一模一样的表
 2 
 3 SELECT a.`categoryname` AS '父栏目',b.`categoryname` AS '子栏目'
 4 FROM `category` AS a, `category` AS b
 5 WHERE a.`categoryid` = b.`pid`
 6 
 7 -- 查询学员所属的年纪(学号,学生的名字,年级名称)
 8 SELECT studentno,studentname,`gradename`
 9 FROM student s
10 INNER JOIN `grade` g
11 ON s.`gradeid` = g.`gradeid`
12 
13 -- 查询科目所属的年纪(科目名称,年级名称)
14 SELECT `subjectname`,`gradename`
15 FROM `subject` sub
16 INNER JOIN `grade` g
17 ON sub.`gradeid` = g.`gradeid`
18 
19 
20 -- 查询了参加数据库结构-1考试的同学信息:学号,学生姓名,科目名,分数
21 
22 SELECT s.`studentno`, `studentname`, `subjectname`, `studentresult`
23 FROM student s
24 INNER JOIN result r
25 ON s.`studentno` = r.`studentno`
26 INNER JOIN SUBJECT sub
27 ON r.`subjectno` = sub.`subjectno`
28 WHERE subjectname = '数据库结构-1'

 

4.5分页和排序

排序

 1 -- ===================== 分页和排序 =====================
 2 
 3 -- 排序: 升序ASC,降序DESC
 4 -- ORDER BY 通过那个字排序
 5 -- 查询的结果根据 成绩降序 排序
 6 SELECT s.`studentno`, `studentname`, `subjectname`, `studentresult`
 7 FROM student s
 8 INNER JOIN result r
 9 ON s.`studentno` = r.`studentno`
10 INNER JOIN SUBJECT sub
11 ON r.`subjectno` = sub.`subjectno`
12 WHERE subjectname = '数据库结构-1'
13 ORDER BY studentresult ASC

分页

 1 -- ===================== 分页和排序 =====================
 2 
 3 -- 排序: 升序ASC,降序DESC
 4 -- ORDER BY 通过那个字排序
 5 -- 查询的结果根据 成绩降序 排序
 6 SELECT s.`studentno`, `studentname`, `subjectname`, `studentresult`
 7 FROM student s
 8 INNER JOIN result r
 9 ON s.`studentno` = r.`studentno`
10 INNER JOIN SUBJECT sub
11 ON r.`subjectno` = sub.`subjectno`
12 WHERE subjectname = '数据库结构-1'
13 ORDER BY studentresult ASC
14 
15 -- 100万
16 -- 为什么要分页?
17 -- 缓解数据库压力,给人的体验更好,瀑布流
18 
19 -- 分页,每页值显示五条数据
20 -- 语法:limit 起始值,页面的大小
21 -- 网页应用: 当前,总的页数,页面的大小
22 -- LIMIT 0,5       1~5
23 -- LIMIT 1,5       2~6
24 -- LIMIT 6,5
25 SELECT s.`studentno`, `studentname`, `subjectname`, `studentresult`
26 FROM student s
27 INNER JOIN result r
28 ON s.`studentno` = r.`studentno`
29 INNER JOIN SUBJECT sub
30 ON r.`subjectno` = sub.`subjectno`
31 WHERE subjectname = '数据库结构-1'
32 ORDER BY studentresult ASC
33 LIMIT 5,5
34 
35 -- 第一页  limit 0,5
36 -- 第二页  limit 5,5
37 -- 第三页  limit 10,5
38 -- 第N页  limit (n-1) * pageSize, pageSize
39 -- [pageSize:页面大小,, ]
40 -- [(n-1) * pageSize起始值]
41 -- [n当前页]
42 -- [数据总数/页面大小 = 总页数]

语法: limit(查询起始下标,pageSize)

 

4.6、子查询

where(这个值是计算出来的)

本质:在where语句中嵌套一个子查询语句

where (select * from)

 1 -- ========================= where ==========================
 2 
 3 -- 1、查询数据库结构-1 的所有的考试结果(学号,科目编号,成绩),降序排列
 4 -- 方式一:使用连接查询
 5 SELECT `studentno`,r.`subjectno`,`studentresult`
 6 FROM result r
 7 INNER JOIN SUBJECT sub
 8 ON r.subjectno = sub.subjectno
 9 WHERE `subjectname`= '数据库结构-1'
10 ORDER BY studentresult DESC
11 
12 -- 方式二:使用子查询(由里及外)
13 -- 查询所有数据库结构-1 的学号
14 SELECT subjectno FROM `subject` WHERE subjectname = '数据库结构-1'
15 SELECT `studentno`,`subjectno`,`studentresult`
16 FROM `result`
17 WHERE subjectno = (
18      SELECT subjectno FROM `subject`
19      WHERE subjectname = '数据库结构-1'
20 )
21 ORDER BY studentresult DESC
22 
23 -- 分数不小于80分的学生的学号和姓名
24 SELECT DISTINCT s.`studentno`,`studentname`
25 FROM student s
26 INNER JOIN result r
27 ON s.studentno = r.studentno
28 WHERE studentresult >= 80
29 
30 -- 在这个基础上增加一个科目,高等数学-2
31 -- 查询 高等数学-2 的编号
32 SELECT DISTINCT s.`studentno`,`studentname`
33 FROM student s
34 INNER JOIN result r
35 ON s.studentno = r.studentno
36 WHERE studentresult >= 80 AND `subjectno`=(
37 SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2'
38 )
39 
40 -- 再改造 (由里及外)
41 SELECT studentno,studentname FROM student WHERE studentno IN (
42     SELECT studentno FROM result WHERE studentresult >=80 AND subjectno IN (
43         SELECT subjectno FROM `subject` WHERE subjectname = '高等数学-2'
44 )
45 )
46 
47 -- 查询课程为 高等数学-2 且分数不小于 80 的同学的学号个姓名
48 SELECT s.`studentno`,`studentname`
49 FROM student s
50 INNER JOIN result r
51 ON s.studentno = r.studentno
52 INNER JOIN `subject` sub
53 ON sub.subjectno = r.subjectno
54 WHERE subjectname = '高等数学-2' AND studentresult >=80

4.7、分组和过滤

1 -- 查询不同课程的平均分,最高分,最低分
2 -- 核心:(根据不同的课程分组)
3 SELECT subjectname, AVG(`studentresult`) 平均分,MAX(`studentresult`) AS 最高分,MIN(`studentresult`) AS 最低分
4 FROM result r
5 INNER JOIN `subject` sub
6 ON r.`subjectno` = sub.`subjectno`
7 GROUP BY r.subjectno  -- 通过什么字段来分组
8 HAVING 平均分>80

 4.8、select小结

顺序很重要:

select 去重,要查询的字段from表 (注意:表和字段可以取别名)

xxx join 要连接的表 on 等值判断

where(具体的值,子查询语句)

Group By (通过哪个字段来分组)

Having (过滤分组后的信息,条件和where时一样的,位置不同)

Order By ... (通过哪个字段排序) [升序/降序]

Limit startindex,pagesize

 

业务层面:

查询:跨表,夸数据库...

 

 

 

5、MySQL函数

 

官网地址:https://dev.mysql.com/doc/refman/5.7/en/

5.1、常用函数

 1 -- ====================== 常用函数 =======================
 2 
 3 -- 数学运算
 4 SELECT ABS(-8)     -- 绝对值
 5 SELECT CEILING(9.4)    -- 向上取整
 6 SELECT FLOOR(9.4)   -- 向下取整
 7 SELECT RAND()     -- 返回一个 0~1 之间的随机数
 8 SELECT SIGN(10)    -- 判断一个数的符号 0-0  负数返回-1,正数返回1
 9 
10 -- 字符串函数
11 SELECT CHAR_LENGTH('即使再小的帆也能远航')  -- 字符串长度
12 SELECT CONCAT('','','')  -- 拼接字符串
13 SELECT INSERT('我爱编程helloworld',1,2,'超级热爱')   -- 查询,替换 从某个位置替换某个长度
14 SELECT LOWER('KuangShen')  -- 大写转小写
15 SELECT UPPER('KuangShen')  -- 小写转大写
16 SELECT INSTR('Kuangshen','h')   -- 返回第一次出现子串的索引
17 SELECT REPLACE('坚持就能成功','坚持','努力')  -- 替换出现的指定字符串
18 SELECT SUBSTR('坚持就能成功',5,4)  -- 返回指定的子字符串(源字符串,截取的位置,截取的长度)
19 SELECT REVERSE('坚持就能成功')  -- 反转字符
20 
21 -- 查询姓周的同学,名字 邹
22 SELECT REPLACE(studentname,'','') FROM student
23 WHERE studentname LIKE '周%'
24 
25 -- 时间和日期的函数(记住)
26 SELECT CURRENT_DATE()  -- 获取当前日期
27 SELECT CURDATE()   -- 获取当前日期
28 SELECT NOW()   -- 获取当前时间
29 SELECT LOCALTIME()  -- 获取本地时间
30 SELECT SYSDATE()  -- 系统时间
31 
32 SELECT YEAR(NOW())
33 SELECT MONTH(NOW())
34 SELECT DAY(NOW())
35 SELECT HOUR(NOW())
36 SELECT MINUTE(NOW())
37 SELECT SECOND(NOW())
38 
39 
40 -- 系统
41 SELECT SYSTEM_USER()
42 SELECT USER()
43 SELECT VERSION()

 

 

5.2、聚合函数(常用)

函数 描述
COUNT() 计数
SUN() 求和
AVG() 平均值
MAX() 最大值
MIN() 最小值

 

 

 

 

 

 

 

 1 -- ============= 聚合函数 ==============
 2 
 3 -- 都能做统计 表中的数据(想查询一个表中有多少个记录,就使用这个count)
 4 SELECT COUNT(studentname) FROM student;  -- COUNT(字段),会忽略所有的 null 值
 5 SELECT COUNT(*) FROM student;   -- COUNT(*), 不会忽略 null 值 本质 计算行数
 6 SELECT COUNT(1) FROM result;   -- COUNT(1),不会忽略所有的 null 值 本质 计算行数
 7 
 8 
 9 SELECT SUM(`studentresult`) AS 总和 FROM result
10 SELECT AVG(`studentresult`) AS 平均分 FROM result
11 SELECT MAX(`studentresult`) AS 最高分 FROM result
12 SELECT MIN(`studentresult`) AS 最低分 FROM result

 5.3、数据库级别的MD5加密(拓展)

什么是MD5?

主要增强算法复杂度和不可逆性。

MD5不可逆,具体的值得md5是一样的

MD5破解网站的原理,背后有一个字典,MD5加密后的值,加密的前值

 1 -- =============== 测试MD5 加密 ================
 2 
 3 CREATE TABLE `testmd5`(
 4     `id` INT(4) NOT NULL,
 5     `name` VARCHAR(20) NOT NULL,
 6     `pwd` VARCHAR(50) NOT NULL,
 7     PRIMARY KEY(`id`)
 8 )ENGINE=INNODB DEFAULT CHARSET=utf8
 9 
10 -- 明文密码
11 INSERT INTO testmd5 VALUES(1,'zhangsan','123456'),(2,'lisi','123456'),(3,'wangwu','123456')
12 
13 -- 加密
14 UPDATE testmd5 SET pwd=MD5(pwd) WHERE id = 1
15 
16 UPDATE testmd5 SET pwd=MD5(pwd)   -- 加密全部的密码
17 
18 -- 插入的时候加密
19 INSERT INTO testmd5 VALUES(4,'xiaoming',MD5('123456'))
20 
21 -- 如何校验:将用户传递进来的密码,进行md5加密,然后比对加密后的值
22 SELECT * FROM testmd5 WHERE `name` = 'xiaoming' AND pwd=MD5('123456')

 

6、事务

6.1、什么是事务

要么都成功,要么都失败

-----------------

1、SQL执行  A给B转账   A 1000    ---->200   B200

2、SQL执行  B收到A的钱     A 800    ------>400

-----------------

将一组SQL放在一个批次中去执行~

 

事务原则:ACID原则 原子性(Atomiscit),一致性(Consistency),隔离性(Isolation),持久性(Durability)      (脏读,幻读......)

参考博客连接:https://blog.csdn.net/dengjili/article/details/82468576

原子性(Atomicity)

要么都成功,要么都失败

一致性(Consistency)

事务前后数据的完整性必须保持一致,1000

持久性(Durability)

事务一旦提交则不可逆,被持久化到数据库中!

隔离性(Isolation)
事务的隔离性是多个用户并发访问数据库时,数据库为每一个用户开启的事务,不能被其他事务的操作数据所干扰,多个并发事务之间要相互隔离。

 

隔离所导致的一些问题

脏读:

指一个事务读取了另外一个事务未提交的数据。

不可重复读:

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

虚读(幻读)

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

 1 -- ===================== 事务 =========================
 2 
 3 -- mysql 是默认开启事务自动提交的
 4 SET autocommit = 0 /*关闭*/
 5 SET autocommit = 1 /*开启(默认的)*/
 6 
 7 -- 手动处理事务
 8 SET autocommit = 0 -- 关闭自动提交
 9 
10 
11 -- 事务开启
12  START TRANSACTION   -- 标记一个事务的开始,从这个之后的sql 都在同一个事务内
13  
14  INSERT xx
15  INSERT xx
16 
17 -- 提交:持久化 (成功!)
18 COMMIT
19 
20 -- 回滚:回到原来的样子 (失败!)
21 ROLLBACK
22 
23 -- 事务结束
24 SET autocommit = 1 -- 开启自动提交
25 
26 
27 -- 了解
28 SAVEPOINT 保存点名  -- 设置一个事务的保存点
29 ROLLBACK TO SAVEPOINT 保存点名  -- 回滚到保存点
30 RELEASE SAVEPOINT 保存点  -- 撤销保存点

 

模拟场景

 1 -- 转账
 2 CREATE DATABASE shop CHARACTER SET utf8 COLLATE utf8_general_ci
 3 USE STOP
 4 
 5 CREATE TABLE `account`(
 6     `id` INT(3) NOT NULL AUTO_INCREMENT,
 7     `name` VARCHAR(30) NOT NULL,
 8     `money` DECIMAL(9,2) NOT NULL,
 9     PRIMARY KEY (`id`)
10 )ENGINE= INNODB DEFAULT CHARSET=utf8
11 
12 
13 INSERT INTO `account`(`name`,`money`)
14 VALUES ('A',2000.00),('B',10000.00)
15 
16 -- 模拟转账:事务
17 SET autocommit = 0; -- 关闭自动提交
18 START TRANSACTION -- 开启一个事务
19 
20 UPDATE account SET money=money-500 WHERE `name` ='A' -- A减500
21 UPDATE account SET money=money+500 WHERE `name` ='B' -- A加500
22 
23 COMMIT; -- 提交事务,就会被持久化了!
24 ROLLBACK; -- 回滚
25 
26 SET autocommit = 1; -- 恢复默认值

7、索引

MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构。0.5    0.00001s

提取句子主干,就可以的到索引的本质:索引是数据结构。

 

7.1、索引的分类

在一个表中,主键索引只有一个,唯一索引可以有多个

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

 

基础语法

 1 -- 索引的使用
 2 -- 1、在创建表的时候个字段增加索引
 3 -- 2、创建完毕后,增加索引
 4 
 5 
 6 -- 显示所有的索引信息
 7 SHOW INDEX FROM student
 8 
 9 -- 增加一个全文索引 (索引名) 列名
10 ALTER TABLE school.student ADD FULLTEXT INDEX `studentname`(`studentname`);
11 
12 -- EXPLAIN 分析sql执行的状况
13 EXPLAIN SELECT * FROM student;  -- 非全文索引
14 
15 EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('');

7.2、测试索引

 1 -- 索引的使用
 2 -- 1、在创建表的时候个字段增加索引
 3 -- 2、创建完毕后,增加索引
 4 
 5 
 6 -- 显示所有的索引信息
 7 SHOW INDEX FROM student
 8 
 9 -- 增加一个全文索引 (索引名) 列名
10 ALTER TABLE school.student ADD FULLTEXT INDEX `studentname`(`studentname`);
11 
12 -- EXPLAIN 分析sql执行的状况
13 EXPLAIN SELECT * FROM student;  -- 非全文索引
14 
15 EXPLAIN SELECT * FROM student WHERE MATCH(studentname) AGAINST('');
16 
17 
18 CREATE TABLE `app_user` (
19     `id` BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
20     `name` VARCHAR(50) DEFAULT '' COMMENT '用户昵称',
21     `email` VARCHAR(50) NOT NULL COMMENT '用户邮箱',
22     `phone` VARCHAR(20) DEFAULT '' COMMENT '手机号',
23     `gender` TINYINT(4) UNSIGNED DEFAULT '0' COMMENT '性别(0:男;1:女)',
24     `password` VARCHAR(100) NOT NULL COMMENT '密码',
25     `age` TINYINT(4) DEFAULT '0' COMMENT '年龄',
26     `create_time` DATETIME DEFAULT CURRENT_TIMESTAMP,
27     `update_time` TIMESTAMP NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
28     PRIMARY KEY (`id`)
29 ) ENGINE=INNODB DEFAULT CHARSET=utf8mb4 COMMENT='app用户表'
30 
31 
32 -- 插入100万条数据
33 -- delimiter $$ -- 写函数之前必须要写,标志
34 DROP FUNCTION IF EXISTS mock_data;
35 DELIMITER $$
36 CREATE FUNCTION mock_data()
37 RETURNS INT
38 BEGIN
39 DECLARE num INT DEFAULT 1000000;
40 DECLARE i INT DEFAULT 0;
41 WHILE i < num DO
42   INSERT INTO app_user(`name`, `email`, `phone`, `gender`, `password`, `age`)
43    VALUES(CONCAT('用户', i), '24736743@qq.com', CONCAT('18', FLOOR(RAND()*(999999999-100000000)+100000000)),FLOOR(RAND()*2),UUID(), FLOOR(RAND()*100));
44   SET i = i + 1;
45 END WHILE;
46 RETURN i;
47 END;
48 SELECT mock_data();
49 
50 
51 SELECT * FROM app_user WHERE NAME = '用户9999';  -- 0.720 sec
52 SELECT * FROM app_user WHERE NAME = '用户9999';  -- 0.711 sec
53 SELECT * FROM app_user WHERE NAME = '用户9999';  -- 0.734 sec
54 
55 EXPLAIN SELECT * FROM app_user WHERE `name` = '用户9999';
56 
57 SELECT * FROM student
58 
59 -- id_表名_字段
60 -- CREATE INDEX 索引名 on 表(字段)
61 CREATE INDEX id_app_user_name ON app_user(`name`);
62 
63 SELECT * FROM app_user WHERE NAME = '用户9999'; -- 0.001 sec
64 EXPLAIN SELECT * FROM app_user WHERE NAME = '用户9999';

 

 

 

 

 

 索引在小数据量的时候,用户不大,但是在打数据的时候,区别十分明显~

 

7.3、索引原则

  • 索引不是越多越好
  • 不要对经常变动数据加索引
  • 小数据量的表不需要加索引
  • 索引一般加在常用来查询到的字段上!

 

索引的数据结构

Hash 类型的索引

Btree: InnoDB 的默认结构

 

阅读:http://blog.codinglabs.org/articles/theory-of-mysql-index.html

 

8、权限管理和备份

8.1、用户管理

SQL 命令操作

用户表:mysql.user

本质:读这张表进行增删改查

 1 -- 创建用户  CREATE USER 用户名 IDENTIFIED BY '密码'
 2 CREATE USER kuangshen IDENTIFIED BY '123456'
 3 
 4 
 5 -- 修改密码(修改当前用户密码)
 6 SET PASSWORD = PASSWORD('123456')
 7 
 8 
 9 -- 修改密码(修改指定用户密码)
10 SET PASSWORD FOR kuangshen = PASSWORD('123456')
11 
12 
13 -- 重命名  RENAME USER 原来名字 TO 新的名字
14 RENAME USER kuangshen TO kuangshen2
15 
16 -- 用户授权 ALL PRIVILEGES 全部的权限,库.表
17 -- ALL PRIVILEGES 除了给别人授权,其他的都能干
18 GRANT ALL PRIVILEGES ON *.* TO kuangshen2
19 
20 -- 查看权限
21 SHOW GRANTS FOR kuangshen2  -- 查看指定用户的权限
22 SHOW GRANTS FOR root@localhost
23 
24 -- root用户的权限:GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' WITH GRANT OPTION
25 
26 -- 撤销权限 REVOKE 哪些权限,在哪个库撤销,给谁撤销
27 REVOKE ALL PRIVILEGES ON *.* FROM kuangshen2
28 
29 -- 删除用户
30 DROP USER kuangshen2

8.2、MySQL备份

为什么要备份:

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

MySQL数据库备份的方式

  • 直接拷贝物理文件
  • 在Sqlyog这种可视化工具中手动导出
    • 在想要导出的表或者库中,右键,选择备份或导出

       

       

  • 使用命令行导出 mysqldump 命令行使用
     1 # mysqldump -h 主机 -u 用户名 -p 密码 数据库 表名 > 物理磁盘位置/文件名
     2 mysqldump -hlocalhost -uroot -p123456 school student >D:/a.sql
     3 mysqldump: [Warning] Using a password on the command line interface can be insecure.
     4 
     5 # mysqldump -h 主机 -u 用户名 -p 密码 数据库 表1 表2 表3 > 物理磁盘位置/文件名
     6 mysqldump -hlocalhost -uroot -p123456 school student result >D:/b.sql
     7 mysqldump: [Warning] Using a password on the command line interface can be insecure.
     8 
     9 # mysqldump -h 主机 -u 用户名 -p 密码 数据库 > 物理磁盘位置/文件名
    10 mysqldump -hlocalhost -uroot -p123456 school >D:/c.sql
    11 mysqldump: [Warning] Using a password on the command line interface can be insecure.
    12 
    13 # 导入
    14 # 登录的情况下,切换到指定的数据库
    15 # source 备份文件
    16 source d:/a.sql
    17 
    18 mysql -u用户名 -p密码 库名< 备份文件

     

假设你要备份数据库,防止数据丢失。

把数据库给朋友!sql文件给朋友即可!

 

 

9、规范数据库设计

9.1、为什么需要设计

当数据库比较复杂的时候,我们就需要设计了

糟糕的数据库设计:

  • 数据冗余,浪费空间
  • 数据库插入和删除都会麻烦、异常【屏蔽使用物理外键】
  • 程序的性能差

 

良好的数据库设计:

  • 节省内存空间
  • 保证数据库的完整性
  • 方便我们开发系统

软件开发中,关于数据库的设计

  • 分析需求:分析业务和需要处理的数据库的需求
  • 概要设计:设计关系图 E-R 图

 

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

  • 收集信息,分析需求
    • 用户表(用户登录注册,用户的个人信息,写博客,创建分类)
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 评论表
    • 友链表(友链信息)
    • 自定义表(系统信息,某个关键的字,或者一些主字段) key: value
    • 说说表(发表心情 .. id...content....create_time)
  • 标识实体(把需求落地到每个字段)
  • 标识实体 之间的关系
    • 写博客:user -->blog
    • 创建分类:user -->category
    • 关注:user --> user
    • 友链:links
    • 评论:user-user-blog

 

9.2、三大范式

为什么需要数据规范化?

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

 

三大范式:

第一范式(1NF)

原子性:保证每一列不可再分

第二范式(2NF)

前提:满足第一范式

每张表只描述一件事情

第三范式(3NF)

前提:满足第一范式和第二范式

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

 

(规范数据库的设计)

 

规范性 和 性能的问题

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

  • 考虑商业化的需求和目标,(成本,用户体验!)数据库的性能更加重要
  • 在规范性能的问题的 时候,需要适当的考虑一下 规范!
  • 故意给某些表增加一些冗余的字段。(多表查询中变为单表查询)
  • 故意增加一些计算列(从大数据量降低为小数据量的查询:索引)

10、JDBC(重点)

10.1、数据库驱动

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

10.2、JDBC

SUN 公司为了简化开发人员的(对数据库的统一)操作,提供了一个(Java操作数据库的)规范,俗称 JDBC

这些规范的实现由具体的厂商去做~ 

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

java.sql

javax.sql

还需要导入一个数据库驱动包 mysql-connector-java-5.1.47.jar

 

10.3、第一个JDBC程序

创建测试数据库

 1 CREATE DATABASE jdbcStudy CHARACTER SET utf8 COLLATE utf8_general_ci;
 2 
 3 USE jdbcStudy;
 4 
 5 CREATE TABLE users(
 6     id INT PRIMARY KEY,
 7     NAME VARCHAR(40),
 8     PASSWORD VARCHAR(40),
 9     email VARCHAR(60),
10     birthday DATE
11 );
12 
13 INSERT INTO users(id,NAME,PASSWORD,email,birthday)
14 VALUES(1,'zhansan','123456','zs@sina.com','1998-12-06'),
15 (2,'lisi','123456','lisi@sina.com','1999-12-01'),
16 (3,'wangwu','123456','wangwu@sina.com','2000-12-23');

 

1、创建一个普通项目

2、导入数据库驱动

 

 3、编写测试代码

 1 package com.kuang.lesson01;
 2 
 3 import java.sql.*;
 4 
 5 //我的第一个JDBC程序
 6 public class jdbcFirstDemo {
 7     public static void main(String[] args) throws ClassNotFoundException, SQLException {
 8         //1.加载驱动
 9         Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
10         //2.用户信息和url
11         //useUnicode=true&characterEncoding=utf8&useSSL=true
12         String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
13         String username = "root";
14         String password = "123456";
15 
16         //3.连接成功,数据库对象
17         Connection connection = DriverManager.getConnection(url, username, password);
18 
19         //4.执行SQL的对象
20         Statement statement = connection.createStatement();
21 
22         //5.执行SQL的对象 去 执行SQL,可能存在结果,查看返回结果
23         String sql = "SELECT * FROM `users`";
24 
25         ResultSet resultSet = statement.executeQuery(sql); //返回的结果集,结果集中封装了我们全部的查询出来的结果
26 
27         while(resultSet.next()) {
28             System.out.println("id=" + resultSet.getObject("id"));
29             System.out.println("name=" + resultSet.getObject("NAME"));
30             System.out.println("pwd=" + resultSet.getObject("PASSWORD"));
31             System.out.println("email=" + resultSet.getObject("email"));
32             System.out.println("birth=" + resultSet.getObject("birthday"));
33             System.out.println("-------------------");
34         }
35 
36         //6.释放连接
37         resultSet.close();
38         statement.close();
39         connection.close();
40     }
41 }

步骤总结:

1、加载驱动

2、连接数据库 DriverManager

3、获得执行sql的对象 Statement

4、获得返回的结果集

5、释放连接

 

DriverManager

1 //1.加载驱动
2         //DriverManager.registerDriver(new com.mysql.jdbc.Driver());
3         Class.forName("com.mysql.jdbc.Driver"); //固定写法,加载驱动
4 
5 //3.连接成功,数据库对象
6         Connection connection = DriverManager.getConnection(url, username, password);
7 //connection 代表数据库库
8 //数据库设置自动提交
9 //事务提交
10 //事务回滚
11 connection.rollback();
12 connection.commit();
13 connection.setAutoCommit();

 

 

 

URL

1 String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=true";
2 
3 
4 //mysql -- 3306
5 //协议://主机地址:端口号/数据库名?参数1&参数2&参数3
6 
7 //oralce -- 1521
8 //jdbc:oracle:thin:@localhost:1521:sid

 

Statement 执行SQL的对象   PreparStatement 执行SQL的对象

1 String sql = "SELECT * FROM `users`"; //编写SQL
2 
3 statement.executeQuery(); //查询操作返回 ResultSet
4 statement.execute(); //执行任何SQL
5 statement.executeUpdate(); //更新、插入删除。都用这个,返回一个受影响的行数

 

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

获得指定的数据类型

1 resultSet.getObject(); //在不知道列的数据类型的情况下使用
2  // 如果知道列的类型就使用指定的类型
3 resultSet.getString();
4 resultSet.getInt();
5 resultSet.getFloat();
6 resultSet.getDouble();
7 ...

遍历,指针

1 resultSet.beforeFirst(); //移动到最前面
2 resultSet.afterLast(); //移动到最后面
3 resultSet.next(); //移动到下一个数据
4 resultSet.previous(); //移动到前一行
5 resultSet.absolute(row); //移动到指定行 

 

释放资源

//6.释放连接
        resultSet.close();

        statement.close();

        connection.close(); //耗资源用完关掉

 

10.4、statement对象

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

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

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

 

CRUD操作-create

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

1 Statement st = conn.createStatement();
2 String sql = "insert into user(...) values(...)";
3 int num = st.executeUpdate(sql);
4 if(num>0){
5     System.out.println("插入成功!!!");
6 }

CRUD操作-delete

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

1 Statement st = conn.createStatement();
2 String sql = "delete from user where id =1";
3 int num = st.executeUpdate(sql);
4 if(num>0){
5     System.out.println("删除成功!!!");
6 }

CRUD操作-update

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

1 Statement st = conn.createStatement();
2 String sql = "update user set name=' ' where name=' '";
3 int num = st.executeupdate(sql);
4 if(num>0){
5     System.out.println("修改成功!!!");
6 }

CRUD操作-read

使用executeQuery(String sql)方法完成数据查询操作,示例操作:

1 statement st = conn.createstatement();
2 String sql = "select * from user where id = 1";
3 ResultSet rs = st.executeQuery(sql);
4 while(rs.next()){
5     //根据获取列的数据类型,分别调用rs的相应方法映射到Java对象中
6 }

 

 

代码实现

1、提取工具类

 1 package com.kuang.lesson02.utils;
 2 
 3 import java.io.InputStream;
 4 import java.sql.*;
 5 import java.util.Properties;
 6 
 7 public class JdbcUtils {
 8 
 9     public static String driver = null;
10     public static String url = null;
11     public static String username = null;
12     public static String password = null;
13 
14 
15     static{
16 
17         try {
18             InputStream in = JdbcUtils.class.getClassLoader().getResourceAsStream("db.properties");
19             Properties properties = new Properties();
20             properties.load(in);
21 
22             driver = properties.getProperty("driver");
23             url = properties.getProperty("url");
24             username = properties.getProperty("username");
25             password = properties.getProperty("password");
26 
27             //1.驱动只用加载一次
28             Class.forName(driver);
29 
30             } catch (Exception e) {
31             e.printStackTrace();
32         }
33     }
34 
35     //获取连接
36     public static Connection getConnection() throws SQLException {
37         return DriverManager.getConnection(url, username, password);
38     }
39 
40     //释放连接资源
41     public static void release (Connection conn, Statement st, ResultSet rs){
42         if (rs!=null){
43             try {
44                 rs.close();
45             } catch (SQLException throwables) {
46                 throwables.printStackTrace();
47             }
48         }
49         if (st!=null){
50             try {
51                 st.close();
52             } catch (SQLException throwables) {
53                 throwables.printStackTrace();
54             }
55         }
56         if (conn!=null){
57             try {
58                 conn.close();
59             } catch (SQLException throwables) {
60                 throwables.printStackTrace();
61             }
62         }
63     }
64 }

 

2、编写增删改的方法:executeUpdate

 

 1 package com.kuang.lesson02;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 import java.sql.Statement;
 9 
10 public class TestInsert {
11     public static void main(String[] args) {
12 
13         Connection conn = null;
14         Statement st = null;
15         ResultSet rs = null;
16 
17         try {
18             conn = JdbcUtils.getConnection();//获取数据库连接
19             st = conn.createStatement(); //获得SQL的执行对象
20             String sql = "INSERT INTO users(id,`NAME`,`PASSWORD`,`email`,`birthday`) VALUES (4,'wuliu','123456','wuliu@sina.com','2000-12-02')";
21 
22             int i = st.executeUpdate(sql);
23             if(i>0) {
24                 System.out.println("插入成功!");
25             }
26         } catch (SQLException e) {
27             e.printStackTrace();
28         } finally {
29 
30             JdbcUtils.release(conn,st,rs);
31         }
32     }
33 }
 1 package com.kuang.lesson02;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 import java.sql.Statement;
 9 
10 public class TestDelete {
11     public static void main(String[] args) {
12 
13         Connection conn = null;
14         Statement st = null;
15         ResultSet rs = null;
16 
17         try {
18             conn = JdbcUtils.getConnection();//获取数据库连接
19             st = conn.createStatement(); //获得SQL的执行对象
20             String sql = "DELETE FROM users WHERE id =4";
21 
22             int i = st.executeUpdate(sql);
23             if(i>0) {
24                 System.out.println("删除成功!");
25             }
26         } catch (SQLException e) {
27             e.printStackTrace();
28         } finally {
29 
30             JdbcUtils.release(conn,st,rs);
31         }
32     }
33 }
 1 package com.kuang.lesson02;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 import java.sql.Statement;
 9 
10 public class TestUpdate {
11     public static void main(String[] args) {
12 
13         Connection conn = null;
14         Statement st = null;
15         ResultSet rs = null;
16 
17         try {
18             conn = JdbcUtils.getConnection();//获取数据库连接
19             st = conn.createStatement(); //获得SQL的执行对象
20             String sql = "UPDATE users SET `NAME`='kuangshen',`email`='kuang@sina.com' WHERE id=1";
21 
22             int i = st.executeUpdate(sql);
23             if(i>0) {
24                 System.out.println("更新成功!");
25             }
26         } catch (SQLException e) {
27             e.printStackTrace();
28         } finally {
29 
30             JdbcUtils.release(conn,st,rs);
31         }
32     }
33 }

3、查询``

 1 package com.kuang.lesson02;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 import java.sql.Statement;
 9 
10 public class TestSelect {
11     public static void main(String[] args) {
12 
13         Connection conn = null;
14         Statement st =null;
15         ResultSet rs = null;
16 
17 
18         try {
19             conn = JdbcUtils.getConnection();
20 
21             st = conn.createStatement();
22 
23             //SQL
24             String sql = "select * from users where id = 1";
25             rs = st.executeQuery(sql); //查询完毕会返回一个结果集
26 
27             while (rs.next()) {
28                 System.out.println(rs.getString("NAME"));
29             }
30 
31         } catch (SQLException throwables) {
32             throwables.printStackTrace();
33         } finally {
34             JdbcUtils.release(conn,st,rs);
35         }
36 
37     }
38 }

SQL注入的问题

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

 1 package com.kuang.lesson02;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.ResultSet;
 7 import java.sql.SQLException;
 8 import java.sql.Statement;
 9 
10 public class SQL注入 {
11     public static void main(String[] args) {
12 
13         //login("kuangshen","123456");
14         login("'or'1=1","'or'1=1"); // 技巧
15 
16     }
17 
18     // 登录业务
19     public static void login(String username,String password){
20 
21         Connection conn = null;
22         Statement st =null;
23         ResultSet rs = null;
24 
25 
26         try {
27             conn = JdbcUtils.getConnection();
28 
29             st = conn.createStatement();
30 
31             //SQL
32             //SELECT * FROM users WHERE `NAME` = 'kuangshen' AND `PASSWORD` = '123456'
33             //SELECT * FROM users WHERE `NAME` = ''or'1=1' AND `PASSWORD` = ''or'1=1'
34             String sql = "select * from users where `NAME`='"+username+"' AND `PASSWORD` = '"+password+"' ";
35             rs = st.executeQuery(sql); //查询完毕会返回一个结果集
36 
37             while (rs.next()) {
38                 System.out.println(rs.getString("NAME"));
39                 System.out.println(rs.getString("PASSWORD"));
40                 System.out.println("---------------------------");
41         }
42 
43         } catch (SQLException throwables) {
44             throwables.printStackTrace();
45         } finally {
46             JdbcUtils.release(conn,st,rs);
47         }
48 
49 
50     }
51 
52 
53 }

 

10.5、PreparedStatement对象

PreparedStatement 可以防止SQL注入,效率跟高!

 

1、新增

 1 package com.kuang.lesson03;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.util.Date;
 6 import java.sql.*;
 7 
 8 public class TestInsert {
 9     public static void main(String[] args) {
10         Connection conn = null;
11         PreparedStatement st = null;
12         ResultSet rs = null;
13 
14         try {
15             conn = JdbcUtils.getConnection();
16 
17             // 区别
18             // 使用? 占位符代替参数
19             String sql = "insert into users(id,`NAME`,`PASSWORD`,`email`,`birthday`) values(?,?,?,?,?)";
20 
21             st = conn.prepareStatement(sql); // 预编译SQL,先写sql,然后不执行
22 
23             // 手动 给参数赋值
24             st.setInt(1,4); //id
25             st.setString(2,"wangliu");
26             st.setString(3,"147258");
27             st.setString(4,"8888888@.qq.com");
28             // 注意点: sql.Date     数据库    java.sql.Date()
29             //          util.Date   Java     new Date().getTime() 获得时间戳
30             st.setDate(5,new java.sql.Date(new Date().getTime()));
31 
32             //执行
33             int i = st.executeUpdate();
34             if (i>0) {
35                 System.out.println("插入成功!");
36             }
37 
38         } catch (SQLException throwables) {
39             throwables.printStackTrace();
40         } finally {
41             JdbcUtils.release(conn,st,rs);
42         }
43     }
44 }

 

2、删除

 1 package com.kuang.lesson03;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.PreparedStatement;
 7 import java.sql.ResultSet;
 8 import java.sql.SQLException;
 9 import java.util.Date;
10 
11 public class TestDelete {
12     public static void main(String[] args) {
13         Connection conn = null;
14         PreparedStatement st = null;
15         ResultSet rs = null;
16 
17         try {
18             conn = JdbcUtils.getConnection();
19 
20             // 区别
21             // 使用? 占位符代替参数
22             String sql = "delete from users where id=?";
23 
24             st = conn.prepareStatement(sql); // 预编译SQL,先写sql,然后不执行
25 
26             // 手动 给参数赋值
27             st.setInt(1,4);
28 
29             //执行
30             int i = st.executeUpdate();
31             if (i>0) {
32                 System.out.println("删除成功!");
33             }
34 
35         } catch (SQLException throwables) {
36             throwables.printStackTrace();
37         } finally {
38             JdbcUtils.release(conn,st,rs);
39         }
40     }
41 }

 

3、更新

 1 package com.kuang.lesson03;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.PreparedStatement;
 7 import java.sql.ResultSet;
 8 import java.sql.SQLException;
 9 
10 public class TestUpdate {
11     public static void main(String[] args) {
12         Connection conn = null;
13         PreparedStatement st = null;
14         ResultSet rs = null;
15 
16         try {
17             conn = JdbcUtils.getConnection();
18 
19             // 区别
20             // 使用? 占位符代替参数
21             String sql = "update users set `NAME`=? where id=?;";
22 
23             st = conn.prepareStatement(sql); // 预编译SQL,先写sql,然后不执行
24 
25             // 手动 给参数赋值
26             st.setString(1,"狂神");
27             st.setInt(2,1);
28 
29             //执行
30             int i = st.executeUpdate();
31             if (i>0) {
32                 System.out.println("更新成功!");
33             }
34 
35         } catch (SQLException throwables) {
36             throwables.printStackTrace();
37         } finally {
38             JdbcUtils.release(conn,st,rs);
39         }
40     }
41 }

 

4、查询

 1 package com.kuang.lesson03;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.PreparedStatement;
 7 import java.sql.ResultSet;
 8 import java.sql.SQLException;
 9 
10 public class TestSelect {
11     public static void main(String[] args) {
12         Connection conn = null;
13         PreparedStatement st = null;
14         ResultSet rs = null;
15 
16         try {
17             conn = JdbcUtils.getConnection();
18 
19             String sql = "select * from users where id = ?"; // 编写SQL
20 
21             st = conn.prepareStatement(sql);// 预编译
22 
23             st.setInt(1,1); // 传递参数
24 
25             //执行
26             rs = st.executeQuery();
27             while (rs.next()) {
28                 System.out.println(rs.getString("NAME"));
29             }
30 
31 
32         } catch (SQLException throwables) {
33             throwables.printStackTrace();
34         } finally {
35             JdbcUtils.release(conn,st,rs);
36         }
37     }
38 }

 

5、防止SQL注入

 1 package com.kuang.lesson03;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.*;
 6 
 7 public class SQL注入 {
 8     public static void main(String[] args) {
 9 
10         //login("lisi","123456");
11         login("'' or 1=1","123456"); // 技巧
12 
13     }
14 
15     // 登录业务
16     public static void login(String username,String password){
17 
18         Connection conn = null;
19         PreparedStatement st =null;
20         ResultSet rs = null;
21 
22 
23         try {
24             conn = JdbcUtils.getConnection();
25             // PreparedStatement 防止SQL注入的本质,把传递进来的参数当做字符
26             // 假设其中存在转义字符,比如说 ' 会被直接转义
27             String sql = "select * from users where `NAME`=? and `PASSWORD`=?"; // Mybatis
28 
29             st = conn.prepareStatement(sql);
30 
31             st.setString(1,username);
32             st.setString(2,password);
33 
34             rs = st.executeQuery(); //查询完毕会返回一个结果集
35             while (rs.next()) {
36                 System.out.println(rs.getString("NAME"));
37                 System.out.println(rs.getString("PASSWORD"));
38                 System.out.println("---------------------------");
39         }
40 
41         } catch (SQLException throwables) {
42             throwables.printStackTrace();
43         } finally {
44             JdbcUtils.release(conn,st,rs);
45         }
46 
47 
48     }
49 
50 
51 }

 

10.7、使用IDEA连接数据库

 

 连接成功后可以选择数据库

 

 双击表

 

 更新数据

 

 

 

 连接失败查看原因:

 

 

10.8、事务

要么都成功,要么都失败

ACID原则

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

一致性:总数不变

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

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

 

隔离性的问题:

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

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

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

 

代码实现

1、开启业务  conn.setAutoCommit(false); 

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

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

 1 package com.kuang.lesson04;
 2 
 3 import com.kuang.lesson02.utils.JdbcUtils;
 4 
 5 import java.sql.Connection;
 6 import java.sql.PreparedStatement;
 7 import java.sql.ResultSet;
 8 import java.sql.SQLException;
 9 
10 public class TestTransaction1 {
11     public static void main(String[] args) {
12         Connection conn = null;
13         PreparedStatement st = null;
14         ResultSet rs = null;
15 
16         try {
17             conn = JdbcUtils.getConnection();
18             // 关闭数据库的自动提交, 自动会开启事务
19 
20             conn.setAutoCommit(false);  // 开启事务
21 
22             String sql1 = "update account set money = money-100 where name = 'A'";
23             st = conn.prepareStatement(sql1);
24             st.executeUpdate();
25 
26             //int x =1/0; // 报错
27 
28             String sql2 = "update account set money = money+100 where name = 'B'";
29             st = conn.prepareStatement(sql2);
30             st.executeUpdate();
31 
32             //业务完毕,提交业务
33             conn.commit();
34             System.out.println("成功!");
35 
36 
37 
38         } catch (SQLException e) {
39             // 要是失败,则默认自动回滚
40             try {
41                 conn.rollback(); // 如果失败则回滚事务
42             } catch (SQLException e1) {
43                 e1.printStackTrace();
44             }
45             e.printStackTrace();
46         } finally {
47             JdbcUtils.release(conn,st,rs);
48         }
49     }
50 }

 

10.9、数据库连接池

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

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

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

 

最小连接数:10

最大连接数:15

等待超时:100ms

 

编写连接池,实现一个接口 DataSource

 

开源数据实现(拿来即用)

DBCP

C3P0

Druid:阿里巴巴

 

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

DBCP

需要用到的jar包

commons-dbcp-1.4.jar

 commons-pool-1.6.jar

 

C3P0

C3P0地址:https://sourceforge.net/projects/c3p0/?source=navbar
C3P0是一个开源的连接池

需要导入jar包

 c3p0-0.9.5.5.jar、mchange-commons-java-0.2.19.jar

 结论:

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

 

Druid

 Apache

 

 

 

 

 

 

 

 

 

 

 

 

 

 
posted @ 2020-12-10 16:55  王刘study  阅读(87)  评论(0)    收藏  举报