bearcat-dao

Node.js 的 DAO 框架
授权协议 MIT
开发语言 JavaScript
所属分类 Web应用开发、 Node.js 扩展
软件类型 开源软件
地区 国产
投 递 者 仉峻
操作系统 跨平台
开源组织
适用人群 未知
 软件概览

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)属性与数据库表的列之间映射参数和结果

Model

model 定义使用 bearcat model
因此,可以非常容易的就设置映射关系、约束、relation关系

例如,我们有一个 test 表,它只有一个 id 主键字段

create table test(
    id bigint(20) NOT NULL COMMENT 'id',    
    
    PRIMARY KEY (id)
)ENGINE=InnoDB DEFAULT CHARSET=utf8;

 然后,我们可以定义下面的 model

var 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;

然后,我们就可以定义这样的 model

var 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 属性

DAO

DAO 是领域对象模型的缩写,一般用于操作数据库

bearcat-dao 提供 domainDaoSupport 对象,封装了基本的sql、cache操作。使用它也非常简单,直接依赖注入,然后通过 init 方法进行初始化

simpleDao.js

var 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为true

BEARCAT_DEBUG=true node xxx.js

开启debug模式后,就能看到具体执行SQL的日志

例子

  • 概述 tj 实现了一个 jstrace,可以用于动态的对node进行类似于dtrace,ktap的trace分析,可以动态检测线上api接口的访问性能,用于express中tj也实现了一个中间件express-jstrace,但是express-jstrace更像一个filter,只能检测req res的性能,通过bearcat提供的强大的AOP支持, 让监控线上方法调用性能成为可能 实现 bea

  • bearcat model 本次升级主要是对model进行了抽象,model 代表着系统中的一些数据,也就是一些javaScript对象,对这些数据还可以有操作,比如校验、数据处理、序列化、持久化等 。所有的这些操作,在 bearcat model,统一的抽象成 constraint 和 filter。(在即将更新的 bearcat-dao 0.2 版本里面还可以看到 model 在数据库 O/R

  • Bearcat是一个基于POJOs进行开发的应用层框架, Bearcat提供了一个轻量级的容器来编写简单,可维护的node.js. Bearcat 提供了一个基础的底层来管理应用逻辑对象,使得开发者就可以把精力放在应用层的逻辑编写上. Bearcat 使开发者编写“简单纯粹的javaScript对象”(POJO), 并且不会侵入这些POJO,你完全可以在不使用Bearcat的环境下部署应用这些PO

 相关资料
  • Bearcat是一个基于自描述javaScript object进行开发的应用层框架, Bearcat提供了一个轻量级的容器来编写简单,可维护的javaScripts. Bearcat 提供了一个基础的底层来管理应用逻辑对象,使得开发者就可以把精力放在应用层的逻辑编写上.  Bearcat 概览 Bearcat 包括几个部分,包括:     核心容器     核心容器包含核心,Beans,以及Co

  • 本文向大家介绍Java的Spring框架中DAO数据访问对象的使用示例,包括了Java的Spring框架中DAO数据访问对象的使用示例的使用技巧和注意事项,需要的朋友参考一下 Spring DAO之JDBC   Spring提供的DAO(数据访问对象)支持主要的目的是便于以标准的方式使用不同的数据访问技术, 如JDBC,Hibernate或者JDO等。它不仅可以让你方便地在这些持久化技术间切换,

  • 另外,假设数据库已经创建和填充。 这描绘了一个学生有多门课程... 我的学生实体: Spring Boot指南没有描述联接或DAOS-我只需要学习如何正确地创建finder方法,这些方法模拟select语句,返回列表或数据结构。 感谢你花时间阅读这篇文章...

  • DaoChain 欢迎使用 DaoChain 区块链镜像认证系统。DaoChain 是 DaoCloud 自安全扫描,安全构建镜像等功能之后隆重推出的分布式镜像校验系统。 DaoChain 结合了区块链的去中心化特性与镜像加密校验技术,实现了不依赖中心化 docker registry 的安全验证功能。 用户可通过加密本地镜像并与区块链上的发布者发布的 hash 值对比,确认本地镜像与发布者发布的

  • 10.8.1 什么是DAO DAO(Database Access Object)使用Microsoft Jet数据库引擎来访问数据库。Microsoft Jet为象Access和Visual Basic这样的产品提供了数据引擎。 与ODBC一样,DAO提供了一组API供编程使用。MFC也提供了一组DAO类,封装了底层的API,从而大大简化了程序的开发。利用MFC的DAO类,用户可以编写独立于DB

  • (本项目终止开发,因为现在 MyBatis 配合 SpringBoot 使用已经全程免配置,其易用性已经达到作者本人的期望。) hydrogen-dao 是一个轻量级的 JDBC 数据库操作工具,专注于简化数据库的连接管理 SQL 执行。其主要功能有: 连接池管理,状态查看; 跨数据库的事务; 根据查询参数来动态组装 select/insert/update/delete 语句,免除大量的 if-