Примечание.
Для доступа к этой странице требуется авторизация. Вы можете попробовать войти или изменить каталоги.
Для доступа к этой странице требуется авторизация. Вы можете попробовать изменить каталоги.
ОБЛАСТЬ ПРИМЕНЕНИЯ: NoSQL
При множественных записях в разных регионах, когда несколько клиентов одновременно записывают в один и тот же элемент, могут возникать конфликты. Такую проблему можно решить с помощью разных политик устранения конфликтов. В этой статье объясняется, как управлять политиками устранения конфликтов.
Совет
Политика разрешения конфликтов может быть указана только во время создания контейнера и не может быть изменена после создания контейнера.
Создание политики разрешения конфликтов, реализующей подход "Сохраняются изменения, внесенные последними"
В этих примерах показано, как настроить контейнер с политикой разрешения конфликтов, реализующей подход "Сохраняются изменения, внесенные последними". В качестве пути по умолчанию для политики "последний изменивший сохраняет" используется поле метки времени или свойство _ts. Для API для NoSQL этот путь также может иметь определяемый пользователем путь с числовым типом. В конфликте побеждает высшее значение. Если путь не задан или является недопустимым, по умолчанию используется значение _ts. Конфликты, разрешённые по этому правилу, не отображаются в ленте конфликтов. Все API-интерфейсы могут использовать эту политику.
Пакет SDK для .NET
DocumentCollection lwwCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
{
Id = this.lwwCollectionName,
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.LastWriterWins,
ConflictResolutionPath = "/myCustomId",
},
});
Пакет SDK для Java версии 4
Асинхронный API пакета SDK для Java версии 4 (Maven com.azure::azure-cosmos)
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/myCustomId");
CosmosContainerProperties containerProperties = new CosmosContainerProperties(container_id, partition_key);
containerProperties.setConflictResolutionPolicy(policy);
/* ...other container config... */
database.createContainerIfNotExists(containerProperties).block();
Пакеты средств разработки для Java версии 2
Пакет SDK Async Java версии 2 (Maven com.microsoft.azure::azure-cosmosdb)
DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createLastWriterWinsPolicy("/myCustomId");
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();
Пакет SDK для Node.js, JavaScript и TypeScript
const database = client.database(this.databaseName);
const { container: lwwContainer } = await database.containers.createIfNotExists(
{
id: this.lwwContainerName,
conflictResolutionPolicy: {
mode: "LastWriterWins",
conflictResolutionPath: "/myCustomId"
}
}
);
Пакет SDK для Python
database = client.get_database_client(database=database_id)
lww_conflict_resolution_policy = {'mode': 'LastWriterWins', 'conflictResolutionPath': '/regionId'}
lww_container = database.create_container(id=lww_container_id, partition_key=PartitionKey(path="/id"),
conflict_resolution_policy=lww_conflict_resolution_policy)
Пакет SDK для GO
db, _ := c.NewDatabase("demo_db")
_, err = db.CreateContainer(context.Background(), azcosmos.ContainerProperties{
ID: "demo_container",
PartitionKeyDefinition: azcosmos.PartitionKeyDefinition{
Paths: []string{"/id"},
Kind: azcosmos.PartitionKeyKindHash,
},
ConflictResolutionPolicy: &azcosmos.ConflictResolutionPolicy{
Mode: azcosmos.ConflictResolutionModeLastWriteWins,
ResolutionPath: "/myCustomId",
},
}, nil)
Создание пользовательской политики устранения конфликтов с помощью хранимой процедуры
В этих примерах показано, как настроить контейнер с пользовательской политикой разрешения конфликтов. Эта политика использует логику в хранимой процедуре для устранения конфликта. Если хранимая процедура назначена для устранения конфликтов, конфликты не отображаются в канале конфликтов, если в указанной хранимой процедуре не возникает ошибка.
После создания политики с использованием контейнера необходимо создать хранимую процедуру. В примере пакета SDK для .NET показан пример этого рабочего процесса. Эта политика поддерживается только в API для NoSQL.
Пример пользовательской хранимой процедуры для устранения конфликтов
Пользовательские хранимые процедуры для устранения конфликтов нужно реализовать с помощью сигнатуры функции, представленной ниже. Имя функции не обязательно совпадает с именем, используемым при регистрации хранимой процедуры в контейнере, но упрощает именование. Ниже приведено описание параметров, которые должны быть реализованы для этой хранимой процедуры.
- incomingItem: данный элемент вставляется или обновляется в фиксации, которая вызывает конфликты. Имеет значение NULL для операций удаления.
- existingItem: элемент, зафиксированный в текущий момент. Значение не является NULL при обновлении и равно NULL при вставке или удалении.
- isTombstone: логическое значение, указывающее, конфликтует ли incomingItem с ранее удаленным элементом. При значении true existingItem также имеет значение NULL.
- conflictingItems: массив фиксированной версии всех элементов в контейнере, которые конфликтуют с incomingItem по идентификатору или любым другим свойствам уникального индекса.
Внимание
Как и любая хранимая процедура, пользовательская процедура разрешения конфликтов может получить доступ к любым данным с одним ключом секции и выполнять любую операцию вставки, обновления или удаления для разрешения конфликтов.
В этом примере представлена хранимая процедура, которая позволяет устранять конфликты, выбирая наименьшее значение из пути /myCustomId.
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;
});
}
}
}
Пакет SDK для .NET
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")
});
Пакет SDK для Java версии 4
Асинхронный API пакета SDK для Java версии 4 (Maven com.azure::azure-cosmos)
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy("resolver");
CosmosContainerProperties containerProperties = new CosmosContainerProperties(container_id, partition_key);
containerProperties.setConflictResolutionPolicy(policy);
/* ...other container config... */
database.createContainerIfNotExists(containerProperties).block();
Пакеты средств разработки для Java версии 2
Пакет SDK Async Java версии 2 (Maven com.microsoft.azure::azure-cosmosdb)
DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy("resolver");
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();
После создания контейнера вы должны создать хранимую процедуру resolver.
Пакет SDK для Node.js, JavaScript и TypeScript
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`
}
}
);
После создания контейнера вы должны создать хранимую процедуру resolver.
Пакет SDK для Python
database = client.get_database_client(database=database_id)
udp_custom_resolution_policy = {'mode': 'Custom' }
udp_container = database.create_container(id=udp_container_id, partition_key=PartitionKey(path="/id"),
conflict_resolution_policy=udp_custom_resolution_policy)
После создания контейнера вы должны создать хранимую процедуру resolver.
Создание пользовательской политики разрешения конфликтов
В этих примерах показано, как настроить контейнер с пользовательской политикой разрешения конфликтов. При этом внедрении каждый конфликт отображается в канале конфликтов. Вам решать, как обрабатывать конфликты по отдельности из ленты конфликтов.
Пакет SDK для .NET
DocumentCollection manualCollection = await createClient.CreateDocumentCollectionIfNotExistsAsync(
UriFactory.CreateDatabaseUri(this.databaseName), new DocumentCollection
{
Id = this.manualCollectionName,
ConflictResolutionPolicy = new ConflictResolutionPolicy
{
Mode = ConflictResolutionMode.Custom,
},
});
Пакет SDK для Java версии 4
Асинхронный API пакета SDK для Java версии 4 (Maven com.azure::azure-cosmos)
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy();
CosmosContainerProperties containerProperties = new CosmosContainerProperties(container_id, partition_key);
containerProperties.setConflictResolutionPolicy(policy);
/* ...other container config... */
database.createContainerIfNotExists(containerProperties).block();
Пакеты средств разработки для Java версии 2
Пакет SDK Async Java версии 2 (Maven com.microsoft.azure::azure-cosmosdb)
DocumentCollection collection = new DocumentCollection();
collection.setId(id);
ConflictResolutionPolicy policy = ConflictResolutionPolicy.createCustomPolicy();
collection.setConflictResolutionPolicy(policy);
DocumentCollection createdCollection = client.createCollection(databaseUri, collection, null).toBlocking().value();
Пакет SDK для Node.js, JavaScript и TypeScript
const database = client.database(this.databaseName);
const {
container: manualContainer
} = await database.containers.createIfNotExists({
id: this.manualContainerName,
conflictResolutionPolicy: {
mode: "Custom"
}
});
Пакет SDK для Python
database = client.get_database_client(database=database_id)
manual_resolution_policy = {'mode': 'Custom'}
manual_container = database.create_container(id=manual_container_id, partition_key=PartitionKey(path="/id"),
conflict_resolution_policy=manual_resolution_policy)
Чтение из веб-канала конфликтов
В этих примерах показано, как читать из ленты конфликтов контейнера. Конфликты могут отображаться в списке конфликтов лишь по нескольким причинам.
- Конфликт не был разрешен автоматически
- Конфликт вызвал ошибку с указанной хранимой процедурой
- Политика разрешения конфликтов настроена на пользовательскую и не назначает хранимую процедуру для обработки конфликтов.
Пакет SDK для .NET
FeedResponse<Conflict> conflicts = await delClient.ReadConflictFeedAsync(this.collectionUri);
Пакеты SDK для Java
Пакет SDK для Java версии 4 (Maven com.azure::azure-cosmos)
int requestPageSize = 3;
CosmosQueryRequestOptions options = new CosmosQueryRequestOptions();
CosmosPagedFlux<CosmosConflictProperties> conflictReadFeedFlux = container.readAllConflicts(options);
conflictReadFeedFlux.byPage(requestPageSize).toIterable().forEach(page -> {
int expectedNumberOfConflicts = 0;
int numberOfResults = 0;
Iterator<CosmosConflictProperties> pageIt = page.getElements().iterator();
while (pageIt.hasNext()) {
CosmosConflictProperties conflictProperties = pageIt.next();
// Read the conflict and committed item
CosmosAsyncConflict conflict = container.getConflict(conflictProperties.getId());
CosmosConflictResponse response = conflict.read(new CosmosConflictRequestOptions()).block();
// response.
}
});
Пакет SDK для Node.js, JavaScript и TypeScript
const container = client
.database(this.databaseName)
.container(this.lwwContainerName);
const { result: conflicts } = await container.conflicts.readAll().toArray();
Python
conflicts_iterator = iter(container.list_conflicts())
conflict = next(conflicts_iterator, None)
while conflict:
# Do something with conflict
conflict = next(conflicts_iterator, None)
Следующие шаги
Узнайте больше о следующих понятиях Azure Cosmos DB.
- Глобальное распределение (взгляд изнутри)
- Как настроить приложение для записи в нескольких регионах
- Настройка клиентов для многоподключения
- Добавление и удаление регионов из учетной записи Azure Cosmos DB
- Как настроить приложение для записи в нескольких регионах
- Секционирование и масштабирование в Azure Cosmos DB
- Индексирование в Azure Cosmos DB