• 数据库与Socket学习


    一、MongoDB

    Node 操作JSON 数据方便,MongoDB 采用 JSON 方式存储,查询速度快。

    1.1 关系型与非关系型数据库

    1.1.1 关系型数据库

    MySQL、SQL Server、DB2、Oracle

    特点:
    1)使用 sql 语句增删改查操作
    2)操作之前都要设计表结构

    1.1.2 非关系型数据库

    MongoDB、Hbase、Redis

    特点:
    1)no sql
    2)轻量、高效、自由,有些就是 key-value 对

    1.2 下载与安装

    下载链接
    安装步骤

    运行 MongoDB 服务器,必须从 MongoDB 目录的 bin 目录中执行 mongod.exe 文件

    • mongod.exe 是服务器,需先启动
    • mongo.exe 是客户端,等服务器启动就可以连接
    # 创建数据库、表都在 D:\MongoDB\data\db 这个目录下,必须以管理员身份运行
    D:\mongodb\bin\.\mongod.exe --dbpath=D:\MongoDB\data\db
    
    • 1
    • 2

    1.3 命令行操作

    1.3.1 查看命令

    # 帮助
    help
    db.help()
    db.test.help()
    db.test.find().help()
    
    # 查看所有数据库名称
    show dbs
    
    # 查看当前使用的数据库
    db
    db.getName()
    
    # 查看当前 db 状态
    db.stats()
    
    # 查看当前 db 的所有集合
    db.getCollectionNames()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    1.3.2 操作数据库命令

    # 创建/切换数据库
    use [name]
    
    # 创建集合,至少有一个集合才能被 show dbs 查看
    db.createCollection([name])
    
    # 删除当前数据库
    db.dropDatabase()
    
    # 删除集合
    db.[name].drop()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    1.3.3 操作集合命令

    假设操作 users 集合

    # 插入数据
    db.users.save([data])
    
    # 查询所有数据
    db.users.find()
    
    # 查询第一条数据
    db.users.findOne()
    
    # 查询 age: 18 的数据
    db.users.find({ age: 18 })
    
    # 查询 age 大于 18 的数据,小于是 $lt
    db.users.find({ age: {$gt: 18} })
    
    # 查询 age 大于等于 18 的数据
    db.users.find({ age: {$gte: 18} })
    
    # 查询 age 大于等于 18, 小于等于 100 的数据
    db.users.find({ age: {$gte: 18, $lte: 100} })
    
    # 查询出 age 字段的数据(包含主键 _id,其他数据不显示)
    db.users.find({}, { age: 1 })
    
    # 查询出 age 字段的数据(不包含主键 _id,其他数据不显示)
    db.users.find({}, { age: 1, _id: 0 })
    
    # 升序排列,倒序排列
    db.users.find().sort({ age: 1 })
    db.users.find().sort({ age: -1 })
    
    # 分页查询, skip 是跳过多少数据,limit 是取多少数据
    db.users.find().skip([page] * [pageSize]).limit([pageSize])
    
    # 查询 name 包含 k 的数据,传正则
    db.users.find({ name: /k/ })
    
    # 查询 age: 18 或 age: 100 的数据
    db.users.find({ $or: [{age: 18}, {age: 100}] })
    
    # 查询数据条数
    db.users.find().count()
    
    # 删除数据,删除所有 age: 100 的数据
    db.users.remove({ age: 100 })
    
    # 删除所有数据
    db.users.remove({})
    
    # 更新数据,{ age: 18 } 替换 { name: 'zs' } 的数据
    db.users.update({ name: 'zs' }, { age: 18 })
    
    # 更新数据,{ name: 'zs' } 的数据修改
    db.users.update({ name: 'zs' }, {$set: { age: 18 }})
    
    # 更新数据,{ name: 'zs' } 的数据修改,age 字段 +10 
    db.users.update({ name: 'zs' }, {$inc: { age: 10 }})
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    1.4 node 操作 MongoDB

    npm i mongoose

    1.4.1 连接数据库

    1)连接数据库

    // 1. db.config.js
    const mongoose = require('mongoose')
    
    // 127.0.0.1:27017 是数据库地址,express_project 是数据库名称(插入数据时会自动创建)
    mongoose.connect('mongodb://127.0.0.1:27017/express_project')
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2)入口文件引入 db.config.js

    // 2. app.js
    require('./db.config')
    
    • 1
    • 2

    3)创建模型(集合)

    // 3. model/UsersModel.js
    const mongoose = require('mongoose')
    
    // 限制集合类型
    const Schema = mongoose.Schema
    
    const UserType = {
      name: String,
      password: String,
      age: Number
    }
    
    // 创建模型 user, 数据库将会对应 users
    const UserModel = mongoose.model('user', new Schema(UserType))
    
    module.exports = UserModel
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    4)操作数据库

    const UserModel = require('../model/UserModel')
    
    // 4. 假设发送了一个 post 请求创建数据
    router.post('/add', function(req, res) {
      const { name, password, age } = req.body
      // 增 删 改 查/UserModel.create UserModel.delete UserModel.update UserModel.find
      UserModel.create({
        name,
        password,
        age
      }).then(data => {
        console.log(data)
      })
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    1.4.2 操作数据库

    1)增

    const UserModel = require('../model/UserModel')
    
    // 创建一条数据
    const name = '张三'
    const password = 123
    UserModel.create({
      name,
      password
    }).then(data => {
      // data 是新创建好的数据
      console.log(data)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    2)删

    const UserModel = require('../model/UserModel')
    
    // 删除 _id 匹配上的一条数据
    UserModel.deleteOne({ _id: '62b2af3f39a05443d53b02b8' }).then(data => {
      console.log(data)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    3)改

    const UserModel = require('../model/UserModel')
    
    // 更新 _id 匹配上的一条数据
    UserModel.updateOne({ _id: '62b2af3f39a05443d53b02b8' },{
      name: '李四',
      password: 123456
    }).then(data => {
      console.log(data)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    4)查

    const UserModel = require('../model/UserModel')
    
    // 查询所有数据
    UserModel.find().then(data => {
      console.log(data)
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    二、Cookie 与 Session

    1)下载 express-session
    npm i express-session

    2)引入 express-session

    // 入口文件 app.js
    var express = require('express')
    var expressSession = require('express-session')
    var MongoStore = require('connect-mongo')
    
    var indexRouter = require('./routes/index')
    
    var app = express()
    
    // 注册 session 中间件,放在注册路由前面
    app.use(expressSession({
      name: 'user', // 下发给客户端的 cookie 名
      secret: 'session', // 服务器生成的 session 签名,也就是密钥
      resave: true, // 设置为 true 表示重新设置 session 对象后会重新计算过期时间
      saveUninitialized: true, //  设置为 true 表示刚开始就会下发一个 cookie,但是需要与服务器通信后才有效
      cookie: {
        maxAge: 1000 * 60 * 60, // cookie 过期时间,这里为一小时
        secure: false, // 为 true 时只有 https 协议才能通过 document.cookie 访问
      },
      // rolling: true, // 为 true 时表示超时前刷新,cookie 会重新计时;false 表示超时前刷新多少次,都按第一次刷新开始计时
      store: MongoStore.create({
        mongoUrl: 'mongodb://127.0.0.1:27017/express_session', // 新建一个数据库存放 session
        ttl: 1000 * 60 * 60, // cookie 过期时间,跟 maxAge 一致
      })
    }))
    
    app.use('/', indexRouter)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    3)登录成功设置 session

    // 登录接口,req.session 是自动匹配 cookie 生成的对象,不同浏览器生成 session 的对象不同
    router.post('/login', function(req, res) {
      const { name, password } = req.body
      // 成功,req.session 添加一个字段记录已登录 例如添加 user 字段
      req.session.user = true
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    4)设置中间件,session 过期校验

    app.use((req, res, next) => {
      // login 相关路由
      if (req.url.includes('/login')) {
        next()
        return
      }
    
      // 校验是否有 cookie
      if (req.session.user) {
        // 重新设置 session 对象,刷新过期时间
        req.session.user = Date.now()
        next()
      } else {
        // 如果是接口就返回错误码,如果是路由就重定向 login 页面
        req.url.includes('/add') ? res.status(401).send({ ok: -1 }) : res.redirect('/login')
      }
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    三、Json Web Token(JWT)

    npm i jsonwebtoken

    const jwt = require('jsonwebtoken')
    
    // 加密。第一个参数是加密数据 第二个参数是密钥 第三个参数设置过期时间
    const token = jwt.sign({
      name: 'admin'
      // expiresIn 支持 1h 1d 写法
    }, 'anydata', { expiresIn: '10s' })
    
    // 解密。第一个参数是加密数据 第二个参数是密钥(需跟加密密钥一致)
    const decoded = jwt.verify(token, 'anydata')
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    四、MySQL

    4.1 连接 MySQL

    npm i mysql2

    const express = require('express')
    const mysql2 = require('mysql2')
    
    const app = express()
    
    app.get('/', async (req, res) => {
      // 创建连接池
      const dbConfig = getDBConfig()
      const promisePool = mysql2.createPool(dbConfig).primise()
      // sql 查询
      const users = await promisePool.query('select * from students')
      console.log(users[0])
      res.send({ 
        code: 0,
        data: users[0]
      })
    })
    
    // 数据库信息
    function getDBConfig() {
      return {
        host: '127.0.0.1', // 地址
        port: 3306, // 端口
        user: 'root', // 账号
        password: '123', // 密码
        database: 'tset', // 数据库名
        connectionLimit: 1 // 1 个连接池
      }
    }
    
    app.listen(3000)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    五、Socket

    5.1 介绍

    应用场景:

    • 弹幕
    • 聊天
    • 协同编辑
    • 基于位置的应用
    • 体育实况更新
    • 股票基金报价实时更新

    建立连接:

    WebSocket 连接必须由浏览器发起,因为请求协议是一个标准的 HTTP 请求,格式如下:

    GET ws://localhost:3000/ws/chat HTTP/1.1
    Host: localhost
    Upgrade: websocket
    Connection: Upgrade
    Origin: http://localhost:3000
    Sec-webSocket-Key: client-random-string
    Sec-webSocket-Version: 13
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    该请求和普通的HTTP请求有几点不同:

    1. GET请求的地址不是类似/path/,而是以ws:// 开头的地址
    2. 请求头Upgrade: websocketConnection: Upgrade表示这个连接将要被转换为WebSocket连接
    3. Sec-webSocket-Key是用于表示这个连接,并非用于加密数据
    4. Sec-webSocket-Version指定了WebSocket的协议版本

    如果服务器接受该请求,就会返回如下响应:

    HTTP/1.1 101 Switching Protoclos
    Upgrade: websocket
    Connection: Upgrade
    Sec-WebSocket-Accept: server-random-string
    
    • 1
    • 2
    • 3
    • 4

    响应码 101 表示本次连接的HTTP协议即将被更改,更改后的协议就是 Upgrade: websocket指定的WebSocket协议

    5.2 ws 模块

    npm i ws

    5.2.1 简易聊天室

    1)客户端

    // 连接socket服务器
    const ws = new WebSocket('ws://localhost:8080?token=XXX')
    
    ws.onopen = function () {
      console.log('socket 连接成功')
      ws.send('给服务器发送消息')
    }
    
    // 监听服务器发送消息
    ws.onmessage = function (messageInfo) {
      console.log(messageInfo.data)
    }
    
    ws.onerror = function () {
      console.log('socket 连接失败')
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    2)服务端

    const express = require('express')
    
    const app = express()
    app.use(express.static('public'))
    
    app.get('/', (req, res) => {
      res.send('index')
    })
    
    app.listen(3000)
    
    // 创建 socket 服务器
    const WebSocket = require('ws')
    const WebSocketServer = WebSocket.WebSocketServer
    
    const wss = new WebSocketServer({ port: 8080 })
    
    wss.on('connection', function connection(ws, req) {
      // req 是请求体,客户端可以携带用户token进行校验
      const url = new URL(req.url, 'http://127.0.0.1:3000')
      console.log(url.searchParams.get('token'))
      // 监听客户端传过来的消息
      ws.on('message', function message(data, isBinary) {
        console.log('received: %s', data)
    
        // 一个客户端 WebSocket 广播到所有其他连接的 WebSocket 客户端,不包括它自己
        wss.clients.forEach(function each(client) {
          if (client !== ws && client.readyState === WebSocket.OPEN) {
            client.send(data, { binary: isBinary })
          }
        })
      })
    
      // 给客户端发送消息
      ws.send('给客户端发送消息')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    5.3 socket.io 模块

    npm i socket.io

  • 相关阅读:
    Windows内的Ubuntu虚拟机安装docker
    【OpenCV】基于cv2的图像阈值化处理【超详细的注释和解释】掌握基本操作
    【Python】《Python编程:从入门到实践 (第2版) 》笔记-Chapter2-变量和简单数据类型
    查看linux开发板的CPU频率
    spring mvc的后台代码中如何返回404页面呢?
    远程小组软件开发过程(2):工具
    牛客 ( 计算几何
    Python 编程基础 | 第二章-基础语法 | 2.2、变量
    VMware vcenter/ESXI系列漏洞总结
    基于SpringBoot实现自动装配返回属性
  • 原文地址:https://blog.csdn.net/weixin_44257930/article/details/125386433