MySQL

大一课余时间所学的MySQL,笔记为总结与摘抄

内容创建收集于‎2023‎年‎4‎月‎11‎日,‏‎21:18:41

1.初始MySQL

 

1.1 启动/关闭数据库

net start mysql80
net stop mysql80

 

1.2 连接数据库

命令行连接

mysql -u root -p    -- 回车
Enter password: 123456

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

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

use 'databasesName'	-- 切换并使用数据库

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

describe ‘tables’;	-- 显示表里的所有信息

create database 'databasename'; -- 创建一个数据库

exit  	-- 退出连接

 

1.3 SQL通用语法

 

1. SQL语句可以单行或多行书写,以分号结尾
2.SQL语句可以使用空格/缩进来增强语句的可读性。
3.MySQL数据库的SQL语句不区分大小写,关键字建议使用大写
4.注释:
单行注释:-- 注释内容或#注释内容(MySQL特有)

多行注释: /*注释内容*/

 

1.4 SQL的分类

1. DDL

Data Definition Language

  • 数据定义语言,用来定义数据库对象(数据库,表,字段)
2. DML

Data Manipulation Language

  • 数据操作语言,用来对数据库表中的数据进行增删改
3. DQL

Data Query Language

  • 数据查询语言,用来查询数据库中表的记录
4. DCL

Data Control Language

  • 数据控制语言,用来创建数据库用户、控制数据库的访问权限

 


 

2.操作数据库

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

mysql不区分大小写

2.1 操作数据库

1. 创建数据库

create database [if not exists] name		-- []可加可不加

 

2. 删除数据库

drop DATABASE [IF EXISTS] name

 

3. 使用数据库

use 'name'		-- 如果表名或者字段名是一个特殊字符,就需要带符号'name'	 eg.'USE'

 

4. 查看数据库

show databases

 

2.2 数据库的列类型

1. 数值

类型说明字节数
tinyint十分小的数据1
smallint较小的数据2
mediumint中等大小的数据3
int标准整型4
bigint较大的数据8
float浮点型4
double浮点型8
decimal字符串形的浮点数(金融计算常用) 

 

2. 字符串

类型说明范围
char字符串固定大小0~255
varchar可变字符串(常用)’String‘0~65535
tinytext微型文本2**8-1
txet文本串(保存大文本)2**16-1

 

3. 时间日期

类型格式eg
dataYYYY-MM-DD2023-4-12
timeHH:mm:ss10:43:01
datetime(常用)YYYY-MM-DD HH:mm:ss2023-4-12 10:43:01
timestamp(时间戳)1970.1.1到现在的毫秒数 
year年份表示 

 

4. null

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

 

 

2.3 数据库的字段属性

Unsigned:

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

 

zerofill:

  • 0填充
  • 不足位数,使用0补充 eg: int(3) 输入:5 5—–>005

 

自增:  (aoto_increment)

  • 自动在上一条记录的基础上+1(默认)
  • 通常用来设计唯一的主键~index
  • 可以自定义设计主键自增的起始值和步长

 

非空:NULL、not null

  • 设置not null ,不进行赋值报错
  • 设置NULL,不赋值无影响,默认值为NULL

 

默认:

  • 设置默认值
  • 不指定某列的值时,就为默认值

 

 

2.4 创建数据库表

CREATE TABLE `demo001` (
  `id` int unsigned NOT NULL AUTO_INCREMENT COMMENT '学号',
  `name` varchar(255) DEFAULT NULL COMMENT '名字',
  `password` varchar(255) NOT NULL COMMENT '密码',
  `birthday` datetime DEFAULT NULL COMMENT '生日日期',
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
-- 引擎                  字符集           整理

 

-- 格式
CREATE TABLE [IF NOT EXISTS] `表名`(
	`字段名` 列类型 [属性] [索引] [注释],
    `字段名` 列类型 [属性] [索引] [注释],
    ……………………………………………………………………………………………
    `字段名` 列类型 [属性] [索引] [注释]
)[表类型][字符集类型][注释]

 

常用命令

show create databases `basename`	-- 查看创建数据库的语句
show create table `tablename`		-- 查看创建数据表的定义语句
desc `tablename`				   -- 显示表结构

 

 

 

2.5 修改删除表

修改表

-- 修改表名																	-- alter:改变
alter table old_name rename new_name

-- 增加表的字段
alter table 列名字 add 字段名 列属性[]

-- 修改表字段(重命名,修改约束)
alter table 列名字 modify 字段名 列属性[]		-- 修改约束(列属性)
alter table 列名字 change old字段名 new字段名 列属性[]		-- 修改字段名、也可以修改约束

-- 删除表字段
alter table 列名字 drof 字段名

 

删除表

drop table if exists tablename

 

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

 


 

3.MySQL数据管理

 

3.1 外键 foreign key

方法一:13~14

CREATE TABLE `grade` (
  `gradeidfather` int NOT NULL,
  `gradename` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`gradeidfather`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;


CREATE TABLE `student` (
  `id` int NOT NULL COMMENT '学生id',
  `name` varchar(255) DEFAULT NULL COMMENT '学生姓名',
  `gradeidson` int DEFAULT NULL COMMENT '所属年级',
  PRIMARY KEY (`id`),
  KEY `FK_gradeid` (`gradeidson`),
  CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeidson`) REFERENCES `grade` (`gradeidfather`)
    -- 约束              外键                       引用
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

 

方法二:创建表成功后,添加外键约束

alter tables student
ADD CONSTRAINT `FK_gradeid` FOREIGN KEY (`gradeidson`) REFERENCES `grade` (`gradeidfather`)
 ADD CONSTRAINT 约束名 FOREIGN KEY 作为外键的列 REFERENCES 被引用的表名 被引用表的字段名

 

3.2 插入 insert

-- 插入单条数据
insert into `tablename`(字段名1,字段名2,.....) values(data1);
-- 插入多条数据
insert into `tablename`(字段名1,字段名2,.....) values(data1),(data2)................;
insert into `tablename` values(data1),(data2)................;			-- 要求一一对应

 

3.3 修改 update

-- 修改单个
update `tablename` set 字段名 = `values` where [条件]
-- 修改多个
update `tablename` set 字段名 = `values`,[字段名 = 赋值],...... where [条件]

条件where: 操作符会返回布尔值

values内容可以是具体的值也可以是变量

操作符含义例子结果
=等于4=5false
<>或!=不等于4<>5true
>   
<   
>=   
<=   
BETWEEN…and…闭合区间(包含)  
and&&  
or||  

3.4 删除 delete truncate

 

delete (不会重置自增)

delete from `tablename`		(会全部删除)
delete from `tablename` where []	(删除指定数据)

 

truncate

truncate `tablename`

 

共同点:都能删除数据,都不会删除表结构

不同点:truncate 自增会归零 ,delete不会

 


 

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

 

4.1 指定查询字段

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}];
   -- 指定查询的记录从哪条至哪条
[]代表可选
{}代表必选

 

格式:select [字段名] from TableName

select * from `TableName`		-- 查询表中全部信息
select [字段名1],[字段名2]…… from `TableName`		-- 查询指定信息

 

[字段名] as `OtherName“

[TableName] as `OtherName“

as 和飘号可以省略

select * from `TableName` as `别名`

 

函数 Concat(a,b)拼接字符串

select concat(`姓名 = `, StudentName) as `新名字` from student

-- 输出结果eg:
    +---------+
    |  新名字  |
    +---------+
	+ 姓名=张三+

 

去重distinct

发现重复数据就去重,只显示一条

select distinct [字段名] from `TableName`

 

数据库的列(表达式)

select 表达式 from tablename

select version()		-- 查询MySQL版本 8.032

select 5-3 as 计算结果   -- 用来计算(表达式)

select @@aoto_increment_increment	-- 查看自增步数(变量)

select `StudentNo`,`StudentResult` + 1 as '加一分后的成绩' from `TableName`

 

 

4.2 where条件字句

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

搜索的条件由一个或多个表达式组成,结果为布尔值

select [字段名],...... from `tablename` where [判断语句]
select [字段名],...... from `tablename` between [] and []	 -- 模糊查询(效果同上)  

 

 

模糊查询:比较运算符

运算符eg描述
IS NULLA IS NULL如果操作数为NULL,结果为真
IS NOT NULLA IS NOT NULL如果操作数为不为NULL,结果为真
BETWEENA BETWEEN B AND C若a在b到c之间,结果为真
LikeA LIKE B如果a匹配b,结果为真
INA IN (A1,A2,A3……)假设a在a1或a2….其中的某一个值,结果为真
%只能在like里面用代表0到任意一个字符
_只能在like里面用代表一个字符

like结合

-- 查询姓D的同学 like结合
select `studentname` from `tablename` where `studentname` LIKE 'D%'

-- 查询名字里面有D的同学
select `studentname` from `tablename` where `studentname` LIKE '%D%'

-- 查询姓D的同学并且姓后面只有一个字
select `studentname` from `tablename` where `studentname` LIKE 'D_'

-- 查询查询姓D的同学并且姓后面只有两个字
select `studentname` from `tablename` where `studentname` LIKE 'D__'

 

in结合

-- 查询 1001,1002成员
select `studentname` from `tablename` where `studentno` in (1001,1002)

 

4.3 联表查询

join

思路:

1.分析需要,分析查询的字段来自哪些表,(连接查询)

2.确定使用哪种连接查询?7种

确定交叉点(这两表中哪个数据是相同的)

判断条件:eg. s(student表).studentNo = r(result表).studenNo

图解 SQL 里的各种 JOIN - 知乎

左连接Left

select s.studentno,`studentname`,`subjectno`,`studentresult`
from student as s
left join result as r
Where/on s.studentno = r.studentno;			-- on是连表前的条件,where是连表后的过滤
--输出结果
studentno  studentname  subjectno  studentresult  
---------  -----------  ---------  ---------------
     1000  张伟                   5               58
     1000  张伟                   4               98
     1000  张伟                   3               68
     1000  张伟                   2               70
     1000  张伟                   1               85
     1001  赵强                   1              100

 

右连接right

select s.studentno,`studentname`,`subjectno`,`studentresult`
from student as s
right join result as r							-- 连接外表
Where/on s.studentno = r.studentno;				-- 判断条件

 

交集inner

 

操作描述
Inner join如果表中至少有一个匹配,就返回行
left join会从左表中返回所有的值,即使右表中没有匹配
right join会从右表中返回所有的值,即使左表中没有匹配

嵌套查询

SELECT s.studentno,studentname,subjectname,studentresult
FROM student s
RIGHT JOIN result r
ON r.studentno = s.studentno
INNER JOIN `subject` sub
ON r.subjectno = sub.subjectno;
-- 输出结果
studentno  studentname  subjectname     studentresult  
---------  -----------  --------------  ---------------
     1001  赵强           高等数学-1           100
     1000  张伟           高等数学-4            98
     1000  张伟           C语言-1              58
     1000  张伟           高等数学-1            85
     1000  张伟           高等数学-3            68
     1000  张伟           高等数学-2            70

自连接

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

 

 

 

 

4.4 分页和排序

order by 必须在where语句下面,limit必须在order by 和 where语句下面

排序:升序ASC 降序DESC

order by [字段名] ASC/DESC

 

分页

格式:limit (n-1)*pageSize ,pageSize

pageSize:页面存储数据的个数

n:当前页面号

(n-1)*pageSize:起始值(相对于一个数组中元素对应的索引)

数据总数/pageSize=总页数

eg: limit 0,5 — 起始值数据为索引为0的值,单页面中数据总数为5

eg: limit 6,5 — 起始值数据为索引为6的值,单页面中数据总数为5

 

 

4.5 子查询

 

本质:where语句中嵌套select查询

select ...... from .........
inner join ........
on ........=........
where ....... and xxx=(
	select.........from........where.......
)

 

 


5. MySQL函数

 

5.1 常用函数

-- 数学函数
SELECT ABS(-8)		    -- 绝对值  8
SELECT CEILING(9.4)		-- 向上取整 10
SELECT FLOOR(9.4)		-- 向下取整 9
SELECT RAND()    		-- 返回一个0~1的随机数
SELECT SIGN(0)		    -- 判断一个数的符号  0->0  -3->-1  2->1

-- 字符串函数
SELECT CHAR_LENGTH()     -- 字符串长度
SELECT CONCAT('h','0')   -- 拼接字符串 'h0'
SELECT INSERT('今天星期一',1,2,'明天')		-- 查询,从第(1)处开始替换(2)个字符 ‘明天星期一’
SELECT LOWER('A')	     -- 小写字母 'a'
SELECT UPPER('a')     	 -- 大写字母 'A'
SELECT INSTR('abc','c')  -- 返回第一次出现字串的位置 3(从1开始)
SELECT replace('我是xxx','xxx','abc')    -- 替换指定字符串‘我是abc’
SELECT substr(str,起始位置,截取数量[为空默认到底])  -- 查找指定闭区间子串
SELECT reverse()		-- 反转字符串

-- 时间和日期函数
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 system_user()/user()		-- 查询系统用户
SELECT version()			   -- 查询MySQL版本

 

5.2 聚合函数(常用)

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

 

count()

-- *、1会记录NULL值,本质计数行数
SELECT COUNT(*) FROM [表名]
SELECT COUNT(1) FROM [表名]

SELECT COUNT([字段名]) FROM [表名]  	-- 不会记录NULL值

 

 

 

 

5.3 数据库级别的MD5加密

 

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

加密

update `tablename` set [字段名] = MD5(字段名)


-- 插入时加密
insert into `tablename` values(`value1`,.....,MD5(......))

 

如何校验

将用户传递进来的值进行MD5加密,然后对比加密后的值

select * from `tablename` where [字段名] = MD5(......) 

 


 

6. 事务

 

6.1 事务的四大主要特性(ACID)

a. 原子性(Atomicity)

原子性是指事务是一个不可分割的工作单位,事务中的操作要么全部成功,要么全部失败

比如在同一个事务中的SQL语句,要么全部执行成功,要么全部执行失败。

 

b. 一致性(Consistency)

事务按照预期生效,数据的状态是预期的状态。

举例说明:张三向李四转100元,转账前和转账后的数据是正确的状态,这就叫一致性,如果出现张三转出100元,李四账号没有增加100元这就出现了数据错误,就没有达到一致性。

 

c. 隔离性(Isolation)

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

 

d. 持久性(Durability)

持久性是指一个事务一旦被提交,它对数据库中数据的改变就是永久性的,接下来即使数据库发生故障也不应该对其有任何影响。

 

 

隔离导致出现的一些问题

(6条消息) 事务的四大特性、不考虑隔离性会产生的三个问题、如何解决事务的四个特性在项目中怎么解决X先生__的博客-CSDN博客

脏读:

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

例子

  小明的银行卡余额里有100元。现在他打算用手机点一个外卖饮料,需要付款10元。但是这个时候,他的女朋友看中了一件衣服95元,她正在使用小明的银行卡付款。于是小明在付款的时候,程序后台读取到他的余额只有5块钱了,根本不够10元,所以系统拒绝了他的交易,告诉余额不足。但是小明的女朋友最后因为密码错误,无法进行交易。小明非常郁闷,明明银行卡里还有100元,怎么会余额不足呢?(他女朋友更郁闷。。。)

 

不可重复读:

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

例子

  事务T1在读取某一数据,而事务T2立马修改了这个数据并且提交事务给数据库,事务T1再次读取该数据就得到了不同的结果,发送了不可重复读。

虚读(幻读):

是指一个事务内读取到了别的事务插入的数据,导致前后读取不一致

例子

  事务T1对一个表中所有的行的某个数据项做了从“1”修改为“2”的操作,这时事务T2又对这个表中插入了一行数据项,而这个数据项的数值还是为“1”并且提交给数据库。而操作事务T1的用户如果再查看刚刚修改的数据,会发现还有一行没有修改,其实这行是从事务T2中添加的,就好像产生幻觉一样,这就是发生了幻读。

 

 

-- mysql是默认开启事务、自动提交的
set autocommit = 0  -- 关闭
set autocommit = 1  -- 开启

-- 手动处理事务
	set autocommit = 0	-- 关闭自动提交
	-- 事务开始
	start transaction   -- 标记一个事务的开始,从这个之后的sql语句都在同一事务中
	insert [语句]
	insert [语句]
	-- 提交:持久化(成功)
	commit
	-- 回滚:回到原来的样子(失败)
	rollback
	-- 事务结束
	set autocommit = 1	-- 开启自动提交
-- 了解
savepoint [保存点名] -- 设置一个事务的保存点
rollback to savepoint [保存点名] -- 回滚保存点
release savepoint [保存点名]  -- 撤销保存点

 


 

7. 索引

索引是帮助MySQL高效获取数据的数据结构。

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

 

7.1 索引的分类

  • 主键索引 (primary key)

    • 唯一的标识,主键不可重复,只能有一个列作为主键
  • 唯一索引 (unique key)

    • 避免重复的列出现,唯一索引可以重复,多个列都可以标识为唯一索引
    • 索引列的值必须唯一,但允许有空值
  • 常规索引 (key/index)

    • 默认的,用index、key关键字来设置
  • 全文索引 (fulltext)

    • 快速定位数据

 

-- 显示所有的索引信息
show inedx from `tablename`

-- 增加一个全文索引    【`索引名`,(列名)】
alter table `tablename` add fulltext index `索引名`(列名)

-- 	给表字段添加索引
create index `indexname` on `tablename`([列名])

-- 删除索引
drop index [索引名] on `tablename`

-- 删除主键索引
alter table `tablename` drop primary key

-- explain[解释] 分析SQL语句执行性能

explain select * from `tablename`; -- 非全文索引

explain select * from `tablename` where match(`列名`) against('')

 

7.2 索引原则

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

 

 

8. 权限管理和备份

 

8.1 用户管理

a. 创建用户——赋予权限——登录密码

 

 -- 创建用户
create user [用户名] identified by '密码'

-- 修改用户密码
ALTER USER "root"@"localhost" IDENTIFIED BY "新密码";

-- 重命名
rename user `用户` to `新用户名`

-- 用户授权
-- all privileges除了授权给其他人的特权(grant),其他都有
grant all privileges on *.* to `用户名`  -- 全部权限 库.表

-- 查看权限
show grants for `用户名` -- 查看指定用户权限
show grants for "root"@"localhost" -- 查看root用户权限

-- 撤销权限 哪些权限,在哪个库,给谁撤销
revoke all privileges on *.* from `用户名`

-- 删除用户
drop user `用户名`

 

8.2 MySQL 备份

为什么要备份数据

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

MySQL数据库备份方式

  • 使用命令行导出 mysqldump (cmd中)
  • 数据库管理工具手动导出
  • 直接拷贝数据库文件和相关配置文件

 

使用命令行导出 mysqldump (cmd中)

-- mysqldump -h[主机] -u[用户名] -p[密码] 数据库 表名1 表名2 表名3...... > 物理磁盘位置/文件名
mysqldump -hlocalhost -uroot -p123456 school student > D:/name.sql

-- 导入
source d:/name.sql	-- 登录的情况下,并且切换到指定数据库

mysql -u用户名 -p密码 库名 < 备份文件地址	-- 无登录情况下

 

 

 

9. 规范数据库设计

 

9.1 为什么需要数据库设计

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

糟糕的数据库设计 :

  • 数据冗余,存储空间浪费
  • 数据更新和插入的异常
  • 程序性能差

良好的数据库设计 :

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

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

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

 

9.2 三大范式

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

  • 信息重复

  • 更新异常

  • 插入异常

    • 无法正确表示信息
  • 删除异常

    • 丢失有效信息

Mysql – 什么是三大范式(通俗详解) – 知乎 (zhihu.com)

  • 第一范式(1 NF):字段不可再拆分。
  • 第二范式(2 NF):表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。
  • 第三范式(3 NF):在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B。

第一范式 – 1NF

遵循原子性。即,表中字段的数据,不可以再拆分

先看一个不符合第一范式的表结构,如下:

员工编码姓名年龄
001销售部小张28
002运营部小黄25
003技术部小高22

在这一个表中的,姓名 字段下的数据是可以再进行拆分的,因此它不符合第一范式,那怎么样才符合第一范式呢?如下:

员工编码部门姓名年龄
001销售部小张28
002运营部小黄25
003技术部小高22

那是否遵循第一范式就一定是好的呢?如下:

员工编码姓名地址
001小张江西省南昌市东湖区
002小黄广东省佛山市禅城区
003小高湖北省武汉市新洲区

通过观察上述表结构,我们发现,地址是可以再进一步拆分的,比如:

员工编码姓名
001小张江西省南昌市东湖区
002小黄广东省佛山市禅城区
003小高湖北省武汉市新洲区

虽然拆分后,看上去更符合第一范式了,但是如果项目就只需要我们输出一个完整地址呢?那明显是表在没拆分的时候会更好用。

所以范式只是给了我们一个参考,我们更多的是要根据项目实际情况设计表结构。


 

第二范式 – 2NF

在满足第一范式的情况下,遵循唯一性,消除部分依赖。即,表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。

再通俗点讲就是,一个表只能描述一件事情

我们用一个经典案例进行解析。

学号姓名年龄课程名称成绩学分
001小张28语文903
001小张28数学902
002小黄25语文903
002小黄25语文903
003小高22数学902

我们先分析一下表结构。

  1. 假设学号是表中的唯一主键,那由学号就可以确定姓名和年龄了,但是却不能确定课程名称和成绩。
  2. 假设课程名称是表中的唯一主键,那由课程名称就可以确定学分了,但是却不能确定姓名、年龄和成绩。
  3. 虽然通过学号和课程名称的联合主键,可以确定除联合主键外的所有的非主键值,但是基于上述两个假设,也不符合第二范式的要求。

 

那我们应该如何调整表结构,让它能复合第二范式的要求呢?

我们可以基于上述的三种主键的可能,拆分成 3 张表,保证一张表只描述一件事情

  1. 学生表 – 学号做主键
学号姓名年龄
001小张28
002小黄25
003小高22
  1. 课程表 – 课程名称做主键
课程名称学分
语文3
数学2
  1. 成绩表 – 学号和课程名称做联合主键
学号课程名称成绩
001语文90
001数学90
002语文90
002语文90
003数学90

 

这时候我们可能会想,为什么我们就要遵循第二范式呢?不遵循第二范式会造成什么样的后果呢

  1. 造成整表的数据冗余。

如,学生表,可能我就只有2个学生,每个学生都有许多的信息,比如,年龄、性别、身高、住址……如果与课程信息放到同一张表中,可能每个学生有3门课程,那数据总条数就会变成6条了。但是通过拆分,学生表我们只需要存储 2 条学生信息,课程表只需要存储 3 条课程信息,成绩表就只需保留学号、课程名称和成绩字段。

  1. 更新数据不方便。

假设,课程的学分发生了变更,那我们就需要把整表关于该课程的学分都要更新一次,但如果我们拆分出课程表,那我们就只需要把课程表中的课程信息更新就行。

  1. 插入数据不方便或产生异常。

① 假设主键是学号或课程名称,我们新增了某个课程,需要把数据插入到表中,这时,可能只有部分人有选修这门课程,那我们插入数据的时候还要规定给哪些人插入对应的课程信息,同时可能由于成绩还没有,我们需要对成绩置空,后续有成绩后还得重新更新一遍。

② 假设主键是学号和课程名称的联合主键。同样也是新增了某课程,但是暂时没有人选修这门课,缺少了学号主键字段数据,会导致课程信息无法插入。


 

第三范式 – 3NF

在满足第二范式的情况下,消除传递依赖。即,在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B

仍然用一个经典例子来解析

学号姓名班级班主任
001小黄一年级(1)班高老师

这个表中,学号是主键,它可以唯一确定姓名、班级、班主任,符合了第二范式,但是在非主键字段中,我们也可以通过班级推导出该班级的班主任,所以它是不符合第三范式的。

那怎么设计表结构,才是符合第三范式的呢?

  1. 学生表
学号姓名班级
001小黄一年级(1)班
  1. 班级表
班级班主任
一年级(1)班高老师

通过把班级与班主任的映射关系另外做成一张映射表,我们就成功地消除了表中的传递依赖了。

 

 

9.3 规范化和性能的关系

为满足某种商业目标 , 数据库性能比规范化数据库更重要

在数据规范化的同时 , 要综合考虑数据库的性能

通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间

通过在给定的表中插入计算列,以方便查询

 

 

 

10. JDBC(重点)

 

10.1 数据库驱动

 

 

image-20230427110135242

 

10.2 JDBC

简化开发人员对数据库的统一操作,提供一个Java操作数据库的规范,俗称——JDBC(规范的实现由具体的厂商去做)

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

 

image-20230427110815568

java.sql

javax.ssql

还需要导入一个数据库驱动包

 

10.3 实操Java与MySQL

1. 将MySQL驱动添加至IDEA

IDEA导入MySQL的jdbc驱动,并操作数据库 – 打点 – 博客园 (cnblogs.com)

    • 在IDEA里面创建一个java项目

    img

    • 选择创建Java项目,JDK这里选择1.8,直接Next

    img

    • 勾选按模板创建,Next

    img

    • 输入项目名称和项目地址,Finish

    img

    • 项目创建完成的界面如下

    img

    • 在项目中建一个名为lib(名称建议就用lib)的文件夹

    img

    • 对之前下载来的zip文件进行解压(mysql-connector-java-8.0.18.jar ),并进入解压出来的文件夹

    img

    img

    • 复制其中的mysql-connector-java-8.0.18.jar文件,在lib文件夹上右键,粘贴到IDEA中,刚刚新建的lib文件夹里

    img

    img

    img

让导入的驱动生效

    • 在IDEA中点击 File——Project Structure

    img

    • 其中的 Module 模块,Dependencies 选项卡

    img

    • 点击最右边的加号(+),选择 JARS or directories

    img

    • 在弹出的窗口中选择刚刚导入 lib 文件夹的驱动,点击Ok

    img

    • 可以看到Module模块中,多出了一个mysql驱动,最后点击Apply,然后Ok

    img

 

2. 实现JDBC程序

 

package com.aliyun;
import java.sql.*;
public class demo01 {
    public static void main(String[] args) throws ClassNotFoundException, SQLException {
//      1.加载驱动
        Class.forName("com.mysql.cj.jdbc.Driver"); // 固定写法,加载驱动     通常不需要手动加载驱动程序类

//      2.用户信息和url(网址)  					   库名
        String url = "jdbc:mysql://localhost:3306/jdbcstudy?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC";
//使用统一码        字符编码				MySQL8以上SSL协议为false		时区
        String username = "root";
        String password = "123456";

//      3.连接成功,数据库对象 Connection(连接)代表的是数据库
        Connection connection = DriverManager.getConnection(url,username,password);
//		                        驱动程序管理器						
        
//      4.执行sql的对象 Statement(声明) 执行的sql对象
        Statement statement = connection.createStatement();
        
        
//      5. 执行sql的对象 去 执行sql,可能存在结果,查看返回结果
        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("password="+resultSet.getObject("PASSWORD"));
        }
        //6.释放连接
        resultSet.close();
        connection.close();
        statement.close();
    }
}

 

 

步骤:

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

 

 

3. 分解知识点

URL

"jdbc:mysql://localhost:3306/jdbcstudy[useUnicode]=true&characterEncoding=utf8&useSSL=false&serverTimezone=UTC";
// 协议 ://主机地址:端口号/数据库名?参数1&参数2&参数3

 

Connection

代表数据库

// 事务的提交、回滚,数据库设置自动提交
connection.commit();
connection.rollback();
connection.setAutoCommit();

 

 

Statement 执行SQL的对象

String sql = "SELECT * FROM users";   // 编写SQL

statement.executeQuery(sql);  //查询操作返回ResultSet
statement.execute(sql);       //执行任何SQL
statement.executeUpdate(sql); //更新、插入、删除。都是用这个,返回一个受影响的行树    

 

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

获得指定的数据类型

//在不知道列类型的时候
resultset.getObject();
//在知道列类型的时候
resultset.getInt();
resultset.getString();
resultset.getFloat();
resultset.getDouble();
resultset.get........

 

//遍历
resultSet.next();				// 移动到下一个数据
resultSet.beforeFirst();		// 移动到最前面
resultSet.afterLast();			// 移动到最后面

 

 

4. 通过配置文件,封装成方法调用

C:\Users\86188\IdeaProjects\jdbc 实例代码

【【狂神说Java】MySQL最新教程通俗易懂】https://www.bilibili.com/video/BV1NJ411J79W?p=40&vd_source=4bf637fc1e8a26c5ca8d7829888d0d52

 

封装方法

package com.aliyun.utils;

import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

public class jdbcutils {
    private static String dirver = null;
    private static String url = null;
    private static String username = null;
    private static String password = null;
    static {
        try{
            InputStream in = jdbcutils.class.getClassLoader().getResourceAsStream("db.properites");
            Properties properties = new Properties();
            properties.load(in);

            dirver = properties.getProperty("dirver");
            url = properties.getProperty("url");
            username = properties.getProperty("username");
            password = properties.getProperty("password");

            //1. 驱动只用加载一次
            Class.forName(dirver);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //获取连接
    public static Connection getConnection() throws SQLException {
        return DriverManager.getConnection(url,username,password);
    }

    //释放连接
    public static void release(Connection connection, Statement statement, ResultSet resultSet) {
        if (connection != null) {
            try {
                connection.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (statement != null) {
            try {
                statement.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (resultSet != null) {
            try {
                resultSet.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }
}

 

调用方法

package com.aliyun.utils;

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

public class test {
    public static void main(String[] args) {
        Connection connection = null;
        Statement statement = null;
        ResultSet resultSet = null;
        try {
            connection = jdbcutils.getConnection();
            statement = connection.createStatement();
            String sql = "";   			//sql语句填充
        //根据增删改查,填充不同方法
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            jdbcutils.release(connection,statement,resultSet);
        }

    }
}

 

 

 

10.4 SQL注入

(6条消息) JDBC-Statement_小袁拒绝摆烂的博客-CSDN博客

实际工作一般用PreparedStatement来进行sql语句的执行,因为sql注入的风险

 

 

在这里插入图片描述

在这里插入图片描述

 

 

10.5 PreparedStatement

 

防止SQL注入(推荐使用PreparedStatement)

比较于Statement

  1. PreparedStatement是先写SQL语句,并且将参数用问号?替代

  2. 将SQL语句进行预编译(不执行)

  3. 预编译后通过setObiect(Int、String……)等方法对 问好?进行赋值操作

    注意:setObject()等方法的参数为 (index,obj) index 的数值由1开始依次往后递增

 

C:\Users\86188\IdeaProjects\jdbc\TEST02

package com.aliyun.utils;

import java.sql.*;
import java.util.Date;

public class TEST02 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet re = 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,"zzh");
            st.setString(3,"123456");
            st.setString(4,"1422833206@qq.com");
            st.setDate(5,new java.sql.Date(new Date().getTime()));
            			// 这里将系统的时间戳转换为SQL语句中的时间戳(同时注意Date的导包由来)
            int i = st.executeUpdate();
            if(i>0){
                System.out.println("t");
            }
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            jdbcutils.release(conn,st,re);
        }
    }
}

 

 

 

 

10.6 idea连接数据库

【【狂神说Java】MySQL最新教程通俗易懂】https://www.bilibili.com/video/BV1NJ411J79W?p=43&vd_source=4bf637fc1e8a26c5ca8d7829888d0d52

 

在idea中,我们可以:

  1. 编写sql语句
  2. 修改数据 (修改之后要记得点击DB键)
  3. 查看数据库
  4. ……….

 

 

10.7 事务

 

通过java完成事务

C:\Users\86188\IdeaProjects\jdbc\test03事务

步骤:

  1. 开启事务 conn.setAutoCommit(false);
  2. 一组业务之下完毕,提交事务 conn.commit();
  3. 可以在catch语句中 编写回滚语句conn.rollback();,默认失败回滚
package com.aliyun.utils;

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

public class test03事务 {
    public static void main(String[] args) {
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet re = null;
        try {
            conn = jdbcutils.getConnection();
            //关闭数据库的自动提交,这里会自动开启事务
            conn.setAutoCommit(false);

            String sql1 = "UPDATE account set money = money-500 where NAME = 'A'";
            st = conn.prepareStatement(sql1);
            st.executeUpdate();

            int s = 1/0;    //失败

            String sql2 = "UPDATE account set money = money+500 where NAME = 'B'";
            st = conn.prepareStatement(sql2);
            st.executeUpdate();

            //业务完毕,提交事务
            conn.commit();
            System.out.println("成功");

        } catch (SQLException throwables) {
            //如果失败,默认回滚(下列注释代码可写可不写)
            
            /*try {
                conn.rollback();        // 如果失败回滚
            } catch (SQLException e) {
                e.printStackTrace();
            }*/
            
            throwables.printStackTrace();
        }finally {
            jdbcutils.release(conn,st,re);
        }
    }
}

 

 

 

页面链接:http://www.datazzh.top/?p=446
声明:内容来源个人归纳总结和部分网络素材
观看视频:【狂神说Java】MySQL最新教程通俗易懂
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇