前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >持久化储存(一)

持久化储存(一)

作者头像
一粒小麦
发布2019-07-18 18:57:24
3.7K0
发布2019-07-18 18:57:24
举报
文章被收录于专栏:一Li小麦一Li小麦

十多年前,高一的体育老师说过一句很每个时刻都会有所回味的话:

年轻靠爆发力,老了以后靠持久力。

之前的示例项目具有最明显的是:没有一个很好的持久化储存数据的途径。

本文介绍的是fs储存,mysql和sequelize。

fs 储存

现在就来完整实践一个fs-db操作库。需求如下:

  • 读取
  • 写入
代码语言:javascript
复制
// 根据属性获取数据
const getDataByProp = (prop) => {
    return fs.readFile(file, (err, data) => {
        if (!err) {
            data = JSON.parse(data);
            return data[prop];
        } else {
            console.log('读取失败!')
        }
    })
}

// 设置属性值
const setDataByProp = (prop, value) => {
    fs.readFile(file, (err, data) => {
        if (!err) {
            data = JSON.parse(data);
            data[prop] = value;
            data = JSON.stringify(data);

            fs.writeFile(file, data, (_err) => {
                if (!_err) {
                    console.log('写入成功!')
                } else {
                    console.log('写入失败')
                }
            })
        } else {
            console.log('读取失败')
        }
    })
}

读取和写入都比较简单。再实现一个命令行版的,允许命令行查询。

代码语言:javascript
复制
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

rl.on("line", input => {
    const [op, key, value] = input.split(" ");
    if (op === 'get') {
        get(key)
    } else if (op === 'set') {
        set(key, value)
    } else if (op === 'quit') {
        rl.close();
    } else {
        console.log('没有该操作');
    }
});

rl.on("close", function () {
    console.log("程序结束");
    process.exit(0);
});

MySql

用docker安装非常方便(Mac):

https://yeasy.gitbooks.io/docker_practice/install/mac.html

https://yeasy.gitbooks.io/docker_practice/container/run.html

基本原生操作

sql语句对前端来说,看这个就足够了:

https://www.runoob.com/sql/sql-tutorial.html

连接

安装mysql2,它提供了一套相当不错的ES7写法。

代码语言:javascript
复制
// 原生使用mysql
setTimeout(async () => {
    const mysql = require('mysql2/promise');
    const cfg = {
        host: 'localhost',
        user: 'root',
        password: '12345678',
        database: 'djtao'
    }
    const connection = await mysql.createConnection(cfg);

});
新建表
代码语言:javascript
复制
// sql语句
    const CREATE_SQL = `CREATE TABLE IF NOT EXISTS test (
    id INT NOT NULL AUTO_INCREMENT,
    message VARCHAR(45) NULL,
    PRIMARY KEY (id))`;  

    // 新建表
    let ret = await connection.execute(CREATE_SQL);
    console.log('create',ret)

打印出来了。发现新建了一个表

增加行

继续输入

代码语言:javascript
复制
// 插入表
        const INSERT_SQL = `INSERT INTO test(message) VALUES(?)`;
    ret = await connection.execute(INSERT_SQL,['hello']);
    console.log('insert',ret);

新增了一条数据。id作为主键,是自增的。因此不需要理他。

查询行

继续输入

代码语言:javascript
复制
// 查询表
    const SELECT_SQL = `SELECT * FROM test`;
    const [rows,fileds] = await connection.execute(SELECT_SQL);
    console.log('select',rows);
修改行
代码语言:javascript
复制
const UPDATE_SQL=`UPDATE test SET  message='hi' WHERE id=1`
    await connection.execute(UPDATE_SQL)

把id为1的message改为了hi

删除行
代码语言:javascript
复制
// 删除行
    const DEL_SQL=`DELETE FROM test WHERE message='hello'`;
    await connection.execute(DEL_SQL);

所有hello的都被删除了。

SQL中间件:Sequelize

Sequelize是一款基于Nodejs功能强大的异步ORM框架。说白了就是对sql语句的封装。 同时支持PostgreSQL, MySQL, SQLite and MSSQL多种数据库,很适合作为Nodejs后端数据库的存储接口,为快速开发Nodejs应用奠定扎实、安全的基础。 既然Nodejs的强项在于异步,没有理由不找一个强大的支持异步的数据库框架,与之配合。

http://docs.sequelizejs.com/

代码语言:javascript
复制
// sequelize.js
(async ()=>{
    const Sequelize=require('sequelize');

    // 建立连接
    const sequelize=new Sequelize('djtao',`root`,`12345678`,{
        host:'localhost',
        dialect:'mysql', //方言
        operatorsAliases:false //操作符别名,不允许
    });

    // 6定义模型
    const Fruit =sequelize.define('Fruit',{
        name:{type:Sequelize.STRING(20),allowNull:false},
        price:{type:Sequelize.FLOAT,allowNull:false},
        stock:{type:Sequelize.INTEGER,defaultValue:0}
    });


    // 同步数据库
    let ret=await Fruit.sync();
    console.log('sync',ret)
})()

发现生成了一个数据表:

包括模型定义的三个字段,还有id和其它2个时间戳。

代码语言:javascript
复制
// 如果不想请求 
const Fruit = sequelize.define("Fruit", {}, {
  timestamps: false
});

定义模型后,就不用建表了。

增加

插入数据呢?一行代码搞定:

代码语言:javascript
复制
await Fruit.create({name:'苹果',price:3.5});

就像操作对象一样操作数据库。

简单查询

如果你要查询全部:

代码语言:javascript
复制
ret = await Fruit.findAll()
    console.log('findAll',JSON.stringify(ret))

如果你想查询价格0-2.5的商品:

代码语言:javascript
复制
const Op=Sequelize.Op;
ret =await Fruit.FindAll({
  where:{price:{[Op.lt]:0,[Op.gt]:2.5}}
})
修改
代码语言:javascript
复制
await Fruit.update({price:'8.5'},{where:{name:'苹果'}})
删除
代码语言:javascript
复制
// 方式1
Fruit.findOne({ where: { id: 1 } }).then(r => r.destroy());
// 方式2
Fruit.destroy({ where: { id: 1 } }).then(r => console.log(r));

删除数据库字段:通常不会操作已有的数据库。如果需要真的删除,则需要强制同步:

代码语言:javascript
复制
Fruit.sync({force: true})
校验
代码语言:javascript
复制
price: {
    validate: {
            isFloat: { msg: "价格字段请输入数字" },
            min: { args: [0], msg: "价格字段必须大于0" } }
        }, 
    stock: {
            validate: {isNumeric: { msg: "库存字段请输入数字" }
        } 
 }
代码语言:javascript
复制
// 添加类级别方法
Fruit.classify = function(name) {
const tropicFruits = ['香蕉', '芒果', '椰子']; // 热带水果
return tropicFruits.includes(name) ? '热带水果':'其他水果'; };
// 添加实例级别方法
Fruit.prototype.totalPrice = function(count) {
  return (this.price * count).toFixed(2);
};
// 使用类方法
['香蕉','草莓'].forEach(f => console.log(f+'是'+Fruit.classify(f)));
// 使用实例方法 
        Fruit.findAll().then(fruits => {
        const [f1] = fruits;
            console.log(`买5kg${f1.name}需要¥${f1.totalPrice(5)}`);
    });

电商系统数据库设计

以下是一个标准电商系统的ER图(实体关系与类模型),它反映出一对一或一对多映射关系

在这张图里,用户处于中心地位:一个以用户为中心的订单,最基本的要素包括六大类:

  • 用户表(users)字段包括地址,名字等。
  • 商品(products):标题,价格,图片,描述,用户
  • 购物车(carts):哪个用户的购物车(外键)
  • 订单(orders):哪个用户下的单(外键)
  • 购物车单个明细(cartItems):关联有什么商品(外键),属于哪个购物车,商品数量数量
  • 用户的订单明细(ohterIstems)哪个订单(外键),有什么商品,数量。
models模块

项目更目录下新建一个models模块,存放6个js文件对应六张表。建表不需要考虑外键。

代码语言:javascript
复制
// users.js
const Sequelize = require('sequelize');
const sequelize = require('../util/database');

const User = sequelize.define('user', {
    id : {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        allowNull: false,
        primaryKey: true
    },
    name: Sequelize.STRING,
    email: Sequelize.STRING
});

module.exports = User;

// products.js
const Sequelize = require('sequelize');
const sequelize = require('../util/database');
const Product = sequelize.define('product', {
    id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        allowNull: false,
        primaryKey: true
    },
    title: {
        type: Sequelize.STRING,
        allowNull: false
    },
    price: {
        type: Sequelize.DOUBLE,
        allowNull: false
    },
    imageUrl: {
        type: Sequelize.STRING,
        allowNull: false
    },
    description: {
        type: Sequelize.STRING,
        allowNull: false
    }
});

module.exports = Product;

// cart.js
const Sequelize = require('sequelize');
const sequelize = require('../util/database');

const Cart = sequelize.define('cart', {
    id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        primaryKey: true,
        allowNull: false
    }
});

module.exports = Cart;

// order.js
const Sequelize = require('sequelize');
const sequelize = require('../util/database');

const Order = sequelize.define('order', {
    id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        allowNull: false,
        primaryKey: true
    }
});

module.exports = Order;


// cart-item.js
const Sequelize = require('sequelize');
const sequelize = require('../util/database');

const CartItem = sequelize.define('cartItem', {
    id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        allowNull: false,
        primaryKey: true
    },
    quantity: Sequelize.INTEGER
});

module.exports = CartItem;

// order-item.js
const Sequelize = require('sequelize');
const sequelize = require('../util/database');

const OrderItem = sequelize.define('orderItem', {
    id: {
        type: Sequelize.INTEGER,
        autoIncrement: true,
        allowNull: false,
        primaryKey: true
    },
    quantity: Sequelize.INTEGER
});

module.exports = OrderItem;
通用模块(utils)
数据库配置

把数据库配置独立出来:

代码语言:javascript
复制
const Sequelize = require('sequelize');
const env = require('dotenv')

env.config();
const sequelize = new Sequelize(
    process.env.DB_Database, 
    process.env.DB_USER, 
    process.env.DB_PWD, {
    dialect: 'mysql',
    host: 'localhost',
    operatorsAliases: false
});

module.exports = sequelize;
初始化(init.js)

数据建立需要初始化,那么可以写一个init函数:

以下展示了数据表初始化的过程.

连接
代码语言:javascript
复制
setTimeout(async ()=>{
    // 定义打印函数
    const log=(text,data)=>{
        console.log(`=======${text}========`);
        console.log(JSON.stringify(data,null,'\t'));
        console.log(`======================`);
    };

    const sequelize=require('./util/database');

    // 定义1对N对模型关系
    const Products=require('./models/products');
    const Users=require('./models/users');
    const Cart=require('./models/cart');
    const CartItem=require('./models/cart-item');
    const OrderItem=require('./models/order-item');
    const Order=require('./models/order');

    // 同步
    await sequelize.sync({false:true});
})
一对多:
代码语言:javascript
复制
// 产品表属于用户表
    Products.belongsTo(Users,{
        constraints:true,
        onDelete:'CASCADE'//阻止删除
    });
    Users.hasMany(Products);

    // 首要是创建用户,pk就是primarykey,对应的就是id
    let user = await Users.findByPk(1);
    if(!user){
        user=await Users.create({
            name:'djao',
            email:'dangjingtao@163.com'
        })
    }

    //添加商品
    let product=await user.createProduct({
        title:'iphone x',
        price:999,
        imageUrl:'iphonex.jpg',
        description:'爱疯叉商品描述'
    });

    log('Product',product);

打印结果如下

多对多
代码语言:javascript
复制
// 产品表属于用户表
    Products.belongsTo(Users, {
        constraints: true,
        onDelete: 'CASCADE'//阻止删除
    });
    Users.hasMany(Products);

    // 首要是创建用户,pk就是primarykey,对应的就是id
    let user = await Users.findByPk(1);
    if (!user) {
        user = await Users.create({
            name: 'djao',
            email: 'dangjingtao@163.com'
        })
    }

    //添加商品
    let product = await user.createProduct({
        title: 'iphone x',
        price: 999,
        imageUrl: 'iphonex.jpg',
        description: '爱疯叉商品描述'
    });

那么对应对关系(外键)就建立起来了。

以上。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 一Li小麦 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • fs 储存
  • MySql
    • 基本原生操作
      • 连接
      • 新建表
      • 增加行
      • 查询行
      • 修改行
      • 删除行
    • SQL中间件:Sequelize
      • 增加
      • 简单查询
      • 修改
      • 删除
      • 校验
  • 电商系统数据库设计
    • models模块
      • 通用模块(utils)
        • 数据库配置
      • 初始化(init.js)
        • 连接
        • 一对多:
        • 多对多
    相关产品与服务
    容器镜像服务
    容器镜像服务(Tencent Container Registry,TCR)为您提供安全独享、高性能的容器镜像托管分发服务。您可同时在全球多个地域创建独享实例,以实现容器镜像的就近拉取,降低拉取时间,节约带宽成本。TCR 提供细颗粒度的权限管理及访问控制,保障您的数据安全。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档