node mysql模型_Node教程——Node封装Mysql的DAO层封装MongoDB的DAO层

概述DAO层的封装

首先我们拿JDBC的DAO层来举例子

DAO(Data Access Object) 是数据访问层

Action像是服务员,顾客点什么菜,菜上给几号桌,都是ta的职责;Service是厨师,action送来的菜单上的菜全是ta做的;Dao是厨房的小工,和原材料(通过hibernate操作数据库)打交道的事情全是ta管。

对象的调用流程:JSP—Action—Service—DAO—Hibernate(某框架)—数据库。

我们来谈谈Node的DAO层封装那些事

基于我目前的开发项目的架构,从数据的流转来看,它类似于下面这个样子

Model(数据模型)-- Middleware(数据处理中间件) -- Router(路由处理)

这一讲我们主要是关注与Model层的处理,既,如果更加简单更加精确的的把数据查询出来

一、 关于Node for MYSQL的DAO封装

基础的知识,我们这里不讲,我们直接考虑如何在项目中使用

首先我们npm mysql,这个没有什么好解释的

开始封装一个最基础的通用的数据链接类

要在node中操作mysql,一般有如下的事情要做

基础的使用我就不讲了,我们直接用单例模式来进行封装成一个类

[model/DAO/model.js]

const mysql = require('mysql')

/**

* 数据模型的基类

* 封装了数据库操作

*/

module.exports = class Model {

// 连接对象

static conn = null

/**

* 初始化数据连接操作

*/

static connection() {

Model.conn = mysql.createConnection({

host: '127.0.0.1',

user: 'root',

password: '123',

database: 'blog'

})

Model.conn.connect(err => {

if (err) {

console.log(`数据库连接失败:${err.message}`)

}

})

}

/**

* 关闭数据库连接,注意,你需要及时的关闭查询数据流,比秒消耗性能

*/

static end() {

if (null != Model.conn) {

Model.conn.end()

}

}

/**

* 通用查询方法

* @param {string} sql 要执行的SQL语句

* @param {Array} params 给SQL语句的占位符,以后由具体的Model决定具体的传入参数

*/

static query(sql, params = []) {

return new Promise((resolve, reject) => {

this.connection()//调用连接

//开始查询

Model.conn.query(sql, params, (err, results) => {

if (err) {

reject(err)

} else {

resolve(results)

}

})

//关闭流

this.end()

})

}

}

具体的业务查询的实现

这里我们假设我的表里面有这些字段,我们具体的业务就是在这里构造查询条件然后就可以去展开具体的查询了,注意继承

[model/articel.js]

const Mysql = require('./DAO/model');

//开始实现具体的查询Model

module.exports = class Article extends Mysql {

/**

* 描述 查询所有的列表,这里是SQL的具体的实现方法,根据以往需求来处理

* @date 2020-04-29

* @returns {any} 返回值是查询出来的数据对象

*/

static getList() {

return new Promise((resolve, reject) => {

let sql = 'SELECT id,title,content,`time`,thumbnail FROM article ORDER BY TIME DESC'

this.query(sql).then(results => {//调用父类的查询方式

resolve(results)

}).catch(err => {

console.log(`获取文章列表失败:${err.message}`)

reject(err)

})

})

}

/**

* 获取指定文章的详情

* @param {integer} id 文章编号

*/

static getArticleById(id) {

return new Promise((resolve, reject) => {

let sql = 'SELECT a.id,a.title,a.content,a.`time`,a.hits,a.`category_id`,c.`name`,a.`thumbnail`,a.`hot` FROM article a,category c WHERE a.`category_id` = c.`id` AND a.id = ?'

this.query(sql, id).then(results => {//调用父类的查询方式

resolve(results[0])

}).catch(err => {

console.log(`获取指定文章的详情失败:${err.message}`)

reject(err)

})

})

}

}

然后呢?如何使用?具体的node项目中,需要说明的,以上的两端代码 在node中,都是处于Model下的,有了model使用就相对比较简单了,

router( 调用中间件mideelwear )--- middleware(接受到router的需求开始调用模型层拿数据) --以req方式,丢回给router,router反过来拿数据去渲染或者做成API接口就可以了

[router/index.js]

+++

const Articel = require('../middelwear/article')

+++

articleApp.get('/:id', [Articel.getArticleById], (req, res) => {

let { article } = req//由于我们之前的中间件已经把结果存到了req里面,这样我们就能直接拿了

//如果是模板渲染可以这样来干

// res.render('article', { article: article })//如果你需要做API接口于是乎你可以以JSON形式丢出去

res.send( JSON.stringify( { article: article } ) )

})

[middleware/articel.js]

//如果数据是从 路由Router过来

function getArticleById (req, res, next) {

//然后再路由里,我只需要这样用就行了,直接从req里面解构过来,需要说明一些

// let id = req.params.id,这个用于处理get /:?这样的数据,?的具体数据,就能从req.params里面弄出来

// let id = req.body,这个用于处理POST这样的数据,具体数据,就能从req.body里面弄出来

let id = req.params.id

Article.getArticleById(id).then(results => {

req.article = results

next()//放行

}).catch(err => {

next(err)

})

}

以上就是最基础的Node for Mysql数据的DAO层的封装,这样一来,后面的数据操作,就变得简单的多了,希望我的文章对你有所帮助!~~~

二、关于Node for MangoDB的DAO封装

首先是npm install mongoose下载 不多解释

开始封装

这里我们同样也是有两个层面的模型,一个dao层,一个是具体的实现层

[molde/dao/]

//这里仅仅演示了一部分的dao命令

module.exports = class MongoDB {

//构造器

constructor(collectionName) {

this.MongoClient = require('mongodb').MongoClient;

this.url = "mongodb://root:root@localhost/";

this.dbName = "blogs_2node_kaifa";

//由于我们的表设计到了多表的操作,所以表(集合)是要变来变去的,所以这里改成由具体的实现传入

//具体的操作是那项表交与用户具体实现,

this.collection = collectionName;

}

//不要加入static ,如果加入就变成静态的了,实例的对象就用不了这些静态的方法了

//链接

connect(url,callback){

if (!url) {

return;

}

this.MongoClient.connect(url, function(err, db) {

callback(err, db);

db.close();//关闭流

});

}

/**

* 描述 插入单条数据

* @date 2020-04-29

* @param {any} oneObj

* @param {any} callback

* @returns {any}

*/

insertOne(oneObj, callback) {

let dbName = this.dbName;

let collection = this.collection;

console.log('this.d');

this.connect(this.url, function(err, db) {

var client = db.db(dbName);

client.collection(collection).insertOne(oneObj, function(err, res) {

if (err) throw err;

if (callback) {

callback(err, res);

}

});

});

}

/**

* 描述 增加多条数据

* @date 2020-04-29

* @param {any} objs

* @param {any} callback

* @returns {any}

*/

insertMany(objs, callback) {

if (!Array.isArray(objs)) {

throw new Error("非数组,类型不匹配!");

return;

}

let dbName = this.dbName;

let collection = this.collection;

this.connect(this.url, function(err, db) {

var client = db.db(dbName);

client.collection(collection).insertMany(objs, function(err, res) {

if (err) throw err;

if (callback) {

callback(err, res);

}

});

});

}

/**

* 描述 查询操作

* @date 2020-04-29

* @param {any} whereStr

* @param {any} callback

* @returns {any}

*/

find (whereStr, callback) {

let dbName = this.dbName;

let collection = this.collection;

this.connect(this.url, function(err, db) {

if (err) throw err;

var client = db.db(dbName);

//开始传入指定的查询条件

client.collection(collection).find(whereStr).toArray(function(err, result) {

if (err) throw err;

if (callback) {

callback(err, result);

}

});

});

}

[model/user.js]

//示例话具体的表(集合)操作对象

const MongoDB = require('./02.通用的模型层');

//实例化dao层,并且给它指定的表

setCollection = new MongoDB('setCollection')

module.exports = class User{

static getUser(queryMD){

return new Promise((resolve,reject)=>{

setCollection.insertOne(queryMD,(err,result)=>{

if(result){

resolve(result)

}else{

reject(err)

}

})

})

}

static updataMany(queryMD){

return new Promise((resolve,reject)=>{

setCollection.updataMany(queryMD,(err,result)=>{

if(result){

resolve(result)

}else{

reject(err)

}

})

})

}

}

以上外面的mongoose的模型层就构建好了,接下里就是我们的中间件部分

//这里是模拟的是中间件,。如果这里有传参和之前的mysql的dao层是一样的操作直接把req身上的都写带下来就可以了

const User = require('./03_具体的模型实现层');

function getSet(queryMD){

//在这里你可以取查询的要素做处理然后,处理完成之后才丢给查询

//这里仅仅是为了演示,就不做具体的要素处理了,

console.log('Jigru1');

User.getUser(queryMD).then((result) => {

console.log( result );//这样我们就查询成功了

}).catch((err) => {

console.log(err);

});

}

//假设,我现在要设置username=admin的用用户,于是乎我就

getSet({"username":"admin"})

特别说明:由于mongo中的不能像msq这种直接用sql的查询,所以使用起来,也不太爽,对于find()之后的各种条件匹配,我们不写在dao层中,具体的模型实现的时候,在写具体的模型查询语句,我认为是极好的一种规范,

欢迎大佬赐教,欢迎大家来我的git让这个dao层的封装变得更强大

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
概述bearcat-dao 是一个 node.js 基于 SQL mapping 的 DAO 框架。实现了基于 SQL mapping 来对数据结果集进行映射,是一种半自动化的模式,相比较于 O/R mapping 全自动化的模式。 因此,在 bearcat-dao 里,开发者能够对SQL进行完全的控制,通过SQL来与数据库打交道并进行性能优化,bearcat-dao 则会把数据结果集映射到 bearcat model 中去。SQL mapping vs O/R mapping结构化查询语言(SQL)已经存在了非常久的时间。自从 Edgar F.Codd 第一次提出“数据可以被规范化为一组相互关联的表”这样的思想以来,已经超过35年了。很少有哪一种软件技术敢声称自己像关系数据库和SQL那样经受住了时间的考验。因此,关系数据库和SQL仍然很有价值,我们可能都曾有这样的经历,应用程序的源代码(经历了很多版本)随着时间的流逝最终还是过时了(无法维护下去),但它的数据库甚至是SQL本身却仍然很有价值。O/R mapping 被设计为用来简化对象持久化工作的,它通过将SQL完全从开发人员的职责中排除来达到这个目的。在O/R mapping中,SQL是给予应用程序中的类与关系数据库表之间的映射关系而生成的。除了不用写SQL语句,使用O/R mapping的API通常也比典型的SQL API要简单很多,但是O/R mapping仍然不是一颗“银弹”,它并非适用于所有的场景。一个最主要的问题就是O/R mapping它需要假设数据库是被恰当的规范化了,如果没有被恰当规范,这就会给映射带来许多麻烦,甚至需要绕些弯路,或者在设计时对效率做些折衷。同时,没有哪一个对象/关系解决方案可以支持每一种数据库的每一种特性、每一种能力以及设计上固有的缺陷,它们仅仅能做到一个子集,而能做到全集的恰恰则是SQL这个专为数据库设计的结构化查询语言SQL mapping 与 O/R mapping 不同,它不是直接把类映射为数据库表或者说把类的字段映射为数据库列,而是把SQL语句与结果(也即输入和输出)映射为类。bearcat-dao 在类(model)和数据库之间建立了一个额外的中间,这就为如何在类和数据库表之间建立映射关系带来了更大的灵活性,使得在不用改变数据模型或者对象模型的情况下改变它们的映射关系成为可能。这个中间其实就是SQL,通过SQL可以将类(model)与数据库表之间的关系降到最低。开发者只需要编写SQL,bearcat-dao 负责在类(model)属性与数据库表的列之间映射参数和结果Modelmodel 定义使用 bearcat model因此,可以非常容易的就设置映射关系、约束、relation关系例如,我们有一个 test 表,它只有一个 id 主键字段create table test(     id bigint(20) NOT NULL COMMENT 'id',              PRIMARY KEY (id) )ENGINE=InnoDB DEFAULT CHARSET=utf8; 然后,我们可以定义下面的 modelvar TestModel = function() {     this.$mid = "testModel";     this.$table = "test";     this.id = "$primary;type:Number"; }    module.exports = TestModel;在 TestModel 里,我们使用 $table 属性来设置需要映射的表名,对于 id 属性,我们用 primary 表明这是一个主键,并且我们给这个字段添加了一个 type 约束,限定它一定为 Number 类型Relation 在关系型数据库的表与表之间是可以有 relation 的,也即关系,有一对一、一对多、多对多这三种情况一对一 relation一对一关系意味着两张表,一张表有另外一张表的id引用(或者外键)。在model对象里面就是说,两个model,是一对一的比如,我们有两张表,test1 表有对 test2 表的 id 引用create table test1(     id bigint(20) NOT NULL COMMENT 'id',         rid bigint(20) NOT NULL COMMENT 'reference to test2 id',                PRIMARY KEY (id) )ENGINE=InnoDB DEFAULT CHARSET=utf8;create table test2(     id bigint(20) NOT NULL COMMENT 'id',              PRIMARY KEY (id) )ENGINE=InnoDB DEFAULT CHARSET=utf8;然后,我们就可以定义这样的 modelvar Test1Model = function() {     this.$mid = "test1Model";     this.$table = "test1";     this.id = "$primary;type:Number";     this.test2 = "$type:Object;ref:test2Model" }    module.exports = Test1Model;var Test2Model = function() {     this.$mid = "test2Model";     this.$table = "test2";     this.id = "$primary;type:Number"; }    module.exports = Test2Model;通过用 Test1Model.test2 属性,我们使用 ref:test2Model 来设置对 test2Model 的引用一对多 relation一对多则意味着,一个model引用着另外一个model数组。比如,我们有一个博客,这个博客里面的文章有很多评论,这个博客文章与评论之间的关系就是一对多的var Test1Model = function() {     this.$mid = "test1Model";     this.$table = "test1";     this.id = "$primary;type:Number";     this.test2 = "$type:Array;ref:test2Model" }    module.exports = Test1Model;在上面的model定义中,我们简单的把 test2 属性的 type 改成 Array 即可,它就变成了一对多的关系多对多 relation多对多一般可以通过中间表,来转化成两个一对多的关系SQL 模板当编写复杂sql语句的时候,如果仅仅使用 String 类型的字符串来编写,肯定非常痛苦,更好的方式是用 SQL 模板编写SQL模板相当简单比如,我们可以定义 id 为 testResultSql 的 SQL 模板sql testResultSql select * from test  end然后我们可以在dao中使用这个 SQL 模板domainDaoSupport.getList("$testResultSql", null, "testModel", function(err, results) {      // results is testModel type array });第一个参数,开头带上 $ 就表面是一个 SQL 模板同时,由于是模板,因此可以包含其他模板,比如sql testResultSql select * from ${testResultTable}  end sql testResultTable test end这个结果和上面是一样的ResultSet 映射数据库结果集是一个由field/value对象组成的数组,因此映射结果集就像用特定key/value对来填充对象。为了能够做到匹配,我们使用 model 属性值里的 prefix model magic attribute value 或者 model 属性里的 prefixmodel attribute比如,如果你查询得到了如下的 resultSet[{     "id": 1,     "title": "blog_title",     "content": "blog_content",     "create_at": 1234567,     "update_at": 1234567 }]那么,映射的model就是这样的var BlogModel = function() {     this.$mid = "blogModel";     this.$table = "ba_blog";     this.id = "$primary;type:Number";     this.aid = "$type:Number";     this.title = "$type:String";     this.content = "$type:String";     this.create_at = "$type:Number";     this.update_at = "$type:Number"; }    module.exports = BlogModel;如果结果集字段是已 ***blog_***开头,比如[{     "blog_id": 1,     "blog_title": "blog_title",     "blog_content": "blog_content",     "blog_create_at": 1234567,     "blog_update_at": 1234567 }]那么,映射model就是这样的var BlogModel = function() {     this.$mid = "blogModel";     this.$table = "ba_blog";     this.$prefix = "blog_";     this.id = "$primary;type:Number";     this.aid = "$type:Number";     this.title = "$type:String";     this.content = "$type:String";     this.create_at = "$type:Number";     this.update_at = "$type:Number"; }    module.exports = BlogModel;仅仅需要添加 this.$prefix model 属性DAODAO 是领域对象模型的缩写,一般用于操作数据库bearcat-dao 提供 domainDaoSupport 对象,封装了基本的sql、cache操作。使用它也非常简单,直接依赖注入,然后通过 init 方法进行初始化simpleDao.jsvar SimpleDao = function() {     this.$id = "simpleDao";     this.$init = "init";     this.$domainDaoSupport = null; }    SimpleDao.prototype.init = function() {     // init with SimpleModel id to set up model mapping     this.domainDaoSupport.initConfig("simpleModel"); }    // query list all // callback return mapped SimpleModel array results SimpleDao.prototype.getList = function(cb) {     var sql = ' 1 = 1';     this.$domainDaoSupport.getListByWhere(sql, null, null, cb); }    module.exports = SimpleDao;完整的api可以参见 domainDaoSupport配置使用修改项目中的context.json placeholds 可以很方便的在不同环境间切换"dependencies": {     "bearcat-dao": "*" }, "beans": [{     "id": "mysqlConnectionManager",     "func": "node_modules.bearcat-dao.lib.connection.sql.mysqlConnectionManager",     "props": [{         "name": "port",         "value": "${mysql.port}"     }, {         "name": "host",         "value": "${mysql.host}"     }, {         "name": "user",         "value": "${mysql.user}"     }, {         "name": "password",         "value": "${mysql.password}"     }, {         "name": "database",         "value": "${mysql.database}"     }] }, {     "id": "redisConnectionManager",     "func": "node_modules.bearcat-dao.lib.connection.cache.redisConnectionManager",     "props": [{         "name": "port",         "value": "${redis.port}"     }, {         "name": "host",         "value": "${redis.host}"     }] }]如果你不需要使用redis, 你可以移除redisConnectionManager定义事务bearcat-dao 基于 bearcat AOP 提供了事务支持. aspect 是 transactionAspect , 提供了 around advice, 当目标事务方法调用cb函数的时候传入了 err, rollback 回滚操作就会被触发, 相反如果没有cb(err)的话, 事务就会被提交(commit).pointcut 定义的是:"pointcut": "around:.*?Transaction"因此, 任何已 Transaction 结尾的POJO中的方法都会匹配到 transaction 事务由于transaction必须在同一个connection中, 在 bearcat-dao 中是通过 transactionStatus 来保证的, 在同一个事务的 transaction 必须在同一个transactionStatus中SimpleService.prototype.testMethodTransaction = function(cb, txStatus) {     var self = this;     this.simpleDao.transaction(txStatus).addPerson(['aaa'], function(err, results) {         if (err) {             return cb(err); // if err occur, rollback will be emited         }         self.simpleDao.transaction(txStatus).getList([1, 2], function(err, results) {             if (err) {                  return cb(err); // if err occur, rollback will be emited             }             cb(null, results); // commit the operations         });     }); }开启 Debug 模式跑node应用时带上BEARCAT_DEBUG为trueBEARCAT_DEBUG=true node xxx.js开启debug模式后,就能看到具体执行SQL的日志例子bearcat-todobearcat-dao example 标签:bearcat

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值