关于小程序中多个函数并发修改同一条数据

这篇具有很好参考价值的文章主要介绍了关于小程序中多个函数并发修改同一条数据。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

关于小程序中多个函数并发修改同一条数据

背景

开发小程序的时候,遇到了如下情况:多个函数可能存在并发修改同一条数据的情况。

修改操作如下

const db = cloud.database();
const _ = db.command;
db.collection('xxx')
            .doc('yyy')
            .update({
              data: {
                order: _.pull(zzz)
              }
            })
            .then(res => {
              console.log(res);
            })
            .catch(err => {
              console.log(err);
            })

在这里我们对数据库进行更新操作,使用 $pull操作符删除order字段中的某个元素(且该元素不会存在重复值,原因是order是对象数组,我们在每个对象里面存的值也不一样)

那么在这样的情况下,会存在冲突的现象吗?

结论

如果第一个操作删除了该元素之后,第二个操作在检查到初始状态时仍认为存在匹配元素,当第二个操作尝试删除时,由于实际上该元素已被删除,可能会导致错误。

因此,在同时有两个操作在同一个数组字段上使用 $pull 操作符删除同一个元素,并且该元素在数组字段上只有一个的情况下,存在潜在的冲突风险。

解决方案

为了避免这种冲突,可以考虑使用事务或锁机制来处理并发删除冲突。

首先介绍一下锁机制的做法,代码如下

// 云函数代码示例(concurrentDelete)
const cloud = require('wx-server-sdk');
cloud.init();

exports.main = async (event, context) => {
  const db = cloud.database();
  const _ = db.command;
  const collection = db.collection('myCollection');
  const docId = event.docId; // 要删除的数据的 _id

  // 尝试获取锁标记
  const lock = await collection.doc(docId).get();

  if (lock.data && lock.data.isDeleting) {
    // 存在锁标记,其他函数正在删除该数据,放弃删除操作
    return { success: false, message: '数据正在删除中,请稍后再试' };
  }

  try {
    // 添加锁标记
    await collection.doc(docId).update({
      data: { isDeleting: true }
    });

    // 执行删除操作
    const result = await collection.doc(docId).update({
                      data: {
                        order: _.pull(event.zzz)
                      }
    			});

    // 删除完成后释放锁标记
    await collection.doc(docId).update({
      data: { isDeleting: false }
    });

    return { success: true, result };
  } catch (error) {
    // 发生错误时也需要释放锁标记
    await collection.doc(docId).update({
      data: { isDeleting: false }
    });
    throw error;
  }
};

在云函数中,首先尝试获取锁标记。如果锁标记存在,表示其他函数正在删除该数据,当前函数放弃删除操作。如果锁标记不存在,则添加锁标记,并执行删除操作。删除完成后释放锁标记。当函数发生错误时也需要释放锁标记,以确保数据的一致性。

在多个函数中调用并发删除的云函数:

// 函数A调用并发删除的云函数
wx.cloud.callFunction({
  name: 'concurrentDelete',
  data: {
    docId: 'xxx' // 要删除的数据的 _id
  },
  success: (res) => {
    if (res.result.success) {
      console.log('函数A删除成功', res.result.result);
    } else {
      console.error('函数A删除失败', res.result.message);
    }
  },
  fail: (err) => {
    console.error('函数A调用失败', err);
  }
});

// 函数B调用并发删除的云函数
wx.cloud.callFunction({
  name: 'concurrentDelete',
  data: {
    docId: 'xxx' // 要删除的数据的 _id
  },
  success: (res) => {
    if (res.result.success) {
      console.log('函数B删除成功', res.result.result);
    } else {
      console.error('函数B删除失败', res.result.message);
    }
  },
  fail: (err) => {
    console.error('函数B调用失败', err);
  }
});

通过调用并发删除的云函数,确保在任意时间点只有一个函数成功删除数据,其他函数会放弃删除操作。

除了锁机制,还可以使用事务操作来确保多个删除操作的一致性。事务操作可以将多个操作作为一个原子性的单元执行,从而保证操作的顺序和结果的一致性。

下面介绍使用事务的做法,代码如下:

//runTransaction接口
const db = wx.cloud.database();
const collection = db.collection('myCollection');

db.runTransaction(async transaction => {
  const doc = await transaction.get(collection.doc('xxx'));

  // 从数组中删除元素
  const updatedArray = doc.data.arrayField.filter(element => element !== 'element');

  // 更新数组字段
  transaction.update(collection.doc('xxx'), {
    data: {
      arrayField: updatedArray
    }
  });
}).then(res => {
  console.log('事务执行成功', res);
}).catch(err => {
  console.error('事务执行失败', err);
});


在使用事务操作时,需要将多个操作封装在一个函数内,并使用 runTransaction 方法来执行事务。在事务函数中,可以获取并操作要更新的数据,并通过 transaction.update 方法更新数组字段。

你也可以通过startTransaction接口来实现

// 云函数代码示例(concurrentDelete)
const cloud = require('wx-server-sdk');
cloud.init();

exports.main = async (event, context) => {
  const db = cloud.database();
  const collection = db.collection('myCollection');
  const docId = event.docId; // 要删除的数据的 _id

  const transaction = await db.startTransaction();

  try {
    const result = await transaction.run(() => {
      return collection.doc(docId).remove();
    });

    await transaction.commit();
    return result;
  } catch (error) {
    await transaction.rollback();
    throw error;
  }
};

使用事务操作可以保证多个删除操作在同一事务中执行,从而避免并发删除冲突,并确保操作的一致性。

关于更多事务的细节,可以去官方文档查看文章来源地址https://www.toymoban.com/news/detail-496435.html

到了这里,关于关于小程序中多个函数并发修改同一条数据的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C++并发多线程--多个线程的数据共享和保护

    目录 1--创建并等待多个线程 2--数据共享 2-1--数据只读 2-2--数据读写 2-3--共享数据保护简单案例         创建多个线程时,可以使用同一个线程入口函数;         多个线程的执行顺序与操作系统的调度机制有关,并不和创建线程的先后顺序相同;         一般会将多个

    2024年02月12日
    浏览(39)
  • IDEA同一窗口中建多个项目

    刚开始用idea工具,习惯了在eclipse下同一窗口多个目录的情况,在idea中一个项目就是一个新的窗口,开始有点不适应。 有没有办法实现在eclipse中那样的效果,答案是肯定的,但在idea中的实现方式略有不同。耽误你两分钟,这篇文章给它详细整明白,具体的步骤如下: 首选创

    2024年02月13日
    浏览(37)
  • 多个硬盘挂载到同一个目录

    同一目录无法重复挂载,后挂载的会覆盖之前挂载的磁盘。但是现在需要将4块磁盘并行挂载,该如何操作呢? 将2块磁盘合并到一个逻辑卷 进行挂载。 基本知识 基本概念PV(Physical Volume)- 物理卷物理卷在逻辑卷管理中处于最底层,它可以是实际物理硬盘上的分区,也可以是整

    2024年02月08日
    浏览(78)
  • 同一网卡如何配置多个IP地址

    平时在做嵌入式linux设备开发时,不知道你是否遇到过这种需求:设备本身只有一个以太网口,但需求是, 这个网口即当做调试口,又当做业务数据通信口 。而且,两种用途对IP地址的要求不同:当做调试口时,IP地址是固定的;当做业务传通信口时,IP地址是动态分配的。该

    2024年02月11日
    浏览(40)
  • Idea 同一窗口导入多个项目详细教程

           idea应该是目前最受欢迎的java开发工具了,对使用过eclipse的人来说,很容易实现多个项目在同一窗口,这样代码开发比较方便。但是对使用idea不怎么熟练的人来说,可能只会构建单模块的项目,比如单体springboot项目。最多在开发springcloud项目时,会使用新建子模块

    2024年02月02日
    浏览(47)
  • RabbitMq同一队列多个消费者问题

    RabbitMQ只有Queue,如果多个消费者绑定同一个queue,那么一条消息,只能被其中一个消费者取走(轮询)。 本质上,RabbitMq的消费者的消息确认机制,就注定不可能让多个消费者同时去消费同一个队列中的同一条消息,只能轮询的方式去消费。 我感觉我们的目的是想用rabbitmq

    2024年02月04日
    浏览(34)
  • gitee同一台电脑使用多个账号的问题

    官方文档:https://gitee.com/help/articles/4238#article-header0 目前 Gitee 支持使用 HTTPS协议 和 ssh 协议 进行代码的推送/拉取。两种协议的差别仅在于同一个仓库使用不同协议时的地址不同,以及对应的授权实现不同。 以仓库 https://gitee.com/normalcoder/Gitee-Blog-Applets 为例,对应两种协议的

    2024年02月05日
    浏览(53)
  • vue 实现多个路由共用同一个页面组件

    这样的弊端是如果router-view里包含其他组件,切换其他组件会让其他组件也重新渲染。 这样的问题是导致切换路由会闪烁一下。因为切换后所有钩子函数都重新触发了。

    2024年02月07日
    浏览(60)
  • 【注意】当同一个Class的多个对象出现在同一段代码内的时候,极易出错。

    下面的 paymentQuery 方法坐落于我们lijianjin系统的LiJianJinPaymentQueryBizService。 这两个bankOrderFlow、orderFlow,... 乱花渐欲迷人眼的赶脚,但其实,这是像“shǐ”一样的代码。         在我们的zhongtai-channel-provider, 上周出现并紧急fix了一个bug。竟然也是 此种情况 引发的bug。   先上

    2024年04月28日
    浏览(59)
  • git同一分支上多个commit合成一个的操作

    1、首先git log——查看当前分支的提交记录 ,想要把圈起来的commit合成一个, 2、开始合并,敲下面这个命令 git rebase -i commitId commitId即找出要合并的几个commit的前一个commit的ID -i 的参数是不需要合并的 commit 的 hash 值,这里指的是第一条 commit, 接着键盘摁下 i 键,我们就进

    2024年01月19日
    浏览(70)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包