事务
Lucid 对事务和保存点具有一流的支持。您可以通过调用 Database.transaction
方法来创建新事务。
import Database from '@ioc:Adonis/Lucid/Database'
// 创建事务
const trx = await Database.transaction()
就像 Database
模块一样,您还可以使用 trx
对象来创建查询构建器实例。
// title: 插入
await trx
.insertQuery()
.table('users')
.insert({ username: 'virk' })
// title: 查询
await trx
.query()
.select('*')
.from('users')
执行完查询后,您必须 commit
或者 rollback
事务。否则,查询将挂起直到超时。
以下是使用带有插入查询的事务的完整示例。
const trx = await Database.transaction()
try {
await trx
.insertQuery()
.table('users')
.insert({ username: 'virk' })
await trx.commit()
} catch (error) {
await trx.rollback()
}
事务托管
上面的示例要求您必须通过将代码包装在 try/catch
块中来手动 commit
或 rollback
事务。事务托管会自动为您执行此操作。
您可以通过将回调传递给 transaction
方法来创建事务托管。
- 执行回调后事务自动提交。
- 如果回调引发异常,事务将自动回滚并重新引发异常。
await Database.transaction(async (trx) => {
await trx
.insertQuery()
.table('users')
.insert({ username: 'virk' })
})
您还可以从回调中返回一个值,然后在顶级范围内访问它。例如:
const userId = await Database.transaction(async (trx) => {
const response = await trx
.insertQuery()
.table('users')
.insert({ username: 'virk' })
return response[0] // 👈 返回值
})
隔离级别
您可以在调用 Database.transaction
方法时定义事务的隔离级别。
await Database.transaction({
isolationLevel: 'read uncommitted'
})
以下是使用事务托管定义隔离级别的示例。
await Database.transaction(async (trx) => {
// 这里使用 trx
}, {
isolationLevel: 'read committed'
})
以下是可用隔离级别的列表。
- "read uncommitted"
- "read committed"
- "snapshot"
- "repeatable read"
- "serializable"
事务传递
事务 API 不仅限于从事务对象创建查询构建器实例。您还可以将其传递给现有的查询构建器实例或模型。
import Database from '@ioc:Adonis/Lucid/Database'
const trx = await Database.transaction()
Database
.insertQuery({ client: trx }) 👈
.table('users')
.insert({ username: 'virk' })
或者在稍后阶段使用 useTransaction
方法传递它。
import Database from '@ioc:Adonis/Lucid/Database'
const trx = await Database.transaction()
Database
.insertQuery()
.table('users')
.useTransaction(trx) 👈
.insert({ username: 'virk' })
保存点
每次创建嵌套事务时,Lucid 在幕后创建一个新的 [savepoint] (en.wikipedia.org/wiki/Savepoint)。
由于事务需要专用连接,因此使用保存点可以减少所需连接的数量。
import Database from '@ioc:Adonis/Lucid/Database'
// 创建事务
const trx = await Database.transaction()
// 这次创建了一个保存点
const savepoint = await trx.transaction()
// 也可以回滚保存点
await trx.rollback()
使用带有 Lucid 模型的事务
您可以使用 useTransaction
方法将事务传递给模型实例。
在模型类中,您可以使用 this.$trx
属性访问事务对象。该属性仅在事务执行期间可用。在 commit
或 rollback
之后,它将被重置为 undefined
。
import User from 'App/Models/User'
import Database from '@ioc:Adonis/Lucid/Database'
// 高亮开始
await Database.transaction(async (trx) => {
const user = new User()
user.username = 'virk'
user.useTransaction(trx)
await user.save()
})
// 高亮结束
模型查询构建器
就像标准查询构建器一样,您也可以将事务传递给模型查询构建器。
import Database from '@ioc:Adonis/Lucid/Database'
import User from 'App/Models/User'
const trx = await Database.transaction()
const users = await User
.query({ client: trx }) 👈
.where('is_active', true)
在事务中保持关系
事务最常见的例子是保持关系。考虑以下通过将它们包装在单个事务中来 创建新用户 和 他们的个人资料 的示例。
import Database from '@ioc:Adonis/Lucid/Database'
import User from 'App/Models/User'
// 高亮开始
await Database.transaction(async (trx) => {
const user = new User()
user.username = 'virk'
user.useTransaction(trx)
await user.save()
/**
* 该关系将隐式引用来自用户实例的事务
*/
await user.related('profile').create({
fullName: 'Harminder Virk',
avatar: 'some-url.jpg',
})
})
// 高亮结束
在下面的示例中,我们获取一个现有用户并为他们创建一个新的配置文件。
import Database from '@ioc:Adonis/Lucid/Database'
import User from 'App/Models/User'
// 高亮开始
await Database.transaction(async (trx) => {
const user = await User.findOrFail(1, { client: trx })
/**
* 该关系将隐式引用来自用户实例的事务
*/
await user.related('profile').create({
fullName: 'Harminder Virk',
avatar: 'some-url.jpg',
})
})
// 高亮结束
本译文仅用于学习和交流目的,转载请务必注明文章译者、出处、和本文链接
我们的翻译工作遵照 CC 协议,如果我们的工作有侵犯到您的权益,请及时联系我们。