Kierowanie zapytania do odpowiedniej bazy danych przy użyciu routingu zależnego od danych
Dotyczy: Azure SQL Database
Routing zależny od danych to możliwość użycia danych w zapytaniu w celu kierowania żądania do odpowiedniej bazy danych. Routing zależny od danych jest podstawowym wzorcem podczas pracy z bazami danych podzielonymi na fragmenty. Kontekst żądania może być również używany do kierowania żądania, zwłaszcza jeśli klucz fragmentowania nie jest częścią zapytania. Każde konkretne zapytanie lub transakcja w aplikacji korzystające z routingu zależnego od danych jest ograniczone do uzyskiwania dostępu do jednej bazy danych na żądanie. W przypadku narzędzi elastycznych usługi Azure SQL Database ten routing odbywa się za pomocą klasy ShardMapManager (Java, .NET).
Aplikacja nie musi śledzić różnych parametry połączenia ani lokalizacji bazy danych skojarzonych z różnymi fragmentami danych w środowisku podzielonym na fragmenty. Zamiast tego Menedżer map fragmentów otwiera połączenia z odpowiednimi bazami danych w razie potrzeby na podstawie danych na mapie fragmentów i wartości klucza fragmentowania, który jest obiektem docelowym żądania aplikacji. Kluczem jest zazwyczaj customer_id, tenant_id, date_key lub inny konkretny identyfikator, który jest podstawowym parametrem żądania bazy danych.
Aby uzyskać więcej informacji, zobacz Skalowanie w poziomie programu SQL Server przy użyciu routingu zależnego od danych.
Pobieranie biblioteki klienta
Aby pobrać:
- Wersja biblioteki w języku Java jest widoczna w temacie Maven Central Repository (Centralne repozytorium Maven).
- Wersja biblioteki .NET— zobacz NuGet.
Używanie elementu ShardMapManager w aplikacji routingu zależnego od danych
Aplikacje powinny utworzyć wystąpienie elementu ShardMapManager podczas inicjowania przy użyciu wywołania fabrycznego GetSQLShardMapManager (Java, .NET). W tym przykładzie zainicjowano zarówno element ShardMapManager , jak i konkretną mapę fragmentów , którą zawiera. W tym przykładzie przedstawiono metody GetSqlShardMapManager i 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");
Uzyskiwanie mapy fragmentów przy użyciu poświadczeń o najniższych uprawnieniach
Jeśli aplikacja nie manipuluje samą mapą fragmentów, poświadczenia używane w metodzie fabryki powinny mieć uprawnienia tylko do odczytu w globalnej bazie danych map fragmentów. Te poświadczenia są zwykle inne niż poświadczenia używane do otwierania połączeń z menedżerem mapy fragmentów. Zobacz również Poświadczenia używane do uzyskiwania dostępu do biblioteki klienta elastycznej bazy danych.
Wywoływanie metody OpenConnectionForKey
Metoda ShardMap.OpenConnectionForKey (Java, .NET) zwraca połączenie gotowe do wydawania poleceń do odpowiedniej bazy danych na podstawie wartości parametru klucza. Informacje o fragmentach są buforowane w aplikacji przez narzędzie ShardMapManager, więc te żądania zwykle nie obejmują wyszukiwania bazy danych względem globalnej bazy danych map fragmentów.
// Syntax:
public Connection openConnectionForKey(Object key, String connectionString, ConnectionOptions options)
// Syntax:
public SqlConnection OpenConnectionForKey<TKey>(TKey key, string connectionString, ConnectionOptions options)
- Parametr klucza jest używany jako klucz odnośnika do mapy fragmentów w celu określenia odpowiedniej bazy danych dla żądania.
- Parametr connectionString służy do przekazywania tylko poświadczeń użytkownika dla żądanego połączenia. W tym parametrze connectionString nie ma nazwy bazy danych ani nazwy serwera, ponieważ metoda określa bazę danych i serwer przy użyciu elementu ShardMap.
- Parametr connectionOptions (Java, .NET) powinien być ustawiony na ConnectionOptions.Validate, jeśli środowisko, w którym mapy fragmentów mogą ulec zmianie, a wiersze mogą zostać przeniesione do innych baz danych w wyniku operacji dzielenia lub scalania. Ta walidacja obejmuje krótkie zapytanie do lokalnej mapy fragmentów w docelowej bazie danych (nie do globalnej mapy fragmentów) przed dostarczeniem połączenia do aplikacji.
Jeśli walidacja względem lokalnej mapy fragmentów nie powiedzie się (wskazująca, że pamięć podręczna jest niepoprawna), Menedżer map fragmentów fragmentów wysyła zapytanie do globalnej mapy fragmentów, aby uzyskać nową poprawną wartość wyszukiwania, zaktualizować pamięć podręczną i uzyskać i zwrócić odpowiednie połączenie z bazą danych.
Użyj właściwości ConnectionOptions.None tylko wtedy, gdy zmiany mapowania fragmentów nie są oczekiwane, gdy aplikacja jest w trybie online. W takim przypadku można założyć, że buforowane wartości są zawsze poprawne, a dodatkowe wywołanie weryfikacji rundy do docelowej bazy danych można bezpiecznie pominąć. Zmniejsza to ruch bazy danych. Parametr connectionOptions można również ustawić za pośrednictwem wartości w pliku konfiguracji, aby wskazać, czy zmiany fragmentowania są oczekiwane, czy nie w danym okresie.
W tym przykładzie użyto wartości klucza całkowitego CustomerID przy użyciu obiektu ShardMap o nazwie 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();
}
Metoda OpenConnectionForKey zwraca nowe już otwarte połączenie z poprawną bazą danych. Połączenia używane w ten sposób nadal korzystają z pełnej możliwości buforowania połączeń.
Metoda OpenConnectionForKeyAsync (Java, .NET) jest również dostępna, jeśli aplikacja używa programowania asynchronicznego.
Integracja z obsługą błędów przejściowych
Najlepszym rozwiązaniem w tworzeniu aplikacji dostępu do danych w chmurze jest zapewnienie, że błędy przejściowe są przechwytywane przez aplikację i że operacje są ponawiane kilka razy przed zgłoszeniem błędu. Obsługa błędów przejściowych dla aplikacji w chmurze została omówiona w temacie Transient Fault Handling (Java, .NET).
Obsługa błędów przejściowych może współistnieć naturalnie ze wzorcem routingu zależnego od danych. Kluczowym wymaganiem jest ponowienie próby całego żądania dostępu do danych, w tym bloku używającego , który uzyskał połączenie routingu zależnego od danych. Powyższy przykład może zostać przepisany w następujący sposób.
Przykład — routing zależny od danych z obsługą błędów przejściowych
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");
}
});
Pakiety niezbędne do zaimplementowania obsługi błędów przejściowych są pobierane automatycznie podczas kompilowania przykładowej aplikacji elastycznej bazy danych.
Spójność transakcyjna
Właściwości transakcyjne są gwarantowane dla wszystkich operacji lokalnych do fragmentu. Na przykład transakcje przesyłane za pośrednictwem routingu zależnego od danych są wykonywane w zakresie docelowego fragmentu dla połączenia. W tej chwili nie ma dostępnych możliwości wprowadzania wielu połączeń do transakcji i dlatego nie ma gwarancji transakcyjnych dla operacji wykonywanych między fragmentami.
Następne kroki
Aby odłączyć fragment lub ponownie dołączyć fragment, zobacz Rozwiązywanie problemów z mapą fragmentu przy użyciu klasy RecoveryManager.
Powiązana zawartość
Jeszcze nie korzystasz z narzędzi elastycznych baz danych? Zapoznaj się z naszym przewodnikiem Wprowadzenie. W przypadku pytań skontaktuj się z nami na stronie pytań i odpowiedzi dotyczących usługi SQL Database oraz w przypadku żądań funkcji, dodaj nowe pomysły lub zagłosuj na istniejące pomysły na forum opinii usługi SQL Database.