自己实现PostgresQL的nodejs驱动,分享给大家

来源:互联网 发布:计划进度表软件下载 编辑:程序博客网 时间:2024/05/21 17:59

PostgresQL性能上不输Mysql,而且支持很多高级特性,于是我写了这个项目,根据libpg的c驱动,封装了这个nodejs驱动。

项目地址:

git clone https://code.csdn.net/limite_god/pgsql.git

开发难点、待实现功能、特性

1、nodejs的v0.12.0开始,api有了不少变化,熟悉这些变化用来不少时间;

2、libpg-c的api的熟悉,全英文的,得一行行认真看;

3、makefile,这里面的知识杂而细,只写了个linux下编译的;

4、libpg的executeParam方法暂未实现,所以添加了escape的连接池,专门用来处理escape;

5、数据类型支持,现在只对libpg的int4及int8做了转换,其它格式会返回字符串(比如日期);

6、连接池使用了nodejs的EventEmitter实现,sql命令会在压力较大的时候进行排队,这一块策略非常重要,涉及了nodejs的核心思想,尽量发挥慢速资源的最大性能,Pool.js,大家可以细看;

7、Database对象cmPool和trPool、esPool,cm处理无需声明事务的sql,tr用来专门执行事务连接,es专门用来escape字符串;

8、api尽量做到给调用者最大的自由,协调资源交给驱动。

9、很多地方注释缺少,等待以后添加;

10、table实现了类mongodb的find,update,remove,save,都可以传递options参数,options参数暂时只支持4个key,ret,sort,limit,offset;

11、我会持续对项目进行维护,添加更多功能,有建议请留言。


环境准备

操作系统centos6+,安装nodejs版本v0.12.0+,postgresql版本9.4.1

需要说明的是,nodejs和postgresql都需要从源码安装,postgress的安装目录采用默认目录,/usr/local/pgsql/,如果你的目录不同,请修改项目跟目录下的makefile


下载代码并编译

模块并没有在官方模块中注册,所以最好在你的nodejs程序的node_modules目录下执行

git clone https://code.csdn.net/limite_god/pgsql.git

cd pgsqlmake

项目的makefile只支持linux,且及其简单,最有可能发生两类错误,一类是头文件找不到,一类是方法的实现着不到。

如果头文件未找到

1、检查nodejs及postgres是否安装
2、检查makefile中的头文件扫描目录是否和你系统的安装目录是否一致,如果不一致,请自己修改

如果提示方法实现未找到

这种情况一般是由于你的系统未把postgres的动态库加入系统扫描路径

尝试添加/etc/ld.so.conf.d/pgsql.conf,添加一行/usr/local/pgsql/lib(你的pg动态库的路径),然后执行ldconfig

DEMO

var async = require('async');
var pgsql = require('pgsql');var DataBase = pgsql.DataBase;var Table = pgsql.Table;var Column = pgsql.Column;var db = new DataBase({    url:"host=127.0.0.1 dbname=test user=postgres",    cmPoolSize:20,  //通过table.find,update,remove,save都使用这个连接池的连接    trPoolSize:5,   //db.getConn获得连接都是这个连接池的连接    esPoolSize:1    //这个一个连接的连接池专门用来执行escape});var testTable = new Table("test",[        new Column("id", "SERIAL", 0, "primary key"),        new Column("index", "SERIAL", 0, ""),        new Column("name", "text", -1, ""),        new Column("description", "text", -1, "")    ]);testTable.colList['description'].escape = true; //需要对文本进行转义db.put(testTable);async.waterfall([    function(cb){   //连接数据库        db.init(function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    {        var t = db.get("test");        console.log(t.getDdl());        t.find({id:3}, {}, function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    {        var t = db.get("test");        var doc = {            $set:{                name:"just a test."            }        };        t.update({id:3}, doc, function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    {        var t = db.get("test");        var options = {            limit:10,            offset:0,            sort:{                id:-1            }        };        t.find({id:3}, {}, options, function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    //save a set    {        var t = db.get("test");        t.save({name:"liming", description:'a\'b'}, function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    //保存记录,并返回自增长的id    {        var t = db.get("test");        var options = {            ret:{                id:1            }        };        t.save({name:"liming", description:'a\'b'}, options, function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    {        var t = db.get("test");        t.remove({name:"test222"}, function(err, data){            console.log(data);            cb(err);        });    },    function(cb)    //跨表的语句,请使用db.execute直接执行    {        db.execute("select * from customer", function(err, data){            console.log(data);            cb(err);        });    },    /* 执行事务 */    function(cb){        db.getConn(function(err, conn){            cb(err, conn);        });    },    function(conn, cb)    {        conn.execute("BEGIN", function(err, data){            console.log(data);            cb(err, conn);        });    },    function(conn, cb)    {        conn.execute("DECLARE myportal CURSOR FOR select * from test", function(err, data){            console.log(data);            cb(err, conn);        });    },    function(conn, cb)    {        var hasNext = true;        async.whilst(            //条件            function() {                return hasNext;   //true,则第二个函数会继续执行,否则,调出循环            },            function(whileCb) { //循环的主体                conn.execute("FETCH NEXT in myportal", function(err, data){                    if(data && data.affected > 0)                    {                        console.log(data);                    }                    else                    {                        hasNext = false;                    }                    whileCb(err);                });            },            function(err) {         //here 如果条件不满足,或者发生异常                cb(err, conn);            }        );    },    function(conn, cb)    {        conn.execute("CLOSE myportal", function(err, data){            console.log(data);            cb(err, conn);        });    },    function(conn, cb)    {        conn.execute("END", function(err, data){            console.log(data);            cb(err, conn);        });    }], function (err, conn) {    if(conn)    {        //使用完连接,记得归还给连接池        db.unLock(conn);    }    if(err)    {        console.log("the error is:");        console.error(err);    }});

输出如下:

init success!create table test(id SERIAL primary key, index SERIAL , name text , description text );select * from test where (id = '3'){ affected: 0, rst: [] }update test set name = 'just a test.' where (id = '3'){ affected: 0, rst: [] }select * from test where (id = '3') order by id desc limit 10{ affected: 0, rst: [] }insert into test(name,description) values('liming','a''b'){ affected: 1, rst: [] }insert into test(name,description) values('liming','a''b') returning id{ affected: 1, rst: [ { id: 23 } ] }delete from test where (name = 'test222'){ affected: 0, rst: [] }{ affected: 1,  rst:    [ { id: 1,       username: 'liming',       password: '123456',       reg_time: '2015-03-25 22:26:30',       type: 1,       status: 1 } ] }{ affected: 0, rst: [] }{ affected: 0, rst: [] }{ affected: 1,  rst: [ { id: 18, index: 18, name: 'liming', description: 'a\'b' } ] }{ affected: 1,  rst: [ { id: 19, index: 19, name: 'liming', description: 'a\'b' } ] }{ affected: 1,  rst: [ { id: 20, index: 20, name: 'liming', description: 'a\'b' } ] }{ affected: 1,  rst: [ { id: 21, index: 21, name: 'liming', description: 'a\'b' } ] }{ affected: 1,  rst: [ { id: 22, index: 22, name: 'liming', description: 'a\'b' } ] }{ affected: 1,  rst: [ { id: 23, index: 23, name: 'liming', description: 'a\'b' } ] }{ affected: 0, rst: [] }{ affected: 0, rst: [] }


0 0
原创粉丝点击