下面的语句若没有特殊注明,默认都书写在 app/service 下。
Create
可以直接使用 insert 方法插入一条记录。
1 | // 插入 |
Read
可以直接使用 get 方法或 select 方法获取一条或多条记录。select 方法支持条件查询与结果的定制。
查询一条记录
1 | const post = await this.app.mysql.get('posts', { id: 12 }); |
查询全表
1 | const results = await this.app.mysql.select('posts'); |
条件查询和结果定制
1 | const results = await this.app.mysql.select('posts', { // 搜索 post 表 |
Update
可以直接使用 update 方法更新数据库记录。
1 | // 修改数据,将会根据主键 ID 查找,并更新 |
Delete
可以直接使用 delete 方法删除数据库记录。
1 | const result = await this.app.mysql.delete('posts', { |
直接执行 sql 语句
插件本身也支持拼接与直接执行 sql 语句。使用 query 可以执行合法的 sql 语句。
注意!!我们极其不建议开发者拼接 sql 语句,这样很容易引起 sql 注入!!
如果必须要自己拼接 sql 语句,请使用 mysql.escape 方法。
参考 preventing-sql-injection-in-node-js
1 | const postId = 1; |
使用事务
MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等。这时候使用事务处理可以方便管理这一组操作。 一个事务将一组连续的数据库操作,放在一个单一的工作单元来执行。该组内的每个单独的操作是成功,事务才能成功。如果事务中的任何操作失败,则整个事务将失败。
一般来说,事务是必须满足4个条件(ACID): Atomicity(原子性)、Consistency(一致性)、Isolation(隔离性)、Durability(可靠性)
- 原子性:确保事务内的所有操作都成功完成,否则事务将被中止在故障点,以前的操作将回滚到以前的状态。
- 一致性:对于数据库的修改是一致的。
- 隔离性:事务是彼此独立的,不互相影响
- 持久性:确保提交事务后,事务产生的结果可以永久存在。
因此,对于一个事务来讲,一定伴随着 beginTransaction、commit 或 rollback,分别代表事务的开始,成功和失败回滚。
egg-mysql 提供了两种类型的事务。
手动控制
优点:beginTransaction, commit 或 rollback 都由开发者来完全控制,可以做到非常细粒度的控制。
缺点:手写代码比较多,不是每个人都能写好。忘记了捕获异常和 cleanup 都会导致严重 bug。
1 | const conn = await app.mysql.beginTransaction(); // 初始化事务 |
自动控制:Transaction with scope
1 | API:beginTransactionScope(scope, ctx) |
scope: 一个 generatorFunction,在这个函数里面执行这次事务的所有 sql 语句。
ctx: 当前请求的上下文对象,传入 ctx 可以保证即便在出现事务嵌套的情况下,一次请求中同时只有一个激活状态的事务。
优点:使用简单,不容易犯错,就感觉事务不存在的样子。
缺点:整个事务要么成功,要么失败,无法做细粒度控制。
1 | const result = await app.mysql.beginTransactionScope(async conn => { |
表达式(Literal)
如果需要调用 MySQL 内置的函数(或表达式),可以使用 Literal。
内置表达式
NOW():数据库当前系统时间,通过 app.mysql.literals.now
获取。
1 | await this.app.mysql.insert(table, { |
=> INSERT INTO $table
(create_time
) VALUES(NOW())
自定义表达式
下例展示了如何调用 MySQL 内置的 CONCAT(s1, …sn) 函数,做字符串拼接。
1 | const Literal = this.app.mysql.literals.Literal; |