5

我有两个现有的集合“A”和“B”。我需要将“B”重命名为“C”,并将“A”重命名为“B”,在此期间不允许对 B 进行任何写入。重命名本身会激活全局锁,但我需要防止在重命名之间发生写入。这可能吗?

这是我的代码:

db.B.renameCollection('C')
                           <-- prevent writes from occurring to B in between commands
db.A.renameCollection('B')

编辑:我使用的是 mongodb 1.8.1 版,目前不能选择更改版本。

4

5 回答 5

4

Mongodb 本身无法处理这个问题,你可以做到这一点的唯一方法是使用一些自定义代码。

如果这只会在你的应用程序中发生一次(我猜重命名集合不是经常做的事情)你可以有一个更“激进”的方法,你可以在你的数据库中搜索一个标志,这意味着'collection db.B已重命名,但 db.A 尚未重命名。如果您的所有写入在将写入提交到服务器之前都检查了这一点,并且如果设置了标志就返回,它可以保护应用程序在 db.B 重命名后不写入 db.A。

我认为这是一种“激进”的方法,因为它显然会影响性能(不过,读取速度如此之快,您可能不会感觉到)。

如果您的应用程序在单个 Web 服务器(而不是 Web 场)上运行,您可以在 Web 应用程序本身上使用同步机制,使用信号量等线程同步工具,甚至是一些将用作标志的线程安全变量上面建议。(取决于您使用的服务器端技术)

于 2012-11-06T08:46:46.827 回答
4

您可以创建一个名为“renameCollection”的函数并对其进行锁定:

db.runCommand({eval:renameCollection,args:["Collection1","Collection2"],nolock:false});

锁允许安全地执行此类操作并等待请求

于 2014-10-17T13:57:33.577 回答
3

正如你可能猜到的:这是不可能的。没有事务支持,只有原子操作。

于 2012-11-06T05:06:40.403 回答
2

我在 TokuMX 上为 Tokutek 工作,使用多语句交易

正如其他答案所说,MongoDB 无法做到这一点(据我所知),但 TokuMX 可以。TokuMX 在非分片集群上有多语句事务。要执行此操作,您可以执行以下操作:

  • db.beginTransaction()
  • db.B.renameCollection('C')
  • db.A.renameCollection('B')
  • db.commitTransaction()
于 2014-01-25T02:15:50.543 回答
1

MongoDB 没有事务重命名的意义,实际上我不确定 SQL 在这种情况下是否也这样做,但是您可以通过一些服务器端编程和锁定集合来完成此操作。

从您的服务器端语言中,您可以在将行写入锁定表时触发命令,针对 B 的每个查询都将检查锁定,如果未找到将写入,否则将退出。

这是一种简单的方法,但很可能有点乏味,特别是如果您有一个非常分段的代码库,它没有在服务器端代码和数据库之间容纳标准化的查询层。

我还应该注意,这renameCollection不适用于分片集合,您很可能已经知道这一点,但我想我还是会这么说。在分片集合的情况下,最好通过复制操作来“移动”集合。

于 2012-11-06T08:27:53.997 回答