Sequelize操作Mysql时使用事务transaction

在 Sequelize 中,事务是一种管理数据库操作的机制,确保它们要么全部成功提交,要么全部回滚。这有助于维护数据库的一致性。下面是 Sequelize 中事务的基本使用介绍。

为什么要使用事务

  1. 多个操作的原子性: 当你需要确保一系列数据库操作要么全部成功提交,要么全部回滚时,使用事务是很重要的。这有助于维护数据库的一致性,确保数据的完整性。

  2. 复杂的业务逻辑: 如果你的业务逻辑涉及多个步骤,其中一个步骤失败,你希望回滚到之前的状态,那么使用事务是必要的。这样可以避免数据库中存在不一致的数据。

  3. 并发控制: 在高并发的情况下,多个用户可能同时尝试对数据库进行写操作。使用事务可以帮助你在一组相关操作中获取锁,确保其他并发事务不能干扰,从而避免数据竞争和不一致性。

  4. 保持数据完整性: 当你需要在多个表之间进行关联操作时,使用事务可以确保这些操作的一致性,避免由于某个操作失败而导致的数据不一致问题。

  5. 嵌套操作: 当你需要执行一系列操作,并且这些操作中的一部分可能需要在失败时回滚,但整体不一定需要回滚时,嵌套事务是有用的。每个嵌套事务可以在特定的情况下进行回滚,而不会影响父事务。

总的来说,事务的使用取决于你的应用程序的需求和设计。如果你需要确保一组相关的数据库操作具有原子性,以及在失败时可以进行回滚,那么使用事务是一个明智的选择。

事务典型应用场景

当你涉及到需要确保一组数据库操作具有原子性的业务场景时,使用事务是关键的。以下是一些更加详细的业务场景,其中使用事务是合适的:

  1. 银行转账:

    在进行银行转账时,通常需要执行两个操作:减少一个账户的余额并增加另一个账户的余额。在这种情况下,使用事务确保这两个操作要么全部成功,要么全部失败。如果在减少一个账户余额之后发生错误,事务会回滚,确保不会发生金额错误的转账。

    sequelize.transaction(async (t) => {
      await Account.update({ balance: newBalance1 }, { where: { id: accountId1 }, transaction: t });
      await Account.update({ balance: newBalance2 }, { where: { id: accountId2 }, transaction: t });
    });
    
  2. 订单处理:

    在处理订单时,可能需要同时更新订单状态和库存。使用事务可以确保这两个更新在同一事务中进行,以避免订单状态和库存数量之间的不一致。

    sequelize.transaction(async (t) => {
      await Order.update({ status: 'processed' }, { where: { id: orderId }, transaction: t });
      await Product.update({ stock: newStock }, { where: { id: productId }, transaction: t });
    });
    
  3. 论坛发帖:

    当用户发帖时,需要在数据库中创建帖子并更新用户的发帖计数。使用事务可以确保这两个操作要么都成功,要么都失败,以维护论坛数据的一致性。

    sequelize.transaction(async (t) => {
      await Post.create({ title: 'New Post', content: 'This is a new post.' }, { transaction: t });
      await User.update({ postCount: newPostCount }, { where: { id: userId }, transaction: t });
    });
    
  4. 购物车结算:

    在购物车结算时,需要创建订单、扣减库存、扣除用户账户金额。这些操作需要在同一事务中进行,以确保数据的一致性。

    sequelize.transaction(async (t) => {
      await Order.create({ /* 订单信息 */ }, { transaction: t });
      await Product.update({ stock: newStock }, { where: { id: productId }, transaction: t });
      await User.update({ balance: newBalance }, { where: { id: userId }, transaction: t });
    });
    

这些场景展示了在涉及多个数据库操作时,使用事务确保操作的原子性和一致性是多么关键。在这些情况下,事务能够保证要么所有操作都成功,要么回滚到事务开始前的状态。

完整的使用流程

  1. 创建事务:

    使用 Sequelize 的 transaction 方法创建一个新的事务对象。

    const { sequelize } = require('./models'); // 假设你的 Sequelize 实例已经创建
    
    sequelize.transaction(async (t) => {
      // 在这里执行事务操作
    });
    
  2. 事务中的操作:

    在事务中执行数据库操作,确保将 t 参数传递给每个操作,以便它们在同一事务中运行。

    const { sequelize, User, Post } = require('./models');
    
    sequelize.transaction(async (t) => {
      const user = await User.create({ username: 'john_doe' }, { transaction: t });
      const post = await Post.create({ title: 'Hello Sequelize!', userId: user.id }, { transaction: t });
    });
    
  3. 事务的提交与回滚:

    在事务块中,使用 commit 提交事务,使用 rollback 回滚事务。如果抛出异常,事务将自动回滚。

    const { sequelize, User, Post } = require('./models');
    
    try {
      await sequelize.transaction(async (t) => {
        const user = await User.create({ username: 'john_doe' }, { transaction: t });
        const post = await Post.create({ title: 'Hello Sequelize!', userId: user.id }, { transaction: t });
    
        // 手动提交事务
        await t.commit();
      });
    } catch (error) {
      // 捕获异常,手动回滚事务
      console.error('Transaction failed:', error);
      await t.rollback();
    }
    
  4. 嵌套事务:

    Sequelize 支持嵌套事务。嵌套事务将在父事务中创建新的保存点。

    const { sequelize, User, Post } = require('./models');
    
    await sequelize.transaction(async (t1) => {
      await sequelize.transaction(async (t2) => {
        const user = await User.create({ username: 'nested_user' }, { transaction: t2 });
        const post = await Post.create({ title: 'Nested Transaction', userId: user.id }, { transaction: t2 });
    
        // 嵌套事务的提交
        await t2.commit();
      });
    
      // 主事务的提交
      await t1.commit();
    });
    

注意,一定要确保在事务中正确处理异步操作,并在适当的时候使用 commitrollback 来确保事务的完整性。

原文链接:https://juejin.cn/post/7333467159220797450 作者:慕仲卿

(0)
上一篇 2024年2月13日 上午10:31
下一篇 2024年2月13日 上午10:42

相关推荐

发表回复

登录后才能评论