Azure Cosmos DB çakışma çözümleme ilkelerini yönetmeManage conflict resolution policies in Azure Cosmos DB

Çok bölgeli yazmalarda, birden fazla istemci aynı öğeye yazdığında çakışmalar oluşabilir.With multi-region writes, when multiple clients write to the same item, conflicts may occur. Bir çakışma oluştuğunda, farklı çakışma çözümleme ilkeleri kullanarak çakışmayı çözebilirsiniz.When a conflict occurs, you can resolve the conflict by using different conflict resolution policies. Bu makalede, çakışma çözümleme ilkelerinin nasıl yönetileceği açıklanır.This article describes how to manage conflict resolution policies.

Son yazıcı oluşturma-WINS çakışma çözümü ilkesiCreate a last-writer-wins conflict resolution policy

Bu örnekler, son yazıcı WINS çakışma çözümleme ilkesiyle bir kapsayıcının nasıl ayarlanacağını gösterir.These samples show how to set up a container with a last-writer-wins conflict resolution policy. Son-yazıcı için varsayılan yol, zaman damgası alanı veya _ts özelliğidir.The default path for last-writer-wins is the timestamp field or the _ts property. SQL API 'SI için bu, sayısal türde Kullanıcı tanımlı bir yola de ayarlanabilir.For SQL API, this may also be set to a user-defined path with a numeric type. Çakışma durumunda en yüksek değer kazanır.In a conflict, the highest value wins. Yol ayarlanmamışsa veya geçersizse, varsayılan olarak _tsolur.If the path isn't set or it's invalid, it defaults to _ts. Bu ilkeyle çözümlenen çakışmalar çakışma akışında gösterilmez.Conflicts resolved with this policy do not show up in the conflict feed. Bu ilke, tüm API 'Ler tarafından kullanılabilir.This policy can be used by all APIs.

.NET SDK V2.NET SDK V2

DocumentCollection lwwCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
  UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
  {
      Id = this.lwwCollectionName,
      ConflictResolutionPolicy = new ConflictResolutionPolicy
      {
          Mode = ConflictResolutionMode.LastWriterWins,
          ConflictResolutionPath = "/myCustomId",
      },
  });

.NET SDK V3.NET SDK V3

Container container = await createClient.GetDatabase(this.databaseName)
    .CreateContainerIfNotExistsAsync(new ContainerProperties(this.lwwCollectionName, "/partitionKey")
    {
        ConflictResolutionPolicy = new ConflictResolutionPolicy()
        {
            Mode = ConflictResolutionMode.LastWriterWins,
            ResolutionPath = "/myCustomId",
        }
    });

Java Async SDK’sıJava Async SDK

DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/myCustomId");
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();

Java Sync SDK’sıJava Sync SDK

DocumentCollection lwwCollection = new DocumentCollection();
lwwCollection.setId(this.lwwCollectionName);
ConflictResolutionPolicy lwwPolicy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/myCustomId");
lwwCollection.setConflictResolutionPolicy(lwwPolicy);
DocumentCollection createdCollection = this.tryCreateDocumentCollection(createClient, database, lwwCollection);

Node.js/JavaScript/TypeScript SDKNode.js/JavaScript/TypeScript SDK

const database = client.database(this.databaseName);
const { container: lwwContainer } = await database.containers.createIfNotExists(
  {
    id: this.lwwContainerName,
    conflictResolutionPolicy: {
      mode: "LastWriterWins",
      conflictResolutionPath: "/myCustomId"
    }
  }
);

Python SDK’sıPython SDK

udp_collection = {
    'id': self.udp_collection_name,
    'conflictResolutionPolicy': {
        'mode': 'LastWriterWins',
        'conflictResolutionPath': '/myCustomId'
    }
}
udp_collection = self.try_create_document_collection(
    create_client, database, udp_collection)

Saklı yordam kullanarak özel bir çakışma çözümleme ilkesi oluşturmaCreate a custom conflict resolution policy using a stored procedure

Bu örnekler çakışmayı çözümlemek için saklı yordama içeren özel çakışma çözümleme ilkesine sahip bir kapsayıcı ayarlama adımlarını göstermektedir.These samples show how to set up a container with a custom conflict resolution policy with a stored procedure to resolve the conflict. Bu çakışmalar, saklı yordamınızdaki bir hata olmadığı takdirde çakışma akışında gösterilmez.These conflicts don't show up in the conflict feed unless there's an error in your stored procedure. İlke kapsayıcı ile oluşturulduktan sonra, saklı yordamı oluşturmanız gerekir.After the policy is created with the container, you need to create the stored procedure. Aşağıdaki .NET SDK örneği bir örnek gösterir.The .NET SDK sample below shows an example. Bu ilke yalnızca çekirdek (SQL) API 'sinde desteklenir.This policy is supported on Core (SQL) Api only.

Örnek özel çakışma çözümü saklı yordamıSample custom conflict resolution stored procedure

Özel çakışma çözümü saklı yordamları aşağıda gösterilen işlev imzası kullanılarak uygulanmalıdır.Custom conflict resolution stored procedures must be implemented using the function signature shown below. İşlev adının, saklı yordamı kapsayıcı ile kaydedilirken kullanılan adla eşleşmesi gerekmez, ancak adlandırmayı basitleştirir.The function name does not need to match the name used when registering the stored procedure with the container but it does simplify naming. Bu saklı yordam için uygulanması gereken parametrelerin açıklaması aşağıdadır.Here is a description of the parameters that must be implemented for this stored procedure.

  • ıncomingıtem: Çakışmaların üretilerek işlemede eklenen veya güncellenen öğe.incomingItem: The item being inserted or updated in the commit that is generating the conflicts. , Silme işlemleri için null.Is null for delete operations.
  • Existingıtem: Şu anda taahhüt edilen öğe.existingItem: The currently committed item. Bu değer bir güncelleştirmede null değil ve INSERT veya delete için null.This value is non-null in an update and null for an insert or deletes.
  • Isınkaldırılma: Incomingıtem 'ın daha önce silinmiş bir öğeyle çakışıp çakışmadığını gösteren Boolean.isTombstone: Boolean indicating if the incomingItem is conflicting with a previously deleted item. Doğru olduğunda, existingItem da null olur.When true, existingItem is also null.
  • Conflictingıtems: Kapsayıcıda, ID veya diğer benzersiz dizin özelliklerindeki ıncomingıtem ile çakışan tüm öğelerin taahhüt edilen sürümünün dizisi.conflictingItems: Array of the committed version of all items in the container that are conflicting with incomingItem on ID or any other unique index properties.

Önemli

Her türlü saklı yordamda olduğu gibi, özel bir çakışma çözümü yordamı aynı bölüm anahtarına sahip tüm verilere erişebilir ve çakışmaları çözümlemek için herhangi bir ekleme, güncelleştirme veya silme işlemi gerçekleştirebilir.Just as with any stored procedure, a custom conflict resolution procedure can access any data with the same partition key and can perform any insert, update or delete operation to resolve conflicts.

Bu örnek saklı yordam, /myCustomId yoldan en düşük değeri seçerek çakışmaları çözer.This sample stored procedure resolves conflicts by selecting the lowest value from the /myCustomId path.

function resolver(incomingItem, existingItem, isTombstone, conflictingItems) {
  var collection = getContext().getCollection();

  if (!incomingItem) {
      if (existingItem) {

          collection.deleteDocument(existingItem._self, {}, function (err, responseOptions) {
              if (err) throw err;
          });
      }
  } else if (isTombstone) {
      // delete always wins.
  } else {
      if (existingItem) {
          if (incomingItem.myCustomId > existingItem.myCustomId) {
              return; // existing item wins
          }
      }

      var i;
      for (i = 0; i < conflictingItems.length; i++) {
          if (incomingItem.myCustomId > conflictingItems[i].myCustomId) {
              return; // existing conflict item wins
          }
      }

      // incoming item wins - clear conflicts and replace existing with incoming.
      tryDelete(conflictingItems, incomingItem, existingItem);
  }

  function tryDelete(documents, incoming, existing) {
      if (documents.length > 0) {
          collection.deleteDocument(documents[0]._self, {}, function (err, responseOptions) {
              if (err) throw err;

              documents.shift();
              tryDelete(documents, incoming, existing);
          });
      } else if (existing) {
          collection.replaceDocument(existing._self, incoming,
              function (err, documentCreated) {
                  if (err) throw err;
              });
      } else {
          collection.createDocument(collection.getSelfLink(), incoming,
              function (err, documentCreated) {
                  if (err) throw err;
              });
      }
  }
}

.NET SDK V2.NET SDK V2

DocumentCollection udpCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
  UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
  {
      Id = this.udpCollectionName,
      ConflictResolutionPolicy = new ConflictResolutionPolicy
      {
          Mode = ConflictResolutionMode.Custom,
          ConflictResolutionProcedure = string.Format("dbs/{0}/colls/{1}/sprocs/{2}", this.databaseName, this.udpCollectionName, "resolver"),
      },
  });

//Create the stored procedure
await clients[0].CreateStoredProcedureAsync(
UriFactory.CreateStoredProcedureUri(this.databaseName, this.udpCollectionName, "resolver"), new StoredProcedure
{
    Id = "resolver",
    Body = File.ReadAllText(@"resolver.js")
});

.NET SDK V3.NET SDK V3

Container container = await createClient.GetDatabase(this.databaseName)
    .CreateContainerIfNotExistsAsync(new ContainerProperties(this.udpCollectionName, "/partitionKey")
    {
        ConflictResolutionPolicy = new ConflictResolutionPolicy()
        {
            Mode = ConflictResolutionMode.Custom,
            ResolutionProcedure = string.Format("dbs/{0}/colls/{1}/sprocs/{2}", this.databaseName, this.udpCollectionName, "resolver")
        }
    });

await container.Scripts.CreateStoredProcedureAsync(
    new StoredProcedureProperties("resolver", File.ReadAllText(@"resolver.js"))
);

Java Async SDK’sıJava Async SDK

DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy("resolver");
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();

Kapsayıcınız oluşturulduktan sonra resolver saklı yordamı oluşturmanız gerekir.After your container is created, you must create the resolver stored procedure.

Java Sync SDK’sıJava Sync SDK

DocumentCollection udpCollection = new DocumentCollection();
udpCollection.setId(this.udpCollectionName);
ConflictResolutionPolicy udpPolicy = ConflictResolutionPolicy.createCustomPolicy(
        String.format("dbs/%s/colls/%s/sprocs/%s", this.databaseName, this.udpCollectionName, "resolver"));
udpCollection.setConflictResolutionPolicy(udpPolicy);
DocumentCollection createdCollection = this.tryCreateDocumentCollection(createClient, database, udpCollection);

Kapsayıcınız oluşturulduktan sonra resolver saklı yordamı oluşturmanız gerekir.After your container is created, you must create the resolver stored procedure.

Node.js/JavaScript/TypeScript SDKNode.js/JavaScript/TypeScript SDK

const database = client.database(this.databaseName);
const { container: udpContainer } = await database.containers.createIfNotExists(
  {
    id: this.udpContainerName,
    conflictResolutionPolicy: {
      mode: "Custom",
      conflictResolutionProcedure: `dbs/${this.databaseName}/colls/${
        this.udpContainerName
      }/sprocs/resolver`
    }
  }
);

Kapsayıcınız oluşturulduktan sonra resolver saklı yordamı oluşturmanız gerekir.After your container is created, you must create the resolver stored procedure.

Python SDK’sıPython SDK

udp_collection = {
    'id': self.udp_collection_name,
    'conflictResolutionPolicy': {
        'mode': 'Custom',
        'conflictResolutionProcedure': 'dbs/' + self.database_name + "/colls/" + self.udp_collection_name + '/sprocs/resolver'
    }
}
udp_collection = self.try_create_document_collection(
    create_client, database, udp_collection)

Kapsayıcınız oluşturulduktan sonra resolver saklı yordamı oluşturmanız gerekir.After your container is created, you must create the resolver stored procedure.

Özel bir çakışma çözümleme ilkesi oluşturmaCreate a custom conflict resolution policy

Bu örnekler özel çakışma çözümleme ilkesine sahip bir kapsayıcı ayarlama adımlarını göstermektedir.These samples show how to set up a container with a custom conflict resolution policy. Bu çakışmalar çakışma akışında görünür.These conflicts show up in the conflict feed.

.NET SDK V2.NET SDK V2

DocumentCollection manualCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
  UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
  {
      Id = this.manualCollectionName,
      ConflictResolutionPolicy = new ConflictResolutionPolicy
      {
          Mode = ConflictResolutionMode.Custom,
      },
  });

.NET SDK V3.NET SDK V3

Container container = await createClient.GetDatabase(this.databaseName)
    .CreateContainerIfNotExistsAsync(new ContainerProperties(this.manualCollectionName, "/partitionKey")
    {
        ConflictResolutionPolicy = new ConflictResolutionPolicy()
        {
            Mode = ConflictResolutionMode.Custom
        }
    });

Java Async SDK’sıJava Async SDK

DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy();
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();

Java Sync SDK’sıJava Sync SDK

DocumentCollection manualCollection = new DocumentCollection();
manualCollection.setId(this.manualCollectionName);
ConflictResolutionPolicy customPolicy = ConflictResolutionPolicy.createCustomPolicy(null);
manualCollection.setConflictResolutionPolicy(customPolicy);
DocumentCollection createdCollection = client.createCollection(database.getSelfLink(), collection, null).getResource();

Node.js/JavaScript/TypeScript SDKNode.js/JavaScript/TypeScript SDK

const database = client.database(this.databaseName);
const {
  container: manualContainer
} = await database.containers.createIfNotExists({
  id: this.manualContainerName,
  conflictResolutionPolicy: {
    mode: "Custom"
  }
});

Python SDK’sıPython SDK

database = client.ReadDatabase("dbs/" + self.database_name)
manual_collection = {
    'id': self.manual_collection_name,
    'conflictResolutionPolicy': {
        'mode': 'Custom'
    }
}
manual_collection = client.CreateContainer(database['_self'], collection)

Çakışma akışından okumaRead from conflict feed

Bu örnekler, kapsayıcının çakışma akışından okuma yöntemlerini göstermektedir.These samples show how to read from a container's conflict feed. Çakışmalar yalnızca otomatik olarak çözümlenmezse veya özel bir çakışma ilkesi kullanılıyorsa çakışma akışında gösterilir.Conflicts show up in the conflict feed only if they weren't resolved automatically or if using a custom conflict policy.

.NET SDK V2.NET SDK V2

FeedResponse<Conflict> conflicts = await delClient.ReadConflictFeedAsync(this.collectionUri);

.NET SDK V3.NET SDK V3

FeedIterator<ConflictProperties> conflictFeed = container.Conflicts.GetConflictIterator();
while (conflictFeed.HasMoreResults)
{
    FeedResponse<ConflictProperties> conflicts = await conflictFeed.ReadNextAsync();
    foreach (ConflictProperties conflict in conflicts)
    {
        // Read the conflicted content
        MyClass intendedChanges = container.Conflicts.ReadConflictContent<MyClass>(conflict);
        MyClass currentState = await container.Conflicts.ReadCurrentAsync<MyClass>(conflict, new PartitionKey(intendedChanges.MyPartitionKey));

        // Do manual merge among documents
        await container.ReplaceItemAsync<MyClass>(intendedChanges, intendedChanges.Id, new PartitionKey(intendedChanges.MyPartitionKey));

        // Delete the conflict
        await container.Conflicts.DeleteAsync(conflict, new PartitionKey(intendedChanges.MyPartitionKey));
    }
}

Java Async SDK’sıJava Async SDK

FeedResponse<Conflict> response = client.readConflicts(this.manualCollectionUri, null)
                    .first().toBlocking().single();
for (Conflict conflict : response.getResults()) {
    /* Do something with conflict */
}

Java Sync SDK’sıJava Sync SDK

Iterator<Conflict> conflictsIterator = client.readConflicts(this.collectionLink, null).getQueryIterator();
while (conflictsIterator.hasNext()) {
    Conflict conflict = conflictsIterator.next();
    /* Do something with conflict */
}

Node.js/JavaScript/TypeScript SDKNode.js/JavaScript/TypeScript SDK

const container = client
  .database(this.databaseName)
  .container(this.lwwContainerName);

const { result: conflicts } = await container.conflicts.readAll().toArray();

PythonPython

conflicts_iterator = iter(client.ReadConflicts(self.manual_collection_link))
conflict = next(conflicts_iterator, None)
while conflict:
    # Do something with conflict
    conflict = next(conflicts_iterator, None)

Sonraki adımlarNext steps

Aşağıdaki Azure Cosmos DB kavramları hakkında bilgi edinin:Learn about the following Azure Cosmos DB concepts: