node prisma+postgreSQL数据库事务

在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)
  }
}
相关推荐
Moshow郑锴25 分钟前
Ansible 批量部署 Node.js 服务:ZIP 直解与共享目录分发两种方案对比
node.js·ansible
少年的范儿7 小时前
Windows 安装 Node.js 教程:nvm 版本管理 + pnpm 安装配置
windows·npm·node.js
peach8 小时前
同样是装依赖,为什么 npm 长成 node_modules,Maven 长成 .m2
npm·node.js·maven
FungLeo10 小时前
成为全栈·Go 后端篇·重写之前先锁基线:契约、Node 版本与行为清单
golang·node.js·go·openapi·契约测试·成为全栈
FungLeo1 天前
成为全栈·Go 后端篇·契约一致性与差分测试:两套实现如何互相校验
golang·node.js·go·合约测试·差分测试·成为全栈·api兼容
月夏1 天前
前端第一次接自己的后端:mock 切真接口踩了 2 个坑,组件只改了一行 import
前端·后端·node.js
SEO_juper1 天前
Node.js 页面主题聚焦度检测:title 和正文各说各的,AI 也读不懂
开发语言·人工智能·node.js·seo·外贸独立站
SEO_juper2 天前
Node.js 重定向链检测工具:301 跳了几跳、有没有成环,一次看清
xml·开发语言·python·node.js·json·bash
king13598745502 天前
AI Agent 端云协同选型:Node.js 任务成本算例与权限检查清单(2027—2028 展望)
人工智能·ai·node.js·ai agent
居里先生7522 天前
PDF 批注到底存在文件的哪里?从 /Annots 讲到导出验证
node.js