数据服务
一个数据服务首先它是一个服务(我们通常用的是http的服务,当然也可能会使用socket或mq,甚至webservice的服务),其次这个服务的任务是用来处理数据,而数据往往在数据库中存放。
一个数据库服务的逻辑如下:
- 获取调用者传参
- 判定调用者传参是否合法
- 处理调用者传来的参数以备使用
- 使用处理好的参数对某个(些)数据库表进行一次或多次增删改查
- 其它业务逻辑
- 返回给调用者服务执行结果
数据库服务
安装并启动一个数据库服务,我们推荐使用postgresql
或mariadb
(mysql
)。通常的,如果数据库服务正常运行,可以通过一些数据库的工具访问它。postgresql的客户端工具推荐使用pgadmin,mysql
的客户端工具推荐workbench.
如果是使用docker容器启动服务,有更简单的方式,打开浏览器地址http://127.0.0.1:8080(如果数据库服务在单独的服务器安装,则需要改成服务器ip地址),即可连接并查看数据库.
使用原子操作
我们封装了一个原子操作来帮助你完成数据库调用。
import an49 from '@mmstudio/an000049';
const db = an49();
安装依赖及配置文件
在使用原子操作之前,需要安装原子操作的依赖
postgresql
yarn add @mmstudio/an000049 @mmstudio/config pg
对应配置文件mm.json
{
"dbconfig": {
"client": "pg",
"connection": "postgres://01factory:01factory@127.0.0.1:5432/01factory",
"pool": {
"min": 0,
"max": 7
}
}
}
mysql
驱动一
yarn add @mmstudio/an000049 @mmstudio/config mysql2
对应配置文件mm.json
{
"dbconfig": {
"client": "mysql2",
"connection": "postgres://01factory:01factory@127.0.0.1:3306/01factory",
"pool": {
"min": 0,
"max": 7
}
}
}
驱动二
yarn add @mmstudio/an000049 @mmstudio/config mysql
对应配置文件mm.json
{
"dbconfig": {
"client": "mysql",
"connection": "postgres://01factory:01factory@127.0.0.1:3306/01factory",
"pool": {
"min": 0,
"max": 7
}
}
}
SqlServer
yarn add @mmstudio/an000049 @mmstudio/config mssql
对应配置文件mm.json
{
"dbconfig": {
"client": "mssql",
"connection": "postgres://01factory:01factory@127.0.0.1:3306/01factory"
}
}
Oracle
yarn add @mmstudio/an000049 @mmstudio/config oracledb
yarn add sqlite3
Sqlite
yarn add @mmstudio/an000049 @mmstudio/config sqlite3
使用
interface Table001 {
f001: string;
f002: string;
f003: string;
f004: string;
f005: number;
}
const tb001 = db<Table001>('tb001');
创建表
一般情况下不会在服务中动态建表。这种情况下,数据库管理员需要限制给到开发人员连接数据库的用户的权限。
await db.schema.createTableIfNotExists('tb001', (builder) => {
builder.comment('用户表');
builder.string('f001').comment('用户ID').primary();
builder.string('f002').comment('用户姓名');
builder.string('f003').comment('头像');
builder.string('f004').comment('手机号');
builder.integer('f005').comment('性别');
builder.index('f001');
builder.unique(['f001']);
});
查询记录
用法一
常用的分页查询、复杂条件的查询等
const tb001 = db<Table001>('tb001');
const dt001 = await tb001.select('f002', 'f004').where('f001', '=', '01factory').andWhere('f002', 'like', '%01%').top(10).offset(0).orWhere('f003', '>', 1);
const d001 = dt001.map((r)=>{
return {
...r,
f005: `${r.f002}-${r.f004}`
};
});
用法二
查询条件如果是多条相等查询,推荐用以下方法,简便,且如果字段名称有重命名时,这里ts会自动提示,甚至自动重命名。
const tb001 = db<Table001>('tb001');
const dt001 = await tb001.select('f002', 'f004').where({f001: '01factory'});
const d001 = dt001.map((r)=>{
return {...r};
});
用法三
示例:查询首行代码
const tb001 = db<Table001>('tb001');
const r001 = await tb001.first('f002', 'f004').where({f001: '01factory'});
const d001 = {...r001};
用法四
查询函数
const tb001 = db<Table001>('tb001');
const [{count}] = await tb001.count<Record<'count', number>>('f001', {as: 'count'})
其它用法
参考https://knexjs.org/上的用法。
增加记录
const tb001 = db<Table001>('tb001');
await tb001.insert({f001:'01factory'});
await tb001.insert([{f001:'01factory'},{f001:'01'},{f001:'factory'}]);
修改记录
const tb001 = db<Table001>('tb001');
await tb001.update({f001:'01factory'}).where('f001', '=', '01');
删除记录
const tb001 = db<Table001>('tb001');
await tb001.del().where('f001', '=', '01factory');
事务
await db.transaction<string>(async (trs) => {
const tb001 = trs<Table001>('tb001');
await tb001.del().where('f002', '=', '01');
const tb002 = trs<Table001>('tb001');
await tb002.update({f001:'01factory'}).where('f001', '=', '01');
await trs.commit();
return '01factory';
});
Join
左连接,右连接,交叉连接用法与下相似,可推可得之。
const data = await tb001.join<Table002>('tb002', 'tb001.f001', '=', 'tb002.f001').select({a002: 'tb001.f002', b002: 'tb002.f002'});
注意
bigint
因为大数字类型(bigint
)直接转为number
可能会溢出,所以此类字段在查询时结果会被转化为string
类型,这样的做法也方便服务向客户端通信。在增加或更新记录时没有这个限制,会自动进行类型转换。
mysql
使用mysql时,直接查出的对象不是纯粹的Object对象,必须进行处理。简单的处理就像上面示例给出的示例
const tb001 = db<Table001>('tb001');
const dt001 = await tb001.select('f002', 'f004').where({f001: '01factory'});
const data001 = dt001.map((r)=>{
return {
...r,
f002: trans(r.f002)
};
});