目录
- 数据库与身份认证
- 数据库的基本概念
- 常见数据库和分类
- 传统型数据库的数据组织结构
- 安装并配置MySQL
- MySQL的基本使用
- 使用SQL管理数据库
- SQL中的SELECT语句
- SQL中的INSERT INTO语句
- SQL中的UPDATE语句
- SQL中的DELETE语句
- SQL中的WHERE子句
- SQL中的AND和OR运算符
- SQL中的ORDER BY子句
- SQL中的COUNT(*)函数
- 在项目中操作数据库
- 安装步骤:
- 使用mysql模块操作数据库
- 前后端的身份认证
- Web开发模式
- 身份认证
- Session认证机制
- 在Express中使用Session认证
- JWT认证机制
数据库与身份认证
数据库的基本概念
数据库是用来组织、存储和** **数据的仓库
常见数据库和分类
- MySQL数据库(最广泛、流行度最高)
- Oracle数据库(收费)
- SQLserver数据库(收费)
- Mongodb数据库
其中前三种属于传统型数据库(也叫关系型数据库、SQL数据库),Mongodb属于新型数据库(也叫非关系型数据库、NoSQL数据库),一定程度上弥补了传统型数据库的缺陷
传统型数据库的数据组织结构
-
Excel的数据组织结构
-
传统型数据库的数据组织结构
从大到小分为数据库、数据表、数据行、字段
数据库类似Excel工作簿,数据表类似Excel工作表,数据行类似Excel每一行数据,字段类似Excel的列 -
实际开发中库、表、行、字段的关系
① 实际开发中,一般每个项目对应独立的数据库
② 不同数据要存储到数据库的不同表中
③ 每个表中存哪些信息由字段决定,eg:为user表设计id、username、password字段
④ 表中的行代表每一条具体的数据
安装并配置MySQL
- MySQL Server:专门用来提供数据存储和服务的软件
- MySQL Workbench:可视化的MySQL管理工具,方便操作存储在MySQL Server中的数据
在windows环境下运行nysql-installer-community-8.0.19.msi
就能依次安装两个软件
MySQL的基本使用
数据类型:① INT 整数 ② VARCHAR(len) 字符串 ③ TINYINT(1) 布尔值
字段的特殊标识:① PK 主键、唯一标识 ② NN 值不允许为空 ③ UQ 值唯一 ④ AI 值自动增长
使用SQL管理数据库
① SQL是一门数据库编程语言 ② 使用SQL语言编写出的代码,叫SQL语句 ③ SQL只能在关系型数据库中使用
SQL中的SELECT语句
SELECT语句用于从表中查询数据,执行的结果被存储在一个结果表中(称为结果集)
语法:
-- 这是注释
-- 从FROM指定的【表中】,查询出【所有的】数据,*表示【所有列】
SELECT * FROM 表名称
-- 从FROM指定的【表中】,查询出【指定列】名称(字段)的数据,多个列之间【用逗号隔开】
SELECT 列名称 FROM 表名称
【注意】:SQL语句的关键字不区分大小写,select等效SELECT
SQL中的INSERT INTO语句
INSERT INTO语句用于向数据表中插入新的数据行
语法:
-- 语法解读:向指定的表中,插入如下几列数据,列的值通过values指定
-- 注意:列和只要一一对应,多个列和多个值之间用逗号隔开
INSERT INTO table_name (列1,列2...) VALUES (值1,值2...)
SQL中的UPDATE语句
UPDATE语句用于修改表中的数据,注意:不加where则会修改所有数据
语法:
-- 1. 用UPDATE指定要更新哪个表中的数据
-- 2. 用SET指定列对应的新值
-- 3. 用WHERE指定更新的条件
UPDATE 表名称 SET 列名称 = 新值 WHERE 列名称 = 某值
SQL中的DELETE语句
DELETE语句用于删除表中数据行,注意:不加where则会删除所有数据
语法:
-- 从指定的表中根据WHERE条件,删除对应的数据行
DELETE FROM 表名称 WHERE 列名称=值
SQL中的WHERE子句
WHERE子句用于限定选择的标准,在SELECT、UPDATE、DELETE语句中均可使用
WHERE 列 运算符 值
运算符:
SQL中的AND和OR运算符
AND和OR可以在WHERE子句中把多个条件结合起来
AND表示必须同时满足多个条件,相当于&&
OR表示任意满足一个条件,相当于||
SQL中的ORDER BY子句
用于根据指定列对结果集进行排序
默认升序排序,ASC表示升序,降序可使用DESC关键字
eg:select * from users order by status desc
多重排序:
-- 先按照status降序排序,再按照username字母顺序升序排序
select * from users order by status desc, username asc
SQL中的COUNT(*)函数
- 用于返回查询结果的总数据条数
语法:SELECT COUNT(*) FROM 表名称
- 使用AS关键字为列设置别名
语法:SELECT COUNT(*) AS 别名 FROM 表名称
select username as name,password from users
在项目中操作数据库
安装步骤:
- 安装操作MySQL数据库的第三方模块(mysql)
- 通过mysql模块连接到数据库
- 通过mtsql模块执行sql语句
配置mysql模块:
测试mysql模块能否正常工作:
使用mysql模块操作数据库
- 查询数据
// 查询users表中所有数据
const sqlStr = 'select * from users'
db.query(sqlStr, (err, result) => {
if (err) {
// 查询失败
console.log(err.message);
return
} else {
// 查询成功
console.log(result);
}
})
【注意】:如果执行的是select语句,则输出结果为数组
2. 插入数据
// 向users表中新增一条数据,username:Spider-man,password:pcc123
const user = { username: 'Spider-man', password: 'pcc123' }
// 定义待执行的sql语句
const sqlStr = 'insert into users (username,password) values (?,?)'
// 执行sql语句
db.query(sqlStr, [user.username, user.password], (err, result) => {
if (err) {
return console.log(err.message);
}
if(result.affectedRows === 1){
console.log('插入数据成功!');
}
})
如果数据对象的每一个属性和数据表中的字段一一对应,则有以下简便方式
const user = { username: 'Spider-woman', password: 'pcc345' }
const sqlStr = 'insert into users set ?'
db.query(sqlStr, user, (err, result) => {
if (err) {
return console.log(err.message);
}
if (result.affectedRows === 1) {
console.log('插入数据成功!');
}
})
【注意】:① 如果执行的是insert语句,则result是一个对象,可以通过affectRows属性来判断是否插入数据成功 ② ?表示占位符,当有多个占位符时,用数组形式插入具体数据,如果只有一个占位符,则不需要用数组
3. 更新数据
// 要更新的数据对象
const user = { id: 8, username: 'aaa', password: '00000' }
// 定义sql语句
const sqlStr = 'update users set username=?, password=? where id=?'
// 执行sql语句
db.query(sqlStr, [user.username, user.password, user.id], (err, result) => {
if (err) {
return console.log(err.message);
}
if (result.affectedRows === 1) {
console.log('更新数据成功!');
}
})
如果数据对象的每一个属性和数据表中的字段一一对应,则有以下简便方式
const user = { id: 6, username: 'bbb', password: '00000' }
// 定义sql语句
const sqlStr = 'update users set ? where id=?'
// 执行sql语句
db.query(sqlStr, [user, user.id], (err, result) => {
if (err) {
return console.log(err.message);
}
if (result.affectedRows === 1) {
console.log('更新数据成功!');
}
})
【注意】:如果执行的是updatet语句,则result是一个对象,可以通过affectRows属性来判断是否更新数据成功
4. 删除数据
推荐使用id删除
// 要执行的sql语句
const sqlStr = 'delete from users where id=?'
db.query(sqlStr, 8, (err, result) => {
if (err) {
return console.log(err.message);
}
if (result.affectedRows === 1) {
console.log('删除数据成功!');
}
})
【注意】:① 如果执行的是delete语句,则result是一个对象,可以通过affectRows属性来判断是否插入数据成功
5. 标记删除
使用delete语句,会把真正的数据从表中删除,无法找回,那么可以使用标记删除的形式,模拟删除的动作
例如通过设置status状态字段,来标记这条数据是否被删除
const sqlStr = 'update users set status=? where id=?'
db.query(sqlStr, [1, 6], (err, result) => {
if (err) {
return console.log(err.message);
}
if(result.affectedRows === 1){
console.log('更新状态成功');
}
})
前后端的身份认证
Web开发模式
主流有两种
- 基于服务器端渲染的传统web开发模式
服务器发送给客户端的html页面是服务器通过字符串拼接动态生成的,因此客户端不需要使用Ajax这样的技术额外请求页面的数据
优点:① 前端耗时少 ② 有利于SEO,爬虫更易获取信息
缺点:① 占用服务器端资源 ② 不利于前后端分离,开发效率低 - 基于前后端分离的新型web开发模式
依赖Ajax技术,后端只负责提供api接口,前端使用Ajax调用接口
优点:① 开发体验好 ② 用户体验好 ③ 减轻服务器端的渲染压力
缺点:不利于SEO - 如何选择开发模式
例如企业级网站,主要功能是展示而没有复杂的交互,则用服务器端渲染
类似后台管理项目,交互性比较强,不需要考虑seo,则用前后端分离
身份认证
身份认证指通过一定手段完成对用户身份的确认,例如手机验证码,二维码登录
服务端渲染使用Session认证机制,前后端分离使用JWT认证机制
Session认证机制
-
http协议的无状态性,客户端每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留HTTP请求状态
-
如何突破http无状态的限制
【注意】:现实生活中会员卡身份认证方式在web开发中称为Cookie
-
什么是Cookie
Cookie是存储在用户浏览器中的一段不超过4kb的字符串,由一个名称、一个值、和其他几个Cookie有效期、安全性、适用范围的可选属性组成
不同域名下的Cookie各自独立,每当客户端发起请求时,会自动把当前域名下所有未过期的Cookie一同发送到服务器
Cookie的特性:① 自动发送 ② 域名独立 ③ 过期时限 ④ 4kb限制 -
Cookie在身份认证中的作用
客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的Cookie,客户端会自动将Cookie保存在浏览器中
随后,当客户端每次请求服务器的时候,浏览器会自动将身份认证相关的Cookie,通过请求头的形式发送给服务器,服务器即可验明客户端的身份
-
Cookie不具有安全性
Cookie存储在浏览器中,浏览器也提供了读写Cookie的API,因此Cookie容易被伪造,不能用Cookie存储用户隐私数据 -
提高身份认证的安全性
类似会员卡在收音机上刷卡认证
会员卡+刷卡认证是Session认证机制的精髓 -
Session工作原理
在Express中使用Session认证
-
安装express-session中间件
npm i express-session
-
配置express-session中间件,通过app.use()注册中间件
-
向session中存数据
配置成功书,通过req.session访问和使用session对象
-
从session中取数据
-
清空session
调用req.session.destroy
JWT认证机制
Session认证机制需要配合Cookie才能实现,Cookie不支持跨域访问
【注意】:① 当前端请求后端接口不存在跨域问题时,推荐使用Session ② 当前端需要跨域请求接口时,推荐JWT
- 什么是JWT
目前最流行的跨域认证解决机制 - JWT工作原理
【总结】:用户的信息通过token字符串的形式保存在客户端浏览器,服务器通过还原Token字符串的形式来认证用户身份
3. JWT组成部分
Header头部、Payload有效荷载、Signature签名,这三部分之间使用英文的.
分割
格式:Header.Payload.Signature
其中,Payload部分是真正的用户信息,是用户信息加密之后生成的字符串,Header和Signature是安全性相关的部分
4. JWT使用方式
客户端收到服务器返回的JWT之后,通常会将它储存在localStorage或sessionStorage中,此后,客户端每次与服务器通信,都要带上这个JWT的字符串,从而进行身份认证。推荐的做法是把JWT放在HTTP请求头的Authorization字段中
语法:Authorization: Bearer <token>