问题描述
在波斯菊中使用事务处理批处理,是否可以查询集合(Select * from partition where openorder=1
)中的分区,然后如果查询返回没有未结订单,则向集合中添加项目。
或者您可以先进行写入,然后进行条件读取(Select * from partition where openorder=1 and id={unique GUID just written}
),然后如果第二次读取失败,则写入将被反转(?)。
我希望在一个原子操作中完成此操作,因为我不想认为没有未结订单,然后另一个进程会在此流程之前写一个未结订单。
如果没有,是否可以以其他方式执行此操作?
**编辑下午3:30 PT 9/16时使用尝试的解决方案,该解决方案在我测试时写了一份文件**
function checkOpenorder(inputDocString,query){
console.log("Stored Procedure Starting")
var context = getContext();
var container = context.getCollection();
var containerLink = container.getSelfLink();
var response = context.getResponse();
var isAccepted = container.queryDocuments(
container.getSelfLink(),query,function (err,items,options) {
if (err) throw err;
// Query would be fed in such that if there is no open order,no items would return in the collection
if (items.length == 0){
var docCreated = container.createDocument(containerLink,inputDocString,function (err2,itemWritten) {
if (err2) throw err2;
// else was successfully able to write document?
response.setBody("Wrote document");
});
}
else {
response.setBody("Order currently open");
}
});
if (!isAccepted) throw new Error('The query was not accepted by the server.')
}
编辑:最终问题9/17 我是否要将最大并行度设置为1,以确保存储过程不能在同一分区中同时运行2次? (如果看到没有未结订单,可能会创建竞争条件->创建一个文档,然后我们有2个未结订单)。我认为我想禁用跨分区查询(再也不需要它)。
解决方法
恐怕答案是否定的。 TransactionalBatch仅支持写操作。如果您要进行跨文档的读写事务,则只有两种选择:
-
在存储过程中执行事务。仅当您在单个分区中工作并且您不需要在事务内执行任何与Cosmos不相关的操作时,此方法才有效。根据您的描述,应该可以。
-
使用某种锁定在客户端执行事务。
如答案之一所述,TransactionBatch
仅支持写操作。我们在Cosmos DB中也面临过类似的挑战。解决问题的方法如下:
- 您可以引入“会话”的概念,其中在请求/会话结束时进行提交/保存操作。
- 为所有
Get
操作创建本地身份映射/缓存。也就是说,首先检查Cosmos文档是否在本地缓存中,如果是,则从本地缓存返回它。否则,请从Cosmos获取。 -
Create
,Upsert
或Delete
操作仅保存到本地缓存并更新身份映射。 -
Commit
操作在请求结束时被调用。它使用本地缓存中的项目创建一个事务批并将其保存到Cosmos。
这种方法的优点是,您可以使用C#完成所有这些操作,而无需任何复杂的锁定代码。
此方法的一些局限性是:
- 它只能在单个分区内工作(我认为这对您来说很好)
- 由于您正在使用Cosmos Document的ID,因此传递自定义
QueryDefinition
不适用于ids
可能很棘手。