来源:Node.js

在后端直接写SQL语句,不仅繁琐,还可能会引发SQL注入的风险

Knex

Knex是一个查询生成器,可以使用js代码生成和执行SQL查询语句

它提供了一种简单和直观的方式来与关系型数据库进行交互,而无需直接编写SQL语句

可以使用Knex定义表结构、执行查询、插入、更新和删除数据等操作

安装与配置

安装

knex支持多种数据库:pg、sqlite3、mysql2、oracledb、tedious等

1
2
3
4
5
6
7
8
9
10
11
12
# 安装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

配置

1
2
3
4
5
6
db:
user: root
host: CherikoM
port: 3306
password: '114514'
database: test

连接数据库

1
2
3
4
5
import knex from 'knex'
const db = knex({
client: "mysql2",
connection: config.db
})

使用

定义表结构

1
2
3
4
5
6
7
8
9
db.schema.createTable('user', (table) => {
table.increments('id') // 自增id
table.integer('age') // age整数
table.string('name') // name字符串
table.string('address') // address字符串
table.timestamps(true,true) // 创建时间和更新时间
}).then(() => {
console.log('创建成功')
})

增删改查

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
import mysql2 from 'mysql2/promise'
import fs from 'node:fs'
import jsyaml from 'js-yaml'
import express from 'express'
import knex from 'knex'

// 读取配置
const yaml = fs.readFileSync('./db.config.yaml', 'utf8')
const config = jsyaml.load(yaml)
const db = knex({
client: "mysql2",
connection: config.db
})

const app = express()
app.use(express.json())

// 查询全部数据
app.get('/', async (req, res) => {
const data = await db('user').select().orderBy('id', 'desc')
const total = await db('user').count('* as total')

// 也可以直接用SQL语句操作
// db.raw("select * from user").then(data=>{ console.log(data) })

// 连表,相当于SELECT * FROM `user` LEFT JOIN `list` ON `user`.`id` = `list`.`user_id`
// const table = await db('user').select().leftJoin('list', 'user.id', 'list.user_id')

res.json({
code: 200,
data,
total: total[0].total,
sql: db('user').select().toSQL().sql // 也可以将操作转换成SQL语句
})
})

// 根据id查询单个数据
app.get('/user/:id', async (req, res) => {
const row = await db('user').select().where({ id: req.params.id })
res.json({
code: 200,
data: row
})
})

// 添加数据
app.post('/create', async (req, res) => {
const { name, age, address } = req.body
const detail = await db('user').insert({ name, age, address })
res.send({
code: 200,
data: detail
})
})

// 更新数据
app.post('/update', async (req, res) => {
const { name, age, address, id } = req.body
const info = await db('user').update({ name, age, address }).where({ id })
res.json({
code: 200,
data: info
})
})

// 删除数据
app.post('/delete', async (req, res) => {
const info = await db('user').delete().where({ id: req.body.id })
res.json({
code: 200,
data: info
})
})

app.listen(11451, () => {
console.log(`Server on 11451`)
})

事务

事务能确保一组数据库操作的原子性,即要么全部成功提交,要么全部回滚

例如A给B转账,涉及到A的钱减少和B的钱增加,需要保证这两个数据的一致性

1
2
3
4
5
6
7
8
9
10
11
12
db.transaction(async (trx) => {
try {
await trx('bill').update({money: -100}).where({ id: 1 }) // 操作A
await trx('bill').update({money: +100}).where({ id: 2 }) // 操作B
// 提交事务
await trx.commit()
}
catch (err) {
// 回滚事务
await trx.rollback()
}
})