在postgreSQL中,使用begin命令或start transition命令可以开启一个事务,使用commit命令或rollback命令可以回滚一个事务。
数据库的事务通常由一组DML语句(以insert、update和delete命令为核心的语句)组成,通过事务可以保证数据库中数据的完整性,保证这一组DML语句要么全部执行,要么全部不执行。
可以把事务看成:一个逻辑工作单元,可以通过提交或回滚操作来结束一个事务
数据库的四个特性如下:
|----------------|--------------------------------------|
| 特性 | 说明 |
| Atomicity原子性 | 事务中的操作要不全做,要不全不做,事务 执行失败时,会回滚到执行前的状态 |
| Consistency一致性 | 事务执行前后,数据库从一个一致状态到另一个 一致状态 |
| Isolation隔离性 | 并发事务互不干扰 |
| Durability持久性 | 事务一旦提交,其结果永久保存 |
prisma的两个事务
|-------|---------------------------------|-----------------|
| 方式 | 语法 | 适用场景 |
| 交互式事务 | transaction(async(tx)=\>{...}) | 需要在事务中做判断,有条件逻辑 |
| 批量事务 | transaction(op1, op2, ...) | 多个独立操作原子执行 |
使用prisma进行数据库事务时,要遵循下面三个原则:
1 只包含数据库操作
2 预先计算好数据,减少事务内判断
3 大批量操作分批执行
常用事务使用示例
交互式事务, 场景:创建用户 + 同时创建2篇文章,全部成功或全部回滚
javascript
// 场景:创建用户 + 同时创建2篇文章,全部成功或全部回滚
const result = await prisma.$transaction(async (tx) => {
// tx 是事务专用的 PrismaClient,所有操作在同一个事务中
const user = await tx.user.create({
data: {
email: 'tx-demo@test.com',
name: '事务演示用户',
password: '123456',
},
})
const post1 = await tx.post.create({
data: {
title: '事务中的文章1',
published: true,
authorId: user.id,
},
})
const post2 = await tx.post.create({
data: {
title: '事务中的文章2',
published: false,
authorId: user.id,
},
})
})
return { user, post1, post2 }
批量事务
javascript
// 多个独立操作原子执行
const [updatedUser, createdPost, userCount] = await prisma.$transaction([
// 操作1:更新用户名
prisma.user.update({
where: { id: 1 },
data: { name: '新名字' },
}),
// 操作2:创建文章
prisma.post.create({
data: { title: '新文章', authorId: 1 },
}),
// 操作3:统计
prisma.user.count(),
])
// 三个操作要么全成功,要么全失败
手动回滚:p2000是一种数据库错误类型(字段值过长),clientVersion是类似自己代码的版本
javascript
import { Prisma } from '@prisma/client'
await prisma.$transaction(async (tx) => {
// ... 一些操作
// 手动触发回滚
throw new Prisma.PrismaClientKnownRequestError(
'业务原因回滚',
{ code: 'P2000', clientVersion: '5.0.0' }
)
})
设置隔离级别与超时
javascript
import { PrismaClient, Prisma } from '@prisma/client'
const prisma = new PrismaClient()
async function runTransaction() {
try {
const result = await prisma.$transaction(
async (tx) => {
// 在此处执行事务操作,使用 tx 代替 prisma
const user = await tx.user.create({ data: { name: 'Alice' } })
const account = await tx.account.create({ data: { userId: user.id, balance: 100 } })
return { user, account }
},
{
//这里统一设置一些事务的配置属性
isolationLevel: Prisma.TransactionIsolationLevel.Serializable, // 设置隔离级别
timeout: 10000, // 事务整体超时时间(毫秒),默认 5000ms
maxWait: 5000, // 等待获取事务执行权的最大时间(毫秒),默认 2000ms
}
)
console.log('Transaction succeeded:', result)
} catch (error) {
console.error('Transaction failed:', error)
}
}