Zarządzaj swoimi danymi za pomocą wersjonowania, wyświetlania i pamięci podręcznej.
Wersjonowanie
Wersjonowanie zachodzi, gdy ustawisz, zaktualizujesz i inkrementujesz dane. Funkcje SetAsync(), UpdateAsync() oraz IncrementAsync() tworzą wersjonowane kopie zapasowe twoich danych przy użyciu pierwszego zapisu do każdego klucza w każdej godzinie UTC. Kolejne zapisy do klucza w tej samej godzinie UTC na stałe nadpisują poprzednie dane.
Wersjonowane kopie zapasowe wygasają 30 dni po tym, jak nowy zapis je nadpisuje. Najnowsza wersja nigdy nie wygasa.
Poniższe funkcje wykonują operacje wersjonowania:
| Funkcja | Opis |
|---|---|
Wyświetla wszystkie wersje dla klucza, zwracając instancję DataStoreVersionPages, której możesz użyć do enumeracji wszystkich numerów wersji. Możesz filtrować wersje za pomocą zakresu czasowego. | |
Pobiera określoną wersję klucza przy użyciu numeru wersji klucza. | |
Usuwa określoną wersję klucza. Ta funkcja tworzy również wersję grobową, zachowując jednocześnie poprzednią wersję. Na przykład, jeśli wywołasz RemoveAsync("User_1234"), a następnie spróbujesz wywołać GetAsync("User_1234"), otrzymasz nil. Możesz jednak nadal używać ListVersionsAsync() oraz GetVersionAsync() do pobierania starszych wersji danych. |
Możesz używać wersjonowania do obsługi żądań użytkowników. Jeśli użytkownik zgłosi problem, który wystąpił 2020-10-09T01:42, możesz przywrócić dane do poprzedniej wersji, używając poniższego przykładu:
local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local DATA_STORE_KEY = "User_1234"
local maxDate = DateTime.fromUniversalTime(2020, 10, 09, 01, 42)
-- Pobiera wersję najbliższą podanemu czasowi
local listSuccess, pages = pcall(function()
return gameStore:ListVersionsAsync(DATA_STORE_KEY, Enum.SortDirection.Descending, nil, maxDate.UnixTimestampMillis)
end)
if listSuccess then
local items = pages:GetCurrentPage()
if #items > 0 then
-- Odczytuje najbliższą wersję
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- Przywraca aktualną wartość, nadpisując ją najbliższą wersją
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- Nie znaleziono wpisów
end
end
Zrzuty
Snapshot Data Stores Open Cloud API pozwala na zrobienie zrzutu wszystkich magazynów danych w grze raz dziennie. Przed opublikowaniem aktualizacji gry zmieniającej logikę przechowywania danych, upewnij się, że zrobisz zrzut. Zrobienie zrzutu gwarantuje, że masz dostęp do najbardziej aktualnych danych z poprzedniej wersji gry.
Na przykład, bez zrzutu, jeśli opublikujesz aktualizację o 3:30 UTC, która powoduje uszkodzenie danych, uszkodzone dane nadpiszą wszelkie dane zapisane między 3:00 a 3:30 UTC. Jeśli jednak zrobisz zrzut o 3:29 UTC, uszkodzone dane nie nadpiszą niczego, co zostało zapisane przed 3:29 UTC, a najnowsze dane dla wszystkich kluczy zapisanych między 3:00 a 3:29 UTC zostaną zachowane.
Wyświetlanie i prefiksy
Magazyny danych pozwalają na wyświetlanie według prefiksu. Na przykład, wyświetlanie pierwszych n znaków nazwy, jak "d", "do" lub "dog" dla dowolnego klucza lub magazynu danych z prefiksem "dog".
Możesz określić prefiks podczas wyświetlania wszystkich magazynów danych lub kluczy i uzyskać tylko obiekty, które pasują do tego prefiksu. Funkcje ListDataStoresAsync() oraz ListKeysAsync() zwracają obiekt DataStoreListingPages, który możesz użyć do enumeracji listy.
| Funkcja | Opis |
|---|---|
| ListDataStoresAsync() | Wyświetla wszystkie magazyny danych. |
| ListKeysAsync() | Wyświetla wszystkie klucze w magazynie danych. |
Zakresy
Możesz dalej organizować klucze w magazynie danych, ustawiając unikalny ciąg jako zakres dla drugiego parametru funkcji GetDataStore(). Domyślny zakres (jeśli nie jest podany) to global. Zakres jest automatycznie dodawany na początku wszystkich kluczy we wszystkich operacjach wykonywanych na magazynie danych.
| Klucz | Zakres |
|---|---|
| houses/User_1234 | houses |
| pets/User_1234 | pets |
| inventory/User_1234 | inventory |
Połączenie nazwy magazynu danych, zakresu i klucza unikalnie identyfikuje klucz. Wszystkie trzy wartości są wymagane do identyfikacji klucza w ramach zakresu. Na przykład, możesz odczytać klucz o zakresie global nazwany User_1234 jako:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
Jeśli klucz User_1234 ma zakres gold, możesz go odczytać tylko jako:
local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory", "gold")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)
Właściwość AllScopes
DataStoreOptions zawiera właściwość AllScopes, która pozwala na zwrócenie kluczy ze wszystkich zakresów w liście. Możesz następnie użyć właściwości KeyName elementu na liście do wspólnych operacji na magazynie danych, takich jak odczyt danych za pomocą GetAsync() oraz usuwanie danych za pomocą RemoveAsync().
Kiedy używasz właściwości AllScopes, drugi parametr funkcji GetDataStore() musi być pustym ciągiem ("").
local DataStoreService = game:GetService("DataStoreService")local options = Instance.new("DataStoreOptions")options.AllScopes = truelocal ds = DataStoreService:GetDataStore("DS1", "", options)
Jeśli włączysz właściwość AllScopes i utworzysz nowy klucz w magazynie danych, zawsze musisz określić zakres dla tego klucza w formacie zakres/klucz-nazwy. Jeśli tego nie zrobisz, API zwróci błąd. Na przykład, gold/player_34545 jest akceptowalne z gold jako zakresem, ale player_34545 prowadzi do błędu.
| global/K1 | house/K1 |
| global/L2 | house/L2 |
| global/M3 | house/M3 |
Pamięć podręczna
Używaj pamięci podręcznej do tymczasowego przechowywania danych z magazynów danych, aby poprawić wydajność i zmniejszyć liczbę żądań wysyłanych do serwera. Na przykład, gra może przechować kopię swoich danych, aby mieć szybki dostęp do tych danych bez konieczności wykonywania kolejnego wywołania do magazynu danych.
Pamięć podręczna ma zastosowanie do modyfikacji, które wykonujesz dla kluczy magazynu danych za pomocą:
GetVersionAsync(), ListVersionsAsync(), ListKeysAsync(), oraz ListDataStoresAsync() nie implementują pamięci podręcznej i zawsze pobierają najnowsze dane z zaplecza serwisowego.
Domyślnie, silnik używa GetAsync() do przechowywania wartości, które otrzymujesz z zaplecza w lokalnej pamięci podręcznej przez cztery sekundy. Również domyślnie, żądania GetAsync() dla kluczy w pamięci podręcznej zwracają wartość z pamięci podręcznej zamiast kontynuować do zaplecza. Twoje żądania GetAsync(), które zwracają wartość z pamięci podręcznej, nie liczą się w ramach twoich limitów serwera oraz limitów przepustowości.
Wszystkie wywołania GetAsync(), które pobierają wartość, która nie jest buforowana z zaplecza, aktualizują pamięć podręczną natychmiastowo i restartują czterosekundowy licznik.
Wyłączenie pamięci podręcznej
Aby wyłączyć pamięć podręczną i zrezygnować z jej użycia, aby uzyskać najnowszą wartość z serwerów, dodaj parametr DataStoreGetOptions do swojego wywołania GetAsync() i ustaw właściwość UseCache na false, aby sprawić, że twoje żądanie zignoruje wszelkie klucze w pamięci podręcznej.
Wyłączenie pamięci podręcznej jest przydatne, jeśli masz wiele serwerów piszących do klucza z wysoką częstotliwością i musisz uzyskać najnowszą wartość z serwerów. Jednak może to spowodować, że zużyjesz więcej swoich limitów i kwot magazynów danych, ponieważ żądania GetAsync(), które omijają pamięć podręczną, zawsze liczą się w ramach twoich limitów przepustowości i serwera.
Aby natychmiast zweryfikować odczyty po zapisie, użyj GetAsync() z DataStoreGetOptions.UseCache = false. Domyślnie GetAsync() używa lokalnej pamięci podręcznej na cztery sekundy, więc normalny odczyt weryfikacyjny może zwrócić nieaktualne dane.
Jest to szczególnie ważne po operacjach zapisu, takich jak UpdateAsync(), SetAsync(), IncrementAsync(), czy RemoveAsync(), które zwracają błąd. W takich przypadkach twój kod musi określić, czy należy ponowić próbę, zwrócić pieniądze lub podjąć inne działania korygujące.
Poniższy przykład pokazuje, jak pominąć pamięć podręczną podczas weryfikacji wyniku zapisu:
local ok = pcall(function()
store:UpdateAsync(key, transform)
end)
if not ok then
local options = Instance.new("DataStoreGetOptions")
options.UseCache = false
local success, value = pcall(function()
return store:GetAsync(key, options)
end)
if success then
-- zdecyduj na podstawie stanu zaplecza, a nie stanu z pamięci podręcznej
end
end
Serializacja
DataStoreService przechowuje dane w formacie JSON. Kiedy zapisujesz dane Luau w Studio, Roblox używa procesu zwanego serializacją, aby przekonwertować te dane na JSON, aby zapisać je w magazynach danych. Następnie Roblox konwertuje twoje dane z powrotem na Luau i zwraca je w innym procesie zwanym deserializacją.
Serializacja i deserializacja wspiera następujące typy danych Luau:
- Liczby
- Nie należy przechowywać specjalnych wartości liczbowych inf, -inf i nan, ponieważ te wartości nie są zgodne ze standardami JSON. Nie można uzyskać dostępu do kluczy, które zawierają te wartości z Open Cloud.
- Tabele
- Tabele muszą zawierać tylko inne wspierane typy danych
- Klucze numeryczne są tłumaczone na ciągi, jeśli długość tabeli wynosi 0
Jeśli spróbujesz zapisać typ danych, którego serializacja nie obsługuje, otrzymasz:
- Niepowodzenie w zapisie tego typu danych i komunikat o błędzie.
- Udany zapis tego typu danych jako nil.
Aby zdebugować, dlaczego twój typ danych jest zapisywany jako nil, możesz użyć funkcji JSONEncode. Kiedy przekażesz swój typ danych Luau do tej funkcji, otrzymasz go z powrotem w formacie, w jakim Roblox zapisałby go w magazynach danych, co pozwala na podgląd i zbadanie zwróconych danych.