febs db库用于连接数据库
febs-db是在citong-db@1.5.3基础上进行开发, citong-db库已停止更新
(v0.0.3及之前版本接口已经不适用, 请查看使用说明README-v0.0.3)
目前支持 mysql
, mssql
; 其中 mysql请使用InnoDB
引擎.
Install
Use npm to install:
npm install febs-db --save
febs-db是一个orm库, 主要的类为:
database
: 代表一个数据库; 可以用于执行sql语句, 进行事务等操作.
tablebase
: 代表一个数据库表; 针对表的基本操作在这个对象中完成;
dataType
: 数据表的字段类型定义
condition
: 进行查询条件构造,会对类型与值进行类型检查. 每个表对象都有一个此对象, 使用 tablebase.condition 获取对象.
procedureParams
: 调用存储过程时, 用于构建参数.
Exception
系统在错误发生时会抛出exception
类型的异常
事务处理中发生异常将自动rollback.
异常类如下
exception(msg, errcode, filename, line)
例子:
var exception = require('febs-db').exception;
try {
...
} catch (e) {
if (e instanceof exception) {
if (e.code == exception.DB_SqlException) {
}
} else {
throw e;
}
}
定义了常用的错误code.
exception.DB_CommonException
exception.DB_SqlException
exception.DB_ConnectException
exception.DB_QueryException
Define-table
操作一个数据表之前, 需要先对表结构进行定义, 与数据不匹配的定义在执行数据操作时会报错. 数据列可以仅列出需要操作的列.
var tablebase = require('febs-db').tablebase;
var dataType = require('febs-db').dataType;
class TableDemo extends tablebase {
constructor() {
super(
'User',
'ID',
{
ID: {type: dataType.BigInt(true), key: true},
Name: {type: dataType.Varchar(10)},
NumberCol:{type: dataType.Float()},
IntCol: {type: dataType.Int(false)},
BoolCol: {type: dataType.Bit()}
}
);
}
}
register table
var database = require('febs-db').database;
class dbAgent extends database {
constructor() {
super('mysql', {});
this.TableDemo = this.registerTable(new TableDemo(), 'mapName');
}
}
global.dbagent = new dbAgent();
combined primary key
var tablebase = require('febs-db').tablebase;
var dataType = require('febs-db').dataType;
class TableDemo extends tablebase {
constructor() {
super(
'Admin',
['ID', 'IntCol'],
{
ID: {type: dataType.BigInt(true), key: true},
Name: {type: dataType.Varchar(10), map:'Name1'},
NumberCol:{type: dataType.Float()},
IntCol: {type: dataType.Int(false)},
BoolCol: {type: dataType.Bit()}
}
);
}
}
column data type
目前支持如下的数据类型. 数据类型定义在dataType
类型中
类型 | 对应创建方法 | 说明 |
---|
VarChar | dataType.VarChar(length) | |
NVarChar | dataType.NVarChar(length) | |
Text | dataType.Text() | |
NText | dataType.NText() | |
Char | dataType.Char(length) | |
NChar | dataType.NChar(length) | |
Bit | dataType.Bit() | 对应boolean 类型 |
BigInt | dataType.BigInt(unsigned) | 当数值在Number.MAX_SAFE_INTEGER之内时为number , 当数值超过时, 为bignumber (查看bignumber.js库 ( https://www.npmjs.com/package/bignumber.js ) |
TinyInt | dataType.TinyInt(unsigned) | |
SmallInt | dataType.SmallInt(unsigned) | |
Int | dataType.Int(unsigned) | |
Float | dataType.Float(unsigned) | |
Numeric | dataType.Numeric(unsigned, precision, scale) | |
Decimal | dataType.Decimal(unsigned, precision, scale) | |
Real | dataType.Real(unsigned) | |
DateTime | dataType.DateTime() | 对应js的Date 类型; 数据库中使用utc时间存储. 本地设置时使用本地时间, 系统会自动转换. 在数据库中, mssql: 存储的格式为 (YYYY-MM-DD hh:mm:ss.SSS) sqlserver中可使用smalldatetime ,datetime ,datetime2 类型. mysql: datetime (YYYY-MM-DD hh:mm:ss.SSS) 使用length来指明ms数据存储. |
Binary | dataType.Binary(length) | 对应js的Buffer 类型 |
VarBinary | dataType.VarBinary(length) | 对应js的Buffer 类型 |
name map
在定义数据表时, 可以对数据表名和字段名称进行映射, 隐藏真正的字段名称以便保证安全性.
在逻辑编写中使用有意义的名称, 而在数据库定义中使用无意义的名称来保证安全性.
var tablebase = require('febs-db').tablebase;
var dataType = require('febs-db').dataType;
class TableDemo extends tablebase {
constructor() {
super(
'Admin',
['ID', 'IntCol'],
{
ID: {type: dataType.BigInt(true), map:'col1', key: true},
Name: {type: dataType.Varchar(10), map:'col2'},
NumberCol:{type: dataType.Float(), map:'col3'},
IntCol: {type: dataType.Int(false), map:'col4'},
BoolCol: {type: dataType.Bit(), map:'col5'}
}
);
}
}
database.registerTable(new TableDemo(), 'realName');
Connect db
var database = require('febs-db').database;
var opt = {
connectTimeout : 5000,
queryTimeout : 5000,
acquireTimeout : 5000,
queueLimit : 200,
connectionLimit : 10,
idleTimeoutMillis : 600000,
host : '',
port : 3306,
database : '',
user : '',
password : '',
encrypt : true,
table_prefix : '',
};
var db = new database(
'mysql',
opt
);
Query db
add
直接使用数据对象添加
let mod = {Name:'demo', IntCol:10};
table.add(mod)
.then((ret)=>{
console.log(`Result of exec is: ${ret}`);
})
.catch(e=>{});
remove
使用查询条件进行删除.
!! 查询条件可以使用 condition 进行构造, condition会对数据类型进行验证.
var where = table.condition.equal('id', 1);
table.remove(where);
.then((ret)=>{
console.log(`Result of exec is: ${ret}`);
})
.catch(e=>{});
update
-
更新方法需传入一个对象, 更新其中的非主键对应的值;
-
如果参数中附带主键, 则主键将作为更新的查询条件之一;
-
如果不附带主键, 则执行条件where必须存在, 否则抛出异常.
let mod = {
ID: 1,
name: "name",
intCol: table.condition.col_inc(1),
intCol2:table.condition.col_origin_sql('`intCol2`+1')
};
table.update(mod);
.then((ret)=>{
console.log(`Result of exec is: ${ret}`);
})
.catch(e=>{});
count
let where = '';
where += table.condition.equal('id', 43);
where += 'AND';
where += table.condition.like('name', '%123');
table.count(where)
.then(count=>{
console.log(`Result is ${count}`);
})
.catch(err=>{})
exist
table.exist(1)
.then(ret=>{
console.log(`Result is ${ret}`);
})
.catch(err=>{})
select
查询时如果不指定分页信息, 则默认查询100条.
var where = '';
where += table.condition.equal('ID', 1);
where += 'AND';
where += table.condition.more_than('ID', 1);
table.select(where, {
cols: ['ID','Name'],
offset: 0,
limit: 100
})
.then(ret=>{})
.catch(e=>{});
table.select(where, {
cols: ['COUNT(ID) as x','Name'],
offset: 0,
limit: 100
})
.then(ret=>{})
.catch(e=>{});
selectLockRow
锁行方式查询, 只能在事务中使用此方式. 在事务结束或update之后自动解锁.
table.selectLockRow(id, ['ID','Name'])
.then(ret=>{})
.catch(e=>{});
store procedure
调用如下的存储过程.
# mysql procedure
CREATE PROCEDURE procedureName(out out1 int, out out2 int, in userid int)
BEGIN
select count(id) INTO out1 from table1;
select count(id) INTO out2 from table1 where id=userid;
select out1, out2;
END
调用过程如下:
var procedureParams = require('febs-db').procedureParams;
var dataType = require('febs-db').dataType;
var params = new procedureParams();
params.addOut('out1', dataType.Int());
params.addOut('out2', dataType.Int());
params.addIn('userid', dataType.Int(), 2);
db.execProcedure('procedureName', params)
.then(ret=>{
console.log('');
console.log('[promise procedure]');
console.log(ret.out.out1);
console.log(ret.out.out2);
})
.catch(e=>{
console.log(e);
})
condition
构造key=value
条件语句
table.condition.equal('colName', value)
构造key>value
条件语句
table.condition.more_than('colName', value)
构造key>=value
条件语句
table.condition.more_equal('colName', value)
构造key<=value
条件语句
table.condition.less_equal('colName', value)
构造key<value
条件语句
table.condition.less_than('colName', value)
构造key<>value
条件语句
table.condition.not_equal('colName', value)
构造key LIKE value
条件语句
table.condition.like('colName', value)
构造key BETWEEN value1 AND value2
条件语句
table.condition.between('colName', value1, value2)
构造key IN (value1,value2...)
条件语句
table.condition.in('colName', valueArray)
构造key NOT IN (value1,value2...)
条件语句
table.condition.not_in('colName', valueArray)
复杂逻辑条件.
let where = '';
where += table.condition.equal('colName', value);
where += 'AND';
where += table.condition.equal('colName2', value2);
在update中使用, 构造自增字段.
let mod = {
id: 1,
col1: table.condition.col_inc(2)
}
await table.update(mod);
在update中使用, 调用原始sql语句.
let mod = {
id: 1,
col1: table.condition.col_origin_sql('table2.col2+col1')
}
await table.update(mod);
transaction
- 执行事务系统将创建一个独立的连接, 事务完成后连接对象将重新被插入到连接池中. 在嵌套的事务中, 不会重新创建连接.
- 事务处理函数中, 返回
false
或发生异常
将rollback
, 返回true
将commit
- 允许事务嵌套调用.
- 仅支持行级锁, 不支持表级锁.
isolation level
事务隔离级别在 isolationLevel
类中定义;
事务默认提供共享锁
, 需要获得排他锁
使用 selectLockRow
var isolationLevel = require('febs-db').isolationLevel;
isolationLevel.Read_uncommitted;
isolationLevel.Read_committed;
isolationLevel.Repeatable_read;
isolationLevel.Serializable;
| 脏读 | 不可重复读 | 幻读 |
---|
Read_uncommitted | √ | √ | √ |
Read_committed | × | √ | √ |
Repeatable_read | × | × | √ |
Serializable | × | × | × |
global.dbagent.sqlLogCallback = function(err, sql, isTransactionBeginOrEnd) {
console.log(
`
${febs.utils.getTimeString(Date.now(), 'yyyy-MM-dd hh:mm:ss')}
SQL: ${sql}
ERR: ${err}
`);
}
global.dbagent.transaction(
isolationLevel.Repeatable_read,
async function(db){
return true;
})
.then(res=>{
if (res)
console.log(`the transaction is committed`);
else
console.log(`the transaction is rollback`);
})
.catch(err=>{ });
Join
let table1 = new Table1(...);
let table2 = new Table2(...);
let table3 = new Table3(...);
let join = table1.join_inner(table2)
.set_alias1('A')
.set_alias2('B')
.on('A.id = B.id')
.join_inner(table3);
let joinSql = join.sql_select(...);
let r = await db.exec(joinSql);
db.ret_data_cvt(r.rows, table1, table2, table3);
Class database API
constructor
constructor(dbtype, opt)
- dbtype: 数据库类型, 目前仅支持
'mysql'
, 'mssql'
- opt: 连接参数
var opt = {
connectTimeout : 5000,
queryTimeout : 5000,
acquireTimeout : 5000,
queueLimit : 200,
connectionLimit : 10,
host : '',
port : 3306,
database : '',
user : '',
password : '',
table_prefix : '',
};
registerTable
registerTable(table, mapName=null) : tablebase
exec
exec(sql)
execProcedure
execProcedure(name, procedureParams)
transaction
transaction(isolationLevel, taskCB)
dbType
get dbtype()
sqlLogCallback
set sqlLogCallback(cb)
get sqlLogCallback()
escapeLike
escapeLike(likeSql)
type_cast
type_cast(type, value)
ret_data_cvt
ret_data_cvt(rows, ...table)
Class tablebase API
constructor
constructor(tablename, idKeyName, model)
model
的定义格式如下:
{
colName: {type
: dataType.BigInt(10), map
: '', key
: true}, // the auto-incrementing
...
}
colName
: 表示列名称type
: 表示列类型, 查看 column data typemap
: 映射数据库中真实的字段名称. 如果不指定则使用colName
key
: 是否是自增键; (同一个表只能有一个自增键, 当指定多个自增键时, 只认为最后一个为自增)
add
add( item )
remove
remove( where )
update
update( item, where = null )
selectLockRow
selectLockRow( id, cols = null )
select
select( where, opt = null )
count
count(where = null)
exist
exist(id)
sql_add
sql_add(item)
sql_remove
sql_remove(where)
sql_update
sql_update(item, where = null)
sql_selectLockRow
sql_selectLockRow(id, cols = null, alias=null)
sql_select
sql_select(where, opt = null, alias=null)
sql_count
sql_count(where, alias=null)
tablename
get tablename()
condition
get condition()
getLogicColName(mapName)
db
get db()
join_inner
join_inner(tableB)
join_cross
join_cross(tableB)
join_left
join_left(tableB)
join_right
join_right(tableB)
join_full
join_full(tableB)
Class condition API
equal
equal( key, value )
more_than
more_than( key, value )
more_equal
more_equal( key, value )
less_equal
less_equal( key, value )
less_than
less_than( key, value )
not_equal
not_equal( key, value )
like
like( key, value )
between
between( key, value1, value2 )
in
in( key, valueArray )
not_in
not_in( key, valueArray )
col_inc
col_inc(n)
col_origin_sql
col_origin_sql(v)
Class dataType API
NULL
NULL ()
getType
getType (value)
isIntegerType
isIntegerType (value)
isStringType
isStringType (value)
getValueBigInt
getValueBigInt(sqlValue)
getValueBit
getValueBit(sqlValue)
Class join
sql_select
sql_select(where, opt = null)
set_alias1
set_alias1(aliasName)
set_alias2
set_alias2(aliasName)
set_on
set_on(onSql)
table1
get table1;
get table2;
alias1
get alias1;
get alias2;
join_inner
join_inner(tableB)
join_cross
join_cross(tableB)
join_left
join_left(tableB)
join_right
join_right(tableB)
join_full
join_full(tableB)