登录/注册

Sequelize事务处理回滚失败

用户头像管理员49阅读

如果你使用了MySQL:MyISAM不支持事务处理,请换成InnoDB!!!


在使用Node.js进行服务端开发中我们经常使用Sequelize作为ORM框架,我们对多个数据表进行处理时通常会使用事务处理。在Sequelize事务文档中给了很多方式,主要分为托管和非托管,很多时候我们在回滚时常常发生失败,明明自己以及提交回滚了,但是仍然有数据表被改动了。

下面是我项目中的一个Demo,在tag表删除数据时,对article表中的tag进行置换,如果置换失败则事务回滚取消删除。在置换时我对id进行了+11,使得触发回滚进行测试。

import Router from "@koa/router";
import DB from "@/db";
import sequelize from "@/db/config";
import { Op } from "sequelize";

let router = new Router();

router.delete("/tag/:id", async ctx => {
  let { id } = ctx.params;
  const t = await sequelize.transaction();
  let deleteTagCount = await DB.Tag.destroy({
    where: {
      id: id,
    },
    transaction: t,
  });
  // todo 解决事务处理问题
  /** 需要删除的个数*/
  let { count: tagCount } = await DB.Article.findAndCountAll({
    where: { tag: { [Op.substring]: id } },
  });
  //将文章表中的 ,id,  ,id   id,   id  四种方法全部置换  // +11使得置换失败,触发回滚
  let replaceTagIdResult = await Promise.all<any>([
    sequelize.query(
      `update article set tag=REPLACE (tag,',${id + "11"},',',') WHERE tag like '%${id}%'`,
      { transaction: t }
    ),
    sequelize.query(
      `update article set tag=REPLACE (tag,',${id + "11"}','') WHERE tag like '%${id}%'`,
      { transaction: t }
    ),
    sequelize.query(
      `update article set tag=REPLACE (tag,'${id + "11"},','') WHERE tag like '%${id}%'`,
      { transaction: t }
    ),
    sequelize.query(
      `update article set tag=REPLACE (tag,'${id + "11"}','') WHERE tag like '%${id}%'`,
      { transaction: t }
    ),
  ]).then(res => {
    // 实际删除了多少
    let _tagCount = res.reduce((total, item) => {
      return total + item[0].affectedRows;
    }, 0);
    if (_tagCount != tagCount) {
      console.log(`删除 ${id} 时 置换数量对不上${_tagCount}/${tagCount}`);
      return false;
    } else {
      return true;
    }
  });
  
  if (!(deleteTagCount && replaceTagIdResult)) {
    console.log("回滚");
    ctx.body = {
      success: false,
      message: "删除失败",
    };
    await t.rollback();
  } else {
    ctx.body = {
      success: true,
      message: "删除成功",
    };
    await t.commit();
  }
});
export default router;
当然了,具体在Sequelize中使用事务处理的方法请在文档看,我这里也不说什么代码错误。

我在项目中也遇到了问题解决了好久:MyISAM不支持事务处理,请换成InnoDB

Preview
登录后评论