數據存儲版本控制、列舉和快取

*此內容是使用 AI(Beta 測試版)翻譯,可能含有錯誤。若要以英文檢視此頁面,請按一下這裡

使用版本控制、列舉和快取來管理您的數據。

版本控制

版本控制在您 設置更新增量 數據時發生。函數 SetAsync()UpdateAsync()IncrementAsync() 使用每個 UTC 小時對每個鍵的首次寫入創建版本備份。對同一 UTC 小時內某個鍵的後續寫入會永久覆蓋先前的數據。

版本備份在新的寫入覆蓋它們后 30 天過期。最新版本永不過期。

以下函數執行版本控制操作:

函數描述

ListVersionsAsync()

列出某個鍵的所有版本,返回一個 DataStoreVersionPages 實例,您可以用它來列舉所有版本號。您可以使用時間範圍過濾版本。

GetVersionAsync()

使用鍵的版本號檢索特定版本的鍵。

RemoveVersionAsync()

刪除特定版本的鍵。

此函數還會創建一個墓碑版本,同時保留先前版本。例如,如果您調用 RemoveAsync("User_1234") 然後再嘗試調用 GetAsync("User_1234"),您將返回 nil。但是,您仍然可以使用 ListVersionsAsync()GetVersionAsync() 檢索數據的舊版本。

您可以使用版本控制來處理用戶請求。如果用戶報告在 2020-10-09T01:42 發生了問題,您可以使用以下示例將數據恢復到先前的版本:


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)
-- 獲取最接近給定時間的版本
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
-- 讀取最近版本
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- 通過使用最近版本覆蓋當前值來恢復
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- 沒有找到條目
end
end

快照

快照數據存儲 Open Cloud API 讓您每天對遊戲中的所有數據存儲進行快照。在發布任何更改數據存儲邏輯的遊戲更新之前,請務必拍攝快照。拍攝快照可以確保您擁有來自遊戲先前版本的最新數據。

例如,沒有快照,如果您在 UTC 時間 3:30 發布了一個導致數據損壞的更新,損壞的數據會覆蓋 3:00-3:30 UTC 之間寫入的任何數據。然而,如果您在 3:29 UTC 拍攝快照,那麼損壞的數據就不會覆蓋任何在 3:29 UTC 之前寫入的內容,並且 3:00-3:29 UTC 之間寫入的所有鍵的最新數據都將被保存。

列舉和前綴

數據存儲允許您按前綴列舉。例如,通過名稱的前 n 個字符列舉,如 "d"、"do" 或 "dog" 用於任何具有 "dog" 前綴的鍵或數據存儲。

您可以在列舉所有數據存儲或鍵時指定前綴,並僅獲取與該前綴匹配的對象。 ListDataStoresAsync()ListKeysAsync() 函數都返回一個 DataStoreListingPages 物件,您可以使用它來列舉列表。

函數描述
ListDataStoresAsync()列出所有數據存儲。
ListKeysAsync()列出數據存儲中的所有鍵。

範圍

您可以通過設置唯一字符串作為 GetDataStore() 的第二個參數的範圍進一步組織數據存儲中的鍵。如果未提供範圍,則默認範圍為 global。範圍會自動附加到所有對數據存儲進行的操作中所有鍵的開頭。

範圍
houses/User_1234houses
pets/User_1234pets
inventory/User_1234inventory

數據存儲名稱、範圍和鍵的組合唯一地識別一個鍵。這三個值都是識別帶有範圍的鍵所必需的。例如,您可以按如下方式讀取名為 User_1234global 範圍鍵:


local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)

如果 User_1234 的範圍是 gold,則只能這樣讀取:


local DataStoreService = game:GetService("DataStoreService")
local inventoryStore = DataStoreService:GetDataStore("PlayerInventory", "gold")
local success, currentGold = pcall(function()
return inventoryStore:GetAsync("User_1234")
end)

AllScopes 屬性

DataStoreOptions 包含一個 AllScopes 屬性,允許您從所有 範圍 中返回鍵的列表。然後,您可以使用列表項的 KeyName 屬性進行常見的數據存儲操作,如使用 GetAsync() 讀取數據 和使用 RemoveAsync() 刪除數據

使用 AllScopes 屬性時,GetDataStore() 的第二個參數必須是一個空字符串 ("")。


local DataStoreService = game:GetService("DataStoreService")
local options = Instance.new("DataStoreOptions")
options.AllScopes = true
local ds = DataStoreService:GetDataStore("DS1", "", options)

如果您啟用 AllScopes 屬性並在數據存儲中創建一個新鍵,則必須始終以範圍/鍵名的格式為該鍵指定範圍。如果不這樣做,API 將拋出錯誤。例如,gold/player_34545 是可接受的,其中 gold 是範圍,但 player_34545 將導致錯誤。

global/K1house/K1
global/L2house/L2
global/M3house/M3

快取

使用快取暫時存儲來自數據存儲的數據,以提高性能並減少對服務器的請求數量。例如,遊戲可以快取其數據的副本,從而可以快速訪問該數據,而無需再次調用數據存儲。

快取適用於您對數據存儲鍵的修改,使用以下方式:

GetVersionAsync()ListVersionsAsync()ListKeysAsync()ListDataStoresAsync() 不實現快取,並始終從服務後端獲取最新數據。

默認情況下,引擎使用 GetAsync() 在本地快取中存儲您從後端檢索的值,時間為四秒。默認情況下,GetAsync() 對快取鍵的請求返回快取值,而不是繼續向後端請求。返回快取值的 GetAsync() 請求不計入您的 服務器限制吞吐量限制

所有從後端檢索未被快取的值的 GetAsync() 調用會立即更新快取並重啟四秒計時器。

禁用快取

要禁用快取並選擇不使用快取從服務器檢索最新值,請在您的 GetAsync() 調用中添加 DataStoreGetOptions 參數並將 UseCache 屬性設置為 false,以使您的請求忽略快取中的任何鍵。

禁用快取在您有多個服務器以高頻率寫入同一鍵並需要從服務器獲取最新值時很有用。不過,這可能會導致您消耗更多的 數據存儲限制和配額,因為繞過快取的 GetAsync() 請求始終計入您的吞吐量和服務器限制。

在寫入後進行即時驗證讀取時,使用 GetAsync() 並設置 DataStoreGetOptions.UseCache = false。默認情況下,GetAsync() 使用本地四秒快取,因此正常的驗證讀取可能會返回陳舊數據。

這在寫操作(如 UpdateAsync()SetAsync()IncrementAsync()RemoveAsync() 返回錯誤時特別重要。在這些情況下,您的代碼需要確定是重試、退還還是採取其他修正措施。

以下示例顯示如何在驗證寫入結果時繞過快取:


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
-- 根據後端狀態決定,而不是快取狀態
end
end

序列化

DataStoreService 以 JSON 格式存儲數據。當您在 Studio 中保存 Luau 數據時,Roblox 使用稱為序列化的過程將該數據轉換為 JSON,以便將其保存在數據存儲中。然後,Roblox 將您的數據轉換回 Luau 並通過另一個名為反序列化的過程返回給您。

序列化和反序列化支持以下 Luau 數據類型:

  • 數字
    • 您不應該存儲特殊的數值 inf-infnan,因為這些值不符合 JSON 標準。您無法使用 Open Cloud 訪問包含這些值的鍵。
  • 表格
    • 表格只能包含其他受支持的數據類型
    • 如果表格的長度為 0,則數字鍵將轉換為字符串

如果您嘗試存儲序列化不支持的數據類型,您將:

  • 無法存儲該數據類型並收到錯誤消息。
  • 成功將該數據類型存儲為 nil

要調試為什麼您的數據類型被存儲為 nil,您可以使用 JSONEncode 函數。當您將您的 Luau 數據類型傳遞給該函數時,您會獲得它的返回格式,這是 Roblox 會將其存儲在數據存儲中的格式,讓您預覽並調查返回的數據。

©2026 Roblox Corporation、Roblox、Roblox 標誌及 Powering Imagination 是我們在美國及其他國家地區的部分註冊與未註冊商標。