knex
上一个文章中我们还使用sql语句去编写接口,在实际工作中我们很少用到sql语句,sql语句编写起来比较繁琐,还有sql注入风险。
Knex是一个基于JavaScript的查询生成器,它允许你使用JavaScript代码来生成和执行SQL查询语句。它提供了一种简单和直观的方式来与关系型数据库进行交互,而无需直接编写SQL语句。你可以使用Knex定义表结构、执行查询、插入、更新和删除数据等操作。
Knex的安装和设置
knex支持多种数据库 pg sqlite3 mysql2 oracledb tedious
用什么数据库安装对应的数据库就行了
sh
#安装knex
$ npm install knex --save
#安装你用的数据库
$ npm install pg
$ npm install pg-native
$ npm install sqlite3
$ npm install better-sqlite3
$ npm install mysql
$ npm install mysql2
$ npm install oracledb
$ npm install tedious
连接数据库
js
import knex from 'knex'
const db = knex({
client: "mysql2",
connection: config.db
})
yaml
db:
user: root
password: '123456'
host: localhost
port: 3306
database: xiaoman
实现增删改差和连表
js
// import mysql2 from "mysql2/promise";
import * as jsyaml from "js-yaml";
import fs from "fs";
import path from "path";
import { fileURLToPath } from "url";
import express from "express";
import knex from "knex";
// ESM 获取当前文件所在目录路径
const __filename = fileURLToPath(import.meta.url); //C:\CN\全栈AI\node\nodecode\mysql-express-yaml\index.js
const __dirname = path.dirname(__filename); //C:\CN\全栈AI\node\nodecode\mysql-express-yaml
console.log(__filename, __dirname);
// 读取 db.config.yaml 文件
const yamlText = fs.readFileSync(
path.join(__dirname, "./db.config.yaml"),
"utf8"
);
const config = jsyaml.load(yamlText);
// 创建数据库连接------是异步的,所以下面都要用async await
// const sql = await mysql2.createConnection({
// ...config.db,
// });
// console.log('sql', sql)
const db = knex({
client: "mysql2",
connection: config.db,
});
// knex所有代码直接编写是没有效果的,需要.then才会起效果
db.schema
.createTableIfNotExists("list", (table) => {
table.increments("id"); //id自增
table.integer("age"); //age 整数
table.string("name"); //name 字符串
table.string("hobby"); //hobby 字符串
table.timestamps(true, true); //创建时间和更新时间
})
.then(() => {
console.log("创建成功");
});
const app = express();
app.use(express.json());
//查询接口 全部
app.get("/", async (req, res) => {
// const [data] = await sql.query("select * from user");
const data = await db("user").select().orderBy("id", "desc");
const count = await db("user").count("* as total");
// [{total: 1}]
// db.raw("select * from user").then((data) => {
// console.log(data); //也是可以从数据库中查询到
// });
// 连表------高级玩法
const table = await db("user")
.select()
.leftJoin("table", "user.id", "table.user_id");
res.json({
data,
table,
total: count[0].total,
// sql: db("list").select().toSQL().sql 可以用来调试
});
});
//单个查询 params
app.get("/user/:id", async (req, res) => {
const row = await db("list").select().where({ id: req.params.id });
// const [row] = await sql.query(
// `select * from user where id = ${req.params.id}`
// );
// const [row] = await sql.query(`select * from user where id = ?`, [
// req.params.id,
// ]);
res.send(row);
});
//新增接口
app.post("/create", async (req, res) => {
const { name, age, hobby } = req.body;
await db("list").insert({ name, age, hobby });
// await sql.query(`insert into user(name,age,address) values(?,?,?)`, [
// name,
// age,
// address,
// ]);
res.send({ ok: 1 });
});
//编辑
app.post("/update", async (req, res) => {
const { name, age, hobby, id } = req.body;
await db("list").update({ name, age, hobby }).where({ id });
// await sql.query(`update user set name = ?,age = ?,address = ? where id = ?`, [
// name,
// age,
// address,
// id,
// ]);
res.send({ ok: 1 });
});
//删除
app.post("/delete", async (req, res) => {
// await sql.query(`delete from user where id = ?`, [req.body.id]);
await db("list").delete().where({ id: req.body.id });
res.send({ ok: 1 });
});
const port = 3000;
app.listen(port, () => {
console.log(`Example app listening on port ${port}`);
});
事务
你可以使用事务来确保一组数据库操作的原子性,即要么全部成功提交,要么全部回滚
例如A给B转钱,需要两条语句,如果A语句成功了,B语句因为一些场景失败了,那这钱就丢了,所以事务就是为了解决这个问题,要么都成功,要么都回滚,保证金钱不会丢失。
js
//伪代码
db.transaction(async (trx) => {
try {
await trx('list').update({money: -100}).where({ id: 1 }) //A
await trx('list').update({money: +100}).where({ id: 2 }) //B
await trx.commit() //提交事务
}
catch (err) {
await trx.rollback() //回滚事务
}
}).then(() => {
console.log('成功')
}).catch(() => {
console.log('失败')
})