Usar roteamento dependente de dados para rotear uma consulta para um banco de dados apropriado
Aplica-se a:Banco de Dados SQL do Azure
Roteamento dependente de dados é a capacidade de usar os dados em uma consulta para rotear a solicitação para um banco de dados apropriado. O roteamento dependente de dados é um padrão fundamental ao trabalhar com bancos de dados fragmentados. O contexto da solicitação também pode ser usado para rotear a solicitação, especialmente se a chave de fragmentação não fizer parte da consulta. Cada consulta ou transação específica em um aplicativo usando roteamento dependente de dados é restrita ao acesso a um banco de dados por solicitação. Para as ferramentas elásticas do Banco de Dados SQL do Azure, esse roteamento é realizado com a classe ShardMapManager (Java, .NET).
O aplicativo não precisa rastrear várias cadeias de conexão ou locais de banco de dados associados a diferentes fatias de dados no ambiente fragmentado. Em vez disso, o Shard Map Manager abre conexões com os bancos de dados corretos quando necessário, com base nos dados no mapa de estilhaços e no valor da chave de fragmentação que é o destino da solicitação do aplicativo. A chave normalmente é o customer_id, tenant_id, date_key ou algum outro identificador específico que é um parâmetro fundamental da solicitação de banco de dados.
Para obter mais informações, consulte Dimensionando o SQL Server com roteamento dependente de dados.
Baixe a biblioteca do cliente
Para transferir:
- A versão Java da biblioteca, consulte Maven Central Repository.
- A versão .NET da biblioteca, consulte NuGet.
Usando um ShardMapManager em um aplicativo de roteamento dependente de dados
Os aplicativos devem instanciar o ShardMapManager durante a inicialização, usando a chamada de fábrica GetSQLShardMapManager (Java, .NET). Neste exemplo, um ShardMapManager e um ShardMap específico que ele contém são inicializados. Este exemplo mostra os métodos GetSqlShardMapManager e GetRangeShardMap (Java, .NET).
ShardMapManager smm = ShardMapManagerFactory.getSqlShardMapManager(connectionString, ShardMapManagerLoadPolicy.Lazy);
RangeShardMap<int> rangeShardMap = smm.getRangeShardMap(Configuration.getRangeShardMapName(), ShardKeyType.Int32);
ShardMapManager smm = ShardMapManagerFactory.GetSqlShardMapManager(smmConnectionString, ShardMapManagerLoadPolicy.Lazy);
RangeShardMap<int> customerShardMap = smm.GetRangeShardMap<int>("customerMap");
Use as credenciais de menor privilégio possível para obter o mapa de estilhaços
Se um aplicativo não estiver manipulando o mapa de estilhaços em si, as credenciais usadas no método de fábrica deverão ter permissões somente leitura no banco de dados do Mapa Global de Fragmentos. Essas credenciais geralmente são diferentes das credenciais usadas para abrir conexões com o gerenciador de mapas de estilhaços. Consulte também Credenciais usadas para acessar a biblioteca de cliente do Elastic Database.
Chamar o método OpenConnectionForKey
O método ShardMap.OpenConnectionForKey (Java, .NET) retorna uma conexão pronta para emitir comandos para o banco de dados apropriado com base no valor do parâmetro key . As informações de estilhaços são armazenadas em cache no aplicativo pelo ShardMapManager, portanto, essas solicitações normalmente não envolvem uma pesquisa de banco de dados no banco de dados do Mapa Global de Fragmentos.
// Syntax:
public Connection openConnectionForKey(Object key, String connectionString, ConnectionOptions options)
// Syntax:
public SqlConnection OpenConnectionForKey<TKey>(TKey key, string connectionString, ConnectionOptions options)
- O parâmetro key é usado como uma chave de pesquisa no mapa de estilhaços para determinar o banco de dados apropriado para a solicitação.
- O connectionString é usado para passar apenas as credenciais do usuário para a conexão desejada. Nenhum nome de banco de dados ou nome de servidor é incluído neste connectionString uma vez que o método determina o banco de dados e o servidor usando o ShardMap.
- O connectionOptions (Java, .NET) deve ser definido como ConnectionOptions.Validate se um ambiente onde os mapas de estilhaços podem ser alterados e as linhas podem ser movidas para outros bancos de dados como resultado de operações de divisão ou mesclagem. Essa validação envolve uma breve consulta ao mapa de fragmentos local no banco de dados de destino (não ao mapa de fragmentos global) antes que a conexão seja entregue ao aplicativo.
Se a validação em relação ao mapa de fragmentos local falhar (indicando que o cache está incorreto), o Gerenciador de Fragmentos consulta o mapa de fragmentos global para obter o novo valor correto para a pesquisa, atualizar o cache e obter e retornar a conexão de banco de dados apropriada.
Use ConnectionOptions.None somente quando as alterações de mapeamento de estilhaços não forem esperadas enquanto um aplicativo estiver online. Nesse caso, pode-se presumir que os valores armazenados em cache estão sempre corretos e a chamada de validação de ida e volta extra para o banco de dados de destino pode ser ignorada com segurança. Isso reduz o tráfego do banco de dados. As connectionOptions também podem ser definidas por meio de um valor em um arquivo de configuração para indicar se as alterações de fragmentação são esperadas ou não durante um período de tempo.
Este exemplo usa o valor de uma chave inteira CustomerID, usando um objeto ShardMap chamado customerShardMap.
int customerId = 12345;
int productId = 4321;
// Looks up the key in the shard map and opens a connection to the shard
try (Connection conn = shardMap.openConnectionForKey(customerId, Configuration.getCredentialsConnectionString())) {
// Create a simple command that will insert or update the customer information
PreparedStatement ps = conn.prepareStatement("UPDATE Sales.Customer SET PersonID = ? WHERE CustomerID = ?");
ps.setInt(1, productId);
ps.setInt(2, customerId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
int customerId = 12345;
int newPersonId = 4321;
// Connect to the shard for that customer ID. No need to call a SqlConnection
// constructor followed by the Open method.
using (SqlConnection conn = customerShardMap.OpenConnectionForKey(customerId, Configuration.GetCredentialsConnectionString(), ConnectionOptions.Validate))
{
// Execute a simple command.
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = @"UPDATE Sales.Customer
SET PersonID = @newPersonID WHERE CustomerID = @customerID";
cmd.Parameters.AddWithValue("@customerID", customerId);cmd.Parameters.AddWithValue("@newPersonID", newPersonId);
cmd.ExecuteNonQuery();
}
O método OpenConnectionForKey retorna uma nova conexão já aberta para o banco de dados correto. As conexões utilizadas dessa forma ainda aproveitam ao máximo o pool de conexões.
O método OpenConnectionForKeyAsync (Java, .NET) também está disponível se seu aplicativo fizer uso de programação assíncrona.
Integração com tratamento de falhas transitórias
Uma prática recomendada no desenvolvimento de aplicativos de acesso a dados na nuvem é garantir que falhas transitórias sejam detetadas pelo aplicativo e que as operações sejam repetidas várias vezes antes de lançar um erro. O tratamento de falhas transitórias para aplicativos em nuvem é discutido em Tratamento de falhas transitórias (Java, .NET).
O tratamento de falhas transitórias pode coexistir naturalmente com o padrão de Roteamento Dependente de Dados. O principal requisito é repetir toda a solicitação de acesso a dados, incluindo o bloco de uso que obteve a conexão de roteamento dependente de dados. O exemplo anterior pode ser reescrito da seguinte forma.
Exemplo - roteamento dependente de dados com tratamento de falhas transitórias
int customerId = 12345;
int productId = 4321;
try {
SqlDatabaseUtils.getSqlRetryPolicy().executeAction(() -> {
// Looks up the key in the shard map and opens a connection to the shard
try (Connection conn = shardMap.openConnectionForKey(customerId, Configuration.getCredentialsConnectionString())) {
// Create a simple command that will insert or update the customer information
PreparedStatement ps = conn.prepareStatement("UPDATE Sales.Customer SET PersonID = ? WHERE CustomerID = ?");
ps.setInt(1, productId);
ps.setInt(2, customerId);
ps.executeUpdate();
} catch (SQLException e) {
e.printStackTrace();
}
});
} catch (Exception e) {
throw new StoreException(e.getMessage(), e);
}
int customerId = 12345;
int newPersonId = 4321;
Configuration.SqlRetryPolicy.ExecuteAction(() -> {
// Connect to the shard for a customer ID.
using (SqlConnection conn = customerShardMap.OpenConnectionForKey(customerId, Configuration.GetCredentialsConnectionString(), ConnectionOptions.Validate))
{
// Execute a simple command
SqlCommand cmd = conn.CreateCommand();
cmd.CommandText = @"UPDATE Sales.Customer
SET PersonID = @newPersonID
WHERE CustomerID = @customerID";
cmd.Parameters.AddWithValue("@customerID", customerId);
cmd.Parameters.AddWithValue("@newPersonID", newPersonId);
cmd.ExecuteNonQuery();
Console.WriteLine("Update completed");
}
});
Os pacotes necessários para implementar o tratamento de falhas transitórias são baixados automaticamente quando você cria o aplicativo de exemplo de banco de dados elástico.
Consistência transacional
As propriedades transacionais são garantidas para todas as operações locais para um fragmento. Por exemplo, as transações enviadas por meio de roteamento dependente de dados são executadas dentro do escopo do fragmento de destino para a conexão. No momento, não há recursos fornecidos para inscrever várias conexões em uma transação e, portanto, não há garantias transacionais para operações realizadas entre fragmentos.
Próximos passos
Para desanexar um fragmento ou reanexá-lo, consulte Usando a classe RecoveryManager para corrigir problemas de mapa de estilhaços.
Recursos adicionais
Ainda não está usando ferramentas de banco de dados elástico? Consulte o nosso Guia de Introdução. Para dúvidas, entre em contato conosco na página de perguntas e respostas da Microsoft para o Banco de dados SQL e para solicitações de recursos, adicione novas ideias ou vote em ideias existentes no fórum de comentários do Banco de dados SQL.