一、数据库的概念
	组织、管理、存储数据的仓库。对数据库主要是增加、删除、修改、查询操作。
	MySQL数据库,免费开源,
	Oracle数据库,收费
	SQL Server数据库,收费,
	Mongodb数据库,
	前三个是传统数据库,又叫关系数据库,或者SQL数据库,
	最后 一个是新型数据库,又叫非关系数据库,或者NOSQL数据库,在一定程度上弥补了传统数据库的缺陷。
	传统数据库组织结构
	数据库、数据表、数据行、字段等4部分组成。
	库、表、行、字段的关系
	一般情况下,每个项目都有独立的数据;
	不同的数据存储在不同的表中;
	每个表中存储信息由字段决定;
	表中的行代表一条具体数据;
	相关MYsql相关软件
	MySQL Server,存储数据存储和服务;
	MySQL workbench,可视化MYSQL管理工具。
二、安装配置数据库
	1、安装数据库
	msi文件包含了数据库与一些相关包。
	通过WorkBench,输入密码即可连接数据库。
	2、创建数据库和表
	进入workbench新建数据库,填写数据库名称,其它信息默认即可快速创建一个数据库;然后在该数据库下创建一个表并添加字段,设置字段类型时如果不能从下拉菜单中选择,则直接手动输入字段类型。其它选项如,PK主键,NN不能为空,NQ值唯一,AI值自动增长。
	3、向表中写入数据
	在表中单击右键,选择第一个命令,在弹出的界面输入表中字段的内容即可。
	4、SQL是一门数据库编程语言;
	使用SQL语言编写的代码叫做SQL语句;
	SQL语言只能在关系数据库中使用。
	5、增加,删除,修改、查询等等操作数据。创建数据库、表、存储过程、视图等。
三、MySQL数据库的使用
	1、SQL语句对大小写不敏感
	-- 1-1使用 * 查询表中所有列的内容
	-- select * from users
	-- 1-2使用列名查询指定列的内容,多个列之间使用逗号隔开
	-- select username,password from users
	-- 2-1 插入数据
	-- insert into users (username,password) values('bailong','bailong123')
	-- 3-1修改id为5的用户的密码为bl123
	-- update users set password = 'bl123' where id = 5
	-- 3-2 修改多个列的属性值,SET后面用逗号隔开即可
	-- update users set password = 'shb123',status = '1' where id = 1
	-- 4-1删除指定内容,一定要添加条件
	-- delete from users where id =1
	2、where子句
	= <> > >= < <= between like
	-- select * from users where  id = 5
	-- select * from users where id <> 5
	-- select * from users where id < 4
	-- select * from users where id <= 4
	-- select * from users where id > 3
	-- select * from users where id >= 3
	select * from users where username like 'twy'
	3、and or 把两个或者多个条件结合起来
	-- select * from users where id = 5 and status = 1
	-- select * from users where id = 3 or status = 1
	4、order by子句
	-- 排序之升序,默认排序规则,或者使用关键字:asc
	-- select * from users order by username asc
	-- 排序之降序,关键字:desc
	-- select * from users order by status desc
	-- 多重排序,需要排序的字段用逗号隔开即可
	-- select * from users order by status asc,username desc
	5、count(*)统计总数
	-- 统计总数 count(*)
	-- select count(*) from users where status = 0
	-- 给列起别名 as
	-- select count(*) as total from users where status = 0
四、在Express中操作MySQL
	1、安装配置SQL
	//1.安装、配置mysql
	const mysql = require('mysql')
	const db = mysql.createPool({
	    host: '127.0.0.1',
	    user: 'root',
	    password: 'root',
	    database: 'my_db_01'
	})
	2、测试SQL是否正常工作
	//2.测试mysql是否可以正常工作
	db.query('select 1',(err,res) => {
	    if(err) return console.log(err.message);
	    console.log(res);
	})
	3、查询数据
	//3.查询数据库中的数据,如果执行的是select语句,返回的是一个数组
	db.query('select * from users',(err,res) => {
	    if(err) return console.log(err.message);
	    console.log(res);
	})
	4、插入数据
	//4-1.插入数据普通方法
	const user = {username: '京城小白龙',password: 'jc123'}
	const sqlstr = 'insert into users (username,password) values(?,?)'
	db.query(sqlstr,[user.username,user.password],(err,res) => {
	    if(err) return console.log(err.message);
	    if(res.affectedRows === 1) {console.log('插入数据成功');}
	})
	//4-2插入数据快捷方法
	const user2 = {username: '京城小白龙2',password: 'jc123888'}
	const sqlstr2 = 'insert into users set ?'
	db.query(sqlstr2,user2,(err,res) => {
	    if(err) return console.log(err.message);
	    if(res.affectedRows === 1) {console.log('插入数据成功');}
	})
	5、更新数据
	//5-1更新数据普通方式,定义更新数据
	const user33 = {id: 5,username: 'A',password: 'B'}
	//5-2定义SQL语句
	const sqlstr33 = 'update users set username = ?,password = ? where id = ?'
	//5-3执行SQL语句
	db.query(sqlstr33,[user33.username,user33.password,user33.id],(err,res) => {
	    if(err) return console.log(err.message);
	    if(res.affectedRows === 1) {
	        console.log('更新数据成功');
	    }
	})
	//更新数据的快捷方式
	const user33 = {id: 19,username: 'abc',password: 'def'}
	const sqlstr33 = 'update users set ? where id = ?'
	db.query(sqlstr33,[user33,user33.id],(err,res) => {
	    if(err) return console.log(err.message);
	    if(res.affectedRows === 1) {
	        console.log('更新数据成功');
	    }
	})
	6、删除数据
	//6-1删除数据,从表中真正的删除数据,比较危险,不建议使用
	const sqlStr = 'delete from users where id = ?'
	//当只有一个问号?点位符时,可以活力数组,直接写值;当有多个问号?点位符时,必须用数据传递数值
	db.query(sqlStr,16,(err,res) => {
	    if(err) return console.log(err.message);
	    if(res.affectedRows === 1) {
	        console.log('删除成功');
	    }
	})
	//6-2标记删除,是把status字段的值修改1,标记为删除,不是真正的删除,比较安全,建议使用
	const sqlStr = 'update users set status = ? where id = ?'
	db.query(sqlStr,[1,6],(err,res) => {
	    if(err) return console.log(err.message);
	    if(res.affectedRows === 1) {
	        console.log('标记删除成功');
	    }
	})
五、前后端身份认证
	web开发模式
	基于服务端渲染的传统开发模式
	服务器发送给客户端的HTML页面,是在服务器通过字符串拼接,动态生成。因此,客户端不需要使用ajax技术额外请求页面数据。优点是:前端耗时少,利于SEO。缺点是:占用服务器资源,不利于前后端分离。一般使用session认证。
	基于前后端分离的开发模式
	依赖于ajax技术的广泛应用,就是后端只负责API接口,前端调用接口的开发模式。
	优点:开发体验好,前端侧重于体验,后端侧重于接口;减轻了服务器端的渲染压力。缺点:不利于SEO,利于SSR技术解决SEO问题。一般使用JWT认证。
	不谈业务场景盲目的使用何种开发模式都是耍流氓。
	企业站,使用利于SEO的服务器端渲染的开发模式;后台项目管理类项目,建议使用前后端分离。另外,如果两者都考虑,则建议首页用服务器端渲染,其它页面使用前后端分离。
	HTTP协议无状态性
	客户端的每次HTTP请求都是独立的,连续多个请求之间没有直接的关系,服务器不会主动保留每次HTTP请求的状态。
	如何突破HTTP的无状态的限制
	类似会员卡身份认证的方式,在WEB开发中的专业术语叫cookie。
	存储在用户浏览器中的不超过4K的字符串,它由一个名称,一个值和其它用于控制cookie的有效期,安全性,使用范围等属性组成。
	COOKIE是各自独立,用户访问请求时,会自动把当前域名下的所有未过期的COOKIE一同发送给服务器。
	自动发送、域名独立、过期时限、4KB限制。
	cookie在身份认证中的作用
	客户端第一次请求服务器的时候,服务器通过响应头的形式,向客户端发送一个身份认证的cookie,客户端会自动将cookie保留在浏览器中。
	随后,当客户端浏览器每次请求服务器的时候,浏览器会自动将身份认证相关的cookie,通过请求头部的形式发送给浏览器,服务器即可验明客户端的身份。
	cookie不具有安全性
	浏览器提供了读写cookie的API,因此,cookie很容易被伪造。不建议服务器将重要的隐私数据,通过cookie的形式发送给客户端浏览器。
	提高身份认证的安全性
	服务器端验证,确认存在即安全。
	1、session工作原理
	客户端与服务器之间,请求与响应的过程中,通过对比客户端中的cookie与服务器中的cookie,来验证用户身份。
	在express中使用session中间件
	// TODO_01:请配置 Session 中间件
	const Session = require('express-session')
	app.use(
	  session({
	    secret: 'bailong',
	    resave: false,
	    saveUninitialized: true
	  })
	)
	  // TODO_02:请将登录成功后的用户信息,保存到 Session 中
	  req.session.user = req.body
	  req.session.islogin = true
	  // TODO_03:请从 Session 中获取用户的名称,响应给客户端
	  if(!req.session.islogin) {
	    return res.send({
	      status: 1,
	      msg: 'fail'
	    })
	  }
	  session.send({
	    status: 0,
	    msg: 'success',
	    username: req.session.user.username
	  })
	})
	  // TODO_04:清空 Session 信息
	  req.session.destroy()
	  res.send({
	    status: 0,
	    msg: '退出登陆成功'
	  })
	2、jwt在express生成token
	// TODO_01:安装并导入 JWT 相关的两个包,分别是 jsonwebtoken 和 express-jwt
	const jwt = require('jsonwebtoken')
	const expressJWT = require('express-jwt')
	// TODO_02:定义 secret 密钥,建议将密钥命名为 secretKey
	const secretKey = 'bailong.org.cn ^_^'
	// TODO_04:注册将 JWT 字符串解析还原成 JSON 对象的中间件
	// 注意:只要配置成功了 express-jwt 这个中间件,就可以把解析出来的用户信息,挂载到 req.user 属性上
	app.use(expressJWT({ secret: secretKey }).unless({ path: [/^\/api\//] }))
	// TODO_03:在登录成功之后,调用 jwt.sign() 方法生成 JWT 字符串。并通过 token 属性发送给客户端
	  // 参数1:用户的信息对象
	  // 参数2:加密的秘钥
	  // 参数3:配置对象,可以配置当前 token 的有效期
	  // 记住:千万不要把密码加密到 token 字符中
	  const tokenStr = jwt.sign({ username: userinfo.username }, secretKey, { expiresIn: '30s' })
	  res.send({
	    status: 200,
	    message: '登录成功!',
	    token: tokenStr, // 要发送给客户端的 token 字符串
	  })
	})
	// 这是一个有权限的 API 接口
	app.get('/admin/getinfo', function (req, res) {
	  // TODO_05:使用 req.user 获取用户信息,并使用 data 属性将用户信息发送给客户端
	  console.log(req.user)
	  res.send({
	    status: 200,
	    message: '获取用户信息成功!',
	    data: req.user, // 要发送给客户端的用户信息
	  })
	})
	// TODO_06:使用全局错误处理中间件,捕获解析 JWT 失败后产生的错误
	app.use((err, req, res, next) => {
	  // 这次错误是由 token 解析失败导致的
	  if (err.name === 'UnauthorizedError') {
	    return res.send({
	      status: 401,
	      message: '无效的token',
	    })
	  }
	  res.send({
	    status: 500,
	    message: '未知的错误',
	  })
	})