NodeJs分为四个阶段 第四阶段~
node+mysql
begin enjoy👇

node+mysql

nodejs同其他的服务端语言平台一样 具备数据库操作的能力。nodejs初期 主要与mongodb搭配 实现数据库操作,随着业务和语言的发展 现在它与mysql和其他数据库的交互越来越多。使用之前需要下载node执行mysql操作的模块 - npm install mysql --global

const mysql = require("mysql");

使用mysql模块链接数据库:

  1. 配置数据库连接信息:数据库服务器地址、用户账号、密码、访问的数据库

  2. 创建数据库连接对象: 执行数据库的连接

  3. 执行mysql数据库的操作:执行增删改查语句

  4. 执行完毕 关闭与mysql服务的连接

//创建连接
const link = mysql.createConnection({
    host : "localhost",	//数据库服务器地址
    port : "3306",	//端口号
    user : "root",	//账号
    password : "",	//密码
    database : "test",	//要连接的数据库
});

//执行连接
link.connect((err) => {
    if (err)   console.log(err.message);
    else {
        console.log("mysql服务已连接,线程号:" + link.threadId); 
    }
});

//使用query方法执行操作
link.query("SHOW TABLES", () => {});

//关闭数据库连接
link.end((err) => {
    if (err) console.log(err.message);
    else {
        console.log("数据库服务已经关闭");
        //关闭之后 不能再执行数据库操作
    }
});

封装连接

//创建数据库连接的模块 - db.connect.js

const mysql = require("mysql");

const link = mysql.createConnection({
    host: "localhost",
    port: "3306",
    user: "root",
    password: "",
    database: "student",

});

//创建数据库连接
link.connect((err) => {
    if (err) console.log(err.message);
    else {
        console.log("mysql服务已连接,线程号:" + link.threadId);
    }
});

//导出连接对象
module.exports = link;

CURD操作

查询语句

  • 语法结构:

    • SELECT 字段列表 FROM 表名 WHERE条件子句 ORDER排序子句 LIMIT子句
    • SELECT * FROM shop_goods ORDER BY gid DESC LIMIT 10
  • node代码:

    //加载数据库连接的模块
    const link = require("./db.connect");
    
    //执行查询任务的sql指令
    link.query("SELECT * FROM  user", (err, result) => {
        if (err) {
            console.log("sql错误提示:" + err.sqlMessage);
            console.log("当前执行sql:" + err.sql);
        } else {
            console.log(result);
        }
    });
    
  • 执行结果:

    • 执行成功时 err为null,result为查询结果集 - DataRowPocket对象集合数组;数据表中每条记录 对应一个数据对象 字段名为对象的属性 。
    • 执行失败时 err为错误对象 ,result为null
  • 大家使用node+mysql查询表数据并在页面中显示

MVC简介

我们经常说 在服务端使用MVC设计模式来进行开发,MVC分别表示:

  • C:Controller 即控制器 是通过路由控制来实现业务流程和逻辑管理
  • V:View 即视图层,用来渲染页面。通常需要使用模板引擎来操作,通过页面表现和程序分离 可以提高代码的可读性和维护性,同时也能实现更为高效的协同开发。
    • Node.js/Python/Java程序员专注于业务逻辑的设计和程序编码
    • 前端开发或者美工专职于用户交互效果的实现
  • M:Model即数据模型,封装方法用来快速实现数据的操作。这样开放人员 就能更多的将经历放在业务的设计和架构上,而不用过多考虑实现的问题。

在MVC结构中,C层是核心 用来控制业务流,在实现的过程中 如果需要进行数据操作 则调用M层实现封装号的方法;如果需要渲染页面 则加载模板引擎编译模板页面返回给用户。

数据模型

在数据中,它首先支持基本的CURD业务,基本的增删改查

  • select:select/findAll是查集合数据,表中的一条记录为一个数据对象,多条结果集就是对象集合的数组形式;即使只有一条符合查询的结果 它也返回数组。

    • 数据模板:SELECT 字段列表 FROM 表名 WHERE 条件字句 ORDER BY 排序字句 LIMIT 限制字句
    • 从数据模板中,我们能够得知 尽管不同的sql查询语句 它们的参数不一样 但sql结构都是一样。那我们可以考虑 提取sql结构 然后以参数形式 来执行一条具体的指令
    • 在查询中 需要设置的参数有:字段列表、表名、条件字句、排序字句、限制字句
    • 封装一个select方法 传入上述参数。接下来在select方法中 组装该条sql语句,然后执行返回结果:select(字段列表、表名、条件字句、排序字句、限制字句)
    //SELECT * FROM users WHERE uid > 100 ORDER BY uid DESC LIMIT 10
    const rows = select("*", "users", "uid > 100", "uid DESC", 10);
    
    //对象集合数组的多条记录 形如这样:
    rows = [
        {uid : 1, uname : "lucy", gender : "w"},
        {},
        {}
    ]
    //只有一条记录 但也返回数组
    //取得该条记录 需要使用arr[0]
    rows = [
        {uid : 1, uname : "lucy", gender : "w"},
    ]
    
  • find:而find/findOne是返回结果集中的一条(limit 1)操作,重要的是它返回一维的数据对象

    • find其实就是给select()方法中设置了limit参数值为1,然后对结果进行重构
    function find(fields, tbname, condition, order) {
        //调用了select 写死了limit为1
        const result = select(fields, tbname, condition, order, 1);
        //将结果集数组 转化成数据对象
        return result.length ? result[0] : {} 
    }
    const row = find("*", "users", "uid > 100", "uid DESC");
    
    //find返回一个数据对象 形如下面:
    row = {
        uid : 1, 
        uname : "lucy", 
        gender : "w"
    },
    
  • add:add/insert/create用来添加一条记录到表中,它通常返回一个OKPackage对象;如果要同时插入多条数据,需要自己来循环,方法本身是不支持的。

    • 插入语句的结构:INSERT INTO(uid, uname) VALUES (1, 'lucy')
    • 提取参数为 字段列表和值的映射对象 { uid : 1, uname : "lucy"}
    const OKPacket = add("users", {uid : 1, uname : "lucy",,,,});
    console.log("新增行ID为:" + OkPacket.insertId);
    
  • save:save/update是用来修改一条记录,它同add很像,区别在于save操作时会有一个where条件。

    const OKPacket = save("users", {uname : "Kate"}, "uid = 1");
    console.log("修改了" + OkPacket.affectedRows);
    
  • delete:delete方法删除记录,它需要删除条件,如果不设置则是整表的删除

    const OKPacket = delete("user", "uname = 'demo'");
    console.log("删除了" + OKpacket.affectedRows);
    
  • runSql :当执行较为复杂的sql操作时,一般没有适用的方法,这样就需要手写sql语句来运行

    runSql("SELECT * FROM users");
    

lautin-model

在实际开发中,通常会使用框架,例如express、koa。它们都有内置的对mongodb数据库封装的模型,对于mysql模块的扩展,通常需要通过npm来下载和安装。进入npmjs.com搜索model关键字,很多很多发布的关于mysql model的包,其中lautin-model是比较优秀的一款,推荐使用:

下载安装

  • npm install lautin-model
  • 配置数据库连接:
const db = require("lautin-model");
db.setConnection({
    type : "mysql",	//加载的驱动
    host : "localhost",	//数据库地址
    user : "root",	//账号
    password : "",	//密码
    database : "test",	//选择数据库
});	//配置数据库连接信息
  • 全局封装的 M(表名)方法 进行数据操作
M("users").find((err, result) => {
    if (err) console.dir(err);
    else console.log(result);
});

基本CURD

  • add方法添加一条记录

    • 用法:M(表名).add(数据).then(resolve, reject)
    • 示例:
    const pms = M("users").add({
        uname : "熏凯旋",
        nickname : "孙行者",
        password : md5('123456'),	//md5包需要额外安装
    });	//数据操作结果为一个正在进行的Promise
        //使用then来接收完成时的结果或错误
    pms.then((result) => {
        //增删改返回OkPacket对象 查询返回RowDataPacket集合
        console.log(result);
    }, (err) => {
        //err对象中 包含sql语句,sql错误提示以及mysql错误号
        console.log(err);
    });
    
  • save方法修改表记录

    • 用法:M(表名).save({新数据, 条件}).then(resolve, reject)
    • 示例:
    //修改编号100的用户昵称为foo
    M("users").save({
        data : {
            nickname : "foo",
        },
        //where条件即可以是字符串('uid=100') 也可以是对象形式
        where : {
            uid : 100
        },
    }).then((result) => {}, (err) => {});
    
  • delete删除记录

    • 用法:M(表名).delete(条件).then(resolve, reject)
    • 示例:
    //删除编号为100的用户记录
    M("users").delete({uid : 100}).then((result) => {}, (err) => {});
    //还可以直接传入一个数值 表示删除主键编号为该值的一条记录
    M("user").delete(100).then((result) => {}, (err) => {})
    
  • select查询多条记录

    • 用法:M(表名).select({字段列表, 条件, 排序规则, 限制行数}).then(resolve, reject)
    • 示例:
    //查询最新上架的笔记本 只显示10条
    M("goods").select({
        where : {gname : ["like", "%笔记本%"]},	// `gname` LIKE '%笔记本%'
        order : "created DESC",
        limit : 10,
    }).then((result) => {
        //result返回对象集合数组 即使只有查询结果[{}]
        console.log(result);
    }, (err) => {});
    
  • find查找一条结果

    • 用法:M(表名).find({字段列表, 条件, 排序规则}).then(resolve, reject)
    • 示例:
    //查找账号为lautin 或者 邮箱为1538731090@qq.com的用户
    M("users").find({
        where : {
            uname : "lautin",
            email : "1538731090@qq.com",
            _logic : "OR"
        },		
    }).then((result) => {
        //返回一个数据对象 不是集合形式
        console.log(result);
    }, (err) => {});
    

链式操作

上述方法,除了在方法体内一次性传参外,还可以使用链式调用 分别设置参数:

  • data()方法:创建数据,传入一个数据对象
  • where()方法:设置条件,支持字符串和对象两种形式,参数格式如下:
    • 'id = 100'等等其它运算符表达式
    • {uname : 'foo', password : 'bar' } 多个条件默认AND连接
    • {uname : 'lautin', email : '1538731090@qq.com', _logic:'OR' } 设置OR连接
    • {uname : ['LIKE', '%abc%'] } 模糊查询
    • {id : ['IN' , '1,3,5' ] } 编号为1,3,5的记录
    • {id : [' NOT IN', '2,4,6'] } 编号2,4,6以外的记录
    • {id : ['BETWEEN', '10, 20'] }编号10到20之间的记录
  • order()方法:设置排序规则,传入字符串 例如: uid DESC
  • limit()方法:限制行数,传入数值或者字符串,例如:5 或者 '0, 5'

链式操作中,可以结合实际情况 选择上述方法。链式方法在调用时 无需考虑它们的顺序 但必须以curd的调用方法结束,此时curd方法中 无需再传入sql分段参数。

const pms = M("users").data({}).add();
//const pms = M("users").data().where().save();
//const pms = M("users").where().delete();
//const pms = M("users").where().order().limit().select();
//const pms = M("users").where().order().find();

//再监听pms
pms.then(resolve, reject);

回调函数

在链式操作中,curd方法 无需再传入sql参数,接下来使用then方法接收Promise决议结果。处理Promise外,链式操作的curd方法中 还可以直接传入一个回调函数来接收结果:

M("users").where().order().select((err, result) => {
    if (err) console.log(err);
    else console.log(result);
});//使用回调函数后 无需再then,其他操作方法同样使用

高级应用

  • 手写sql语句:

对于复杂的业务处理时,往往需要使用高级sql语句。例如:联合查询、交叉连接、事物和存储过程等。这样curd方法自然无法满足需求,但内置的runSql()可以接收一条sql语句 来定制实际需求。

//执行sql指令时 设置空模型即可
M().runSql(sql, (err, result) => {
    
});
  • 自定义表模型:

如果想要定制自己的模型方法,可以通过创建表模型类来完成。该模型需要继承核心的Model类,在使用前需要配置模型存放的根路径,该路径必须是一个绝对地址:

const path = require("path");
//使用path.resolve()方法 转化绝对路径
db.use("model", path.resolve("./models"));
//文件名必须和模型类名称保持一致,例如 ~/models/CateModel.js
module.exports = function (Model) {

    class CateModel extends Model {

        constructor() {
    
            //部署表名、前缀和主键
            super({
                tableName: "category",
                tablePrefix: "shop_",
                pk : "cid",
            });
    		
            getNameById(cid) {
                //to do here
                
            }
        };

         
    }

    return CateModel;

}

对于自定义的表模型需要严格按照上述规范来定义,你也可以在命令行使用make model CateModel来帮你快速生成。当创建好模型后,使用D(类名) 创建它的示例:

D("CateModel").getNameById(100);

posted @ Zycin (非转载 来自个人学习资料整理)