ORM框架: 对象关系映射,面对对象sql
本节使用sequelize作为orm-sql框架,数据库为sqlite
同样的,需要安装相应的js版数据库Driver,如: PostgreSQL -> pg, mysql/mariadb -> mysql, sqlite -> sqlite3…
npm install sqlite3
npm install sequelize
const app = express();
const { Sequelize } = require('sequelize');
拷贝第一节HelloWorld的项目
指定方言为sqlite,持久化路径为本目录下的data.db
const sqlite = new Sequelize({
dialect: 'sqlite',
storage: './data.db'
})
sequelize主打一个面对对象sql,因此我们要建立一个对应数据表的类
就和上一节一样,弄一张一模一样的user表吧:
const { Sequelize,DataTypes } = require('sequelize');
Model.init(schema,options)
const User = sqlite.define('User', {
id: {
primaryKey: true,
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true
},
// 在这里定义模型属性
uname: {
type: DataTypes.STRING,
allowNull: true
},
passwd: {
type: DataTypes.STRING
// allowNull 默认为 true
}
}, {
// 直接指定表名,不指定的话sequelize将默认以模型的复数形式作为表名
tableName: 'user'
});
还有另一种方法,效果是一样的,看个人喜好使用:
const { Sequelize,DataTypes,Model } = require('sequelize');
Model.init(schema,options)
User继承Model类
class User extends Model {};
User.init(
{
id: {
primaryKey: true,
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true
},
// 在这里定义模型属性
uname: {
type: DataTypes.STRING,
allowNull: true,
},
passwd: {
type: DataTypes.STRING,
defaultValue: '123456', //默认值
//allowNull 默认为 true
}
},
{
// 这是其他模型参数
sqlite, // 我们需要传递连接实例
modelName: 'User1', // 我们需要选择模型名称,
// 直接指定表名
tableName: 'user',
}
);
Model.sync
: 底层执行的是 create table if not exist
Model.sync({force: true})
: 底层是先 drop if 然后 createModel.sync({alter: true})
:花里胡哨的,总之就是保证数据库中有和该模型对应的表
我们使用User.sync()
创建一张user表
app.put('/db/user', async function (req, res) {
let what = await User.sync();
res.json(what);
});
使用api调试工具PUT 127.0.0.1:8080/db/user,将会得到1,注意只要能成功映射到到数据表都是1
用Beekeeper查看我们的user表,你会发现和我们定义的模型有点不一样:多了2个字段——createdAt和updatedAt,即创建时间和修改时间
sequelize会自动管理这两个字段,注意当你使用了其他的sql工具修改表,这两个字段不会自动更新
如果你不想要这两个值,或者想换个名字,可以在定义模型时往options添加这些设置:
// 禁止createdAt和updatedAt
timestamps: false,
// 只禁止createdAt
createdAt: false,
// 给updatedAt换个名字
updatedAt: 'updateTime'
drop()方法,底层是 drop if,既可以作用于模型,也可作用于数据库:
sqlite.drop(); //这将删除当前data.db下所有的表
我们使用User.drop()
来删除user表
app.delete('/db/user', async function (req, res) {
let what = await User.drop();
res.json(what);
});
使用api调试工具PUT 127.0.0.1:8080/db/user,将会得到1,注意即使表已经没了,也是1
在操作表记录前,我们先通过模型(Model.build
)创建一个实例,然后调用save()
将这个实例插入到表中
当然,如果你从前端拿来的数据不需要进行处理和转化就能拿来用,也可以直接用Model.create
插入记录
app.use(express.json({type: 'application/json'}));
app.put('/db/user/record', async function (req, res) {
/**前端请求体
{
"uname": "evanp",
"passwd": "iloveu"
}
*/
try {
let user = User.build(req.body);
let what = await user.save();
// let what = await User.create(req.body);
res.json(what);
}catch(e){
res.json(e);
}
});
使用api调试工具PUT 127.0.0.1:8080/db/user/record,携带相应的请求体,将会得到:
{
"id": 1,
"uname": "evanp",
"passwd": "iloveu",
"updatedAt": "2023-03-19T08:03:37.964Z",
"createdAt": "2023-03-19T08:03:37.964Z"
}
是的,添加记录成功后它会顺便把整条记录查出来作为返回结果
Ok,那么现在user表里已经有了id=1的一条记录了,让我们试一下创建相同id的记录会怎么样…
服务器直接挂了,我们可不希望这样,这意味着有任何不妥的sql都可能导致服务器崩溃,那怎么办呢?
有的朋友可能记起来了,在上一节中,使用了try-catch语法糖包裹sql操作,这是一种不错的方法
sequelize模型内置了一些方法使得我们可以基于模型直接查询
select * from ...
select * from ... LIMIT 1
这些方法都可以添加options参数设置WHERE,LIMIT等限制条件
我们使用findOne来查询evanp和用户名和密码都对的上的一条记录:
//我为了方便直接url传参了,实际上为了隐私,至少应该放在请求体内
app.get('/db/user/record', async function (req, res) {
let evanp = await User.findOne({where: req.query});
res.json(evanp);
});
如果你只需要查询其中某些字段,就在options中设置attributes:
User.findAll({
attributes: ['id','uname']
});
如果想给字段取别名,就比如像这样给id取名uid:
User.findAll({
attributes: [['id','uid'],'uname']
});
Model.update(修改项,限制)
app.post('/db/user/record', async function (req, res) {
/*请求体
{
"set":{
"passwd": "123456"
},
"where": {
"uname": "evanp",
"passwd": "iloveu"
}
}
*/
let what = await User.update(req.body.set,{where: req.body.where})
res.json(what);
});
使用api工具进行调试,修改成功将返回1,修改失败将返回0(找不到/改不了)
Model.destroy(限制)
app.delete('/db/user/record', async function (req, res) {
/*请求体
{
"uname": "evanp",
"passwd": "123456"
}
*/
let what = await User.destroy({where: req.body})
res.json(what);
});
使用api工具进行调试,删除成功将返回1,删除失败将返回0(找不到/删不了)
当然了,如果你需要直接使用sql语句,也是可以的,连接实例.query(sqlStr)
即可
通常,返回结果包含2个值,一个是结果数组,一个是相关信息
app.post('/db/user/record/freely', async function (req, res) {
/*json请求体
{
"sql": "xxx"
}
*/
let what = null;
try {
what = await sqlite.query(req.body.sql);
} catch (e) {
what = e;
}
res.json(what);
});
执行insert前要注意,如果这张表是经过sequelize同步的,也许会有那两个时间字段的,别忘了
本节的例子仅仅为了演示在express.js中如何运用sequelize操作数据库,关于sequelize的更多拓展和高级使用方法,请移步sequelize官方文档https://www.sequelize.cn/