Phiên bản lưu trữ dữ liệu, liệt kê và bộ nhớ cache

*Nội dung này được dịch bằng AI (Beta) và có thể có lỗi. Để xem trang này bằng tiếng Anh, hãy nhấp vào đây.

Quản lý dữ liệu của bạn bằng cách sử dụng phiên bản, liệt kê và bộ nhớ cache.

Phiên bản

Phiên bản diễn ra khi bạn thiết lập, cập nhật, và tăng dữ liệu. Các hàm SetAsync(), UpdateAsync(), và IncrementAsync() tạo các bản sao lưu có phiên bản của dữ liệu của bạn sử dụng lần ghi đầu tiên vào mỗi khóa trong mỗi giờ UTC. Các lần ghi tiếp theo vào một khóa trong cùng một giờ UTC sẽ ghi đè vĩnh viễn dữ liệu trước đó.

Các bản sao lưu có phiên bản sẽ hết hạn sau 30 ngày kể từ khi một lần ghi mới ghi đè lên chúng. Phiên bản mới nhất sẽ không bao giờ hết hạn.

Các hàm sau đây thực hiện các thao tác phiên bản:

HàmMô tả

ListVersionsAsync()

Liệt kê tất cả các phiên bản của một khóa bằng cách trả về một thể hiện DataStoreVersionPages mà bạn có thể sử dụng để liệt kê tất cả các số phiên bản. Bạn có thể lọc các phiên bản bằng cách sử dụng một khoảng thời gian.

GetVersionAsync()

Lấy một phiên bản cụ thể của một khóa bằng số phiên bản của khóa đó.

RemoveVersionAsync()

Xóa một phiên bản cụ thể của một khóa.

Hàm này cũng tạo một phiên bản tombstone trong khi giữ lại phiên bản trước đó. Ví dụ, nếu bạn gọi RemoveAsync("User_1234") và sau đó cố gắng gọi GetAsync("User_1234"), bạn sẽ nhận được nil trở lại. Tuy nhiên, bạn vẫn có thể sử dụng ListVersionsAsync()GetVersionAsync() để lấy các phiên bản cũ hơn của dữ liệu.

Bạn có thể sử dụng phiên bản để xử lý các yêu cầu từ người dùng. Nếu một người dùng báo cáo rằng một vấn đề xảy ra vào lúc 2020-10-09T01:42, bạn có thể khôi phục dữ liệu về một phiên bản trước đó bằng ví dụ sau:


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)
-- Lấy phiên bản gần nhất với thời gian đã cho
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
-- Đọc phiên bản gần nhất
local closestEntry = items[1]
local success, value, info = pcall(function()
return gameStore:GetVersionAsync(DATA_STORE_KEY, closestEntry.Version)
end)
-- Khôi phục giá trị hiện tại bằng cách ghi đè nó bằng phiên bản gần nhất
if success then
local setOptions = Instance.new("DataStoreSetOptions")
setOptions:SetMetadata(info:GetMetadata())
gameStore:SetAsync(DATA_STORE_KEY, value, nil, setOptions)
end
else
-- Không tìm thấy mục nào
end
end

Ảnh chóp

API Mở Cloud Lưu trữ Dữ liệu Ảnh chóp cho phép bạn chụp một ảnh chóp của tất cả các kho lưu trữ dữ liệu trong một trò chơi mỗi ngày một lần. Trước khi bạn phát hành bất kỳ bản cập nhật nào cho trò chơi thay đổi logic lưu trữ dữ liệu của bạn, hãy chắc chắn chụp một ảnh chóp. Việc chụp một ảnh chóp đảm bảo rằng bạn có dữ liệu mới nhất có sẵn từ phiên bản trước của trò chơi.

Ví dụ, không có ảnh chóp, nếu bạn phát hành một bản cập nhật vào lúc 3:30 UTC làm hỏng dữ liệu, dữ liệu bị hỏng sẽ ghi đè lên bất kỳ dữ liệu nào được ghi giữa 3:00-3:30 UTC. Nhưng nếu bạn chụp một ảnh chóp lúc 3:29 UTC, dữ liệu bị hỏng sẽ không ghi đè lên bất kỳ dữ liệu nào được ghi trước 3:29 UTC, và dữ liệu mới nhất cho tất cả các khóa được ghi giữa 3:00-3:29 UTC sẽ được bảo tồn.

Liệt kê và tiền tố

Kho lưu trữ dữ liệu cho phép bạn liệt kê theo tiền tố. Ví dụ, liệt kê theo n ký tự đầu tiên của một tên, như "d", "do", hoặc "dog" cho bất kỳ khóa hoặc kho lưu trữ dữ liệu nào có tiền tố là "dog".

Bạn có thể chỉ định một tiền tố khi liệt kê tất cả các kho lưu trữ dữ liệu hoặc khóa, và chỉ nhận lại các đối tượng khớp với tiền tố đó. Cả hai hàm ListDataStoresAsync()ListKeysAsync() trả về một đối tượng DataStoreListingPages mà bạn có thể sử dụng để liệt kê danh sách.

HàmMô tả
ListDataStoresAsync()Liệt kê tất cả các kho lưu trữ dữ liệu.
ListKeysAsync()Liệt kê tất cả các khóa trong một kho lưu trữ dữ liệu.

Phạm vi

Bạn có thể tổ chức các khóa trong kho lưu trữ dữ liệu hơn nữa bằng cách đặt một chuỗi độc nhất làm phạm vi cho tham số thứ hai của GetDataStore(). Phạm vi mặc định (nếu không có phạm vi nào được chỉ định) là global. Phạm vi sẽ tự động được thêm vào đầu tất cả các khóa trong mọi thao tác thực hiện trên kho lưu trữ dữ liệu.

KhóaPhạm vi
houses/User_1234houses
pets/User_1234pets
inventory/User_1234inventory

Sự kết hợp của tên kho lưu trữ dữ liệu, phạm vi và khóa xác định duy nhất một khóa. Tất cả ba giá trị đều cần thiết để xác định một khóa với một phạm vi. Ví dụ, bạn có thể đọc một khóa có phạm vi global tên là User_1234 như sau:


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

Nếu khóa User_1234 có phạm vi là gold, thì bạn chỉ có thể đọc nó như sau:


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

Thuộc tính AllScopes

DataStoreOptions chứa thuộc tính AllScopes cho phép bạn trả về các khóa từ tất cả các phạm vi trong một danh sách. Bạn có thể sử dụng thuộc tính KeyName của một mục trong danh sách cho các thao tác kho dữ liệu chung như đọc dữ liệu bằng GetAsync()xóa dữ liệu bằng RemoveAsync().

Khi bạn sử dụng thuộc tính AllScopes, tham số thứ hai của GetDataStore() phải là một chuỗi rỗng ("").


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

Nếu bạn kích hoạt thuộc tính AllScopes và tạo một khóa mới trong kho lưu trữ dữ liệu, bạn luôn phải chỉ định một phạm vi cho khóa đó theo định dạng phạm vi/khóa. Nếu không, các API sẽ ném ra lỗi. Ví dụ, gold/player_34545 là hợp lệ với gold là phạm vi, nhưng player_34545 sẽ dẫn đến một lỗi.

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

Bộ nhớ cache

Sử dụng bộ nhớ cache để lưu trữ tạm thời dữ liệu từ các kho lưu trữ dữ liệu nhằm cải thiện hiệu suất và giảm số lượng yêu cầu gửi đến máy chủ. Ví dụ, một trò chơi có thể lưu trữ một bản sao của dữ liệu của mình để có thể truy cập nhanh chóng dữ liệu đó mà không cần thực hiện thêm một cuộc gọi khác đến kho lưu trữ dữ liệu.

Bộ nhớ cache áp dụng cho các sửa đổi bạn thực hiện đối với các khóa kho lưu trữ dữ liệu bằng cách sử dụng:

GetVersionAsync(), ListVersionsAsync(), ListKeysAsync(), và ListDataStoresAsync() không thực hiện bộ nhớ cache và luôn lấy dữ liệu mới nhất từ backend dịch vụ.

Mặc định, engine sử dụng GetAsync() để lưu trữ các giá trị bạn lấy từ backend vào bộ nhớ cache cục bộ trong bốn giây. Cũng theo mặc định, các yêu cầu GetAsync() cho các khóa đã được lưu trong bộ nhớ cache sẽ trả về giá trị đã được lưu thay vì tiếp tục đến backend. Các yêu cầu GetAsync() của bạn trả về một giá trị đã được lưu không tính vào giới hạn máy chủgiới hạn throughput.

Tất cả các cuộc gọi GetAsync() mà truy xuất một giá trị không được lưu trong bộ nhớ cache từ backend sẽ cập nhật bộ nhớ cache ngay lập tức và khởi động lại bộ đếm thời gian bốn giây.

Vô hiệu hóa bộ nhớ cache

Để vô hiệu hóa bộ nhớ cache và không sử dụng bộ nhớ cache để truy xuất giá trị cập nhật nhất từ các máy chủ, hãy thêm tham số DataStoreGetOptions vào cuộc gọi GetAsync() của bạn và đặt thuộc tính UseCache thành false để yêu cầu của bạn bỏ qua mọi khóa trong bộ nhớ cache.

Việc vô hiệu hóa bộ nhớ cache rất hữu ích nếu bạn có nhiều máy chủ ghi vào một khóa với tần suất cao và cần lấy giá trị mới nhất từ các máy chủ. Tuy nhiên, điều này có thể khiến bạn tiêu thụ nhiều hơn giới hạn và hạn ngạch kho lưu trữ dữ liệu của bạn, vì các yêu cầu GetAsync() bỏ qua bộ nhớ cache luôn tính vào throughput và giới hạn máy chủ của bạn.

Để xác minh ngay lập tức các lần đọc sau khi ghi, hãy sử dụng GetAsync() với DataStoreGetOptions.UseCache = false. Mặc định, GetAsync() sử dụng bộ nhớ cache cục bộ bốn giây, vì vậy một lần đọc xác minh bình thường có thể trả về dữ liệu lỗi thời.

Điều này đặc biệt quan trọng sau các hoạt động ghi như UpdateAsync(), SetAsync(), IncrementAsync(), hoặc RemoveAsync() trở về lỗi. Trong những trường hợp này, mã của bạn cần xác định xem có nên thử lại, hoàn lại, hoặc thực hiện các hành động sửa lỗi khác hay không.

Ví dụ sau đây cho thấy cách bỏ qua bộ nhớ cache khi xác minh kết quả của một phép ghi:


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
-- quyết định dựa trên trạng thái backend, không phải trạng thái cached
end
end

Tuần tự hóa

DataStoreService lưu trữ dữ liệu ở định dạng JSON. Khi bạn lưu trữ dữ liệu Luau trong Studio, Roblox sử dụng một quá trình gọi là tuần tự hóa để chuyển đổi dữ liệu đó thành JSON để lưu trữ trong các kho lưu trữ dữ liệu. Roblox sau đó chuyển đổi dữ liệu của bạn trở lại thành Luau và trả nó cho bạn qua một quá trình khác gọi là giải tuần tự hóa.

Tuần tự hóa và giải tuần tự hóa hỗ trợ các kiểu dữ liệu Luau sau đây:

  • Số
    • Bạn không nên lưu trữ các giá trị số đặc biệt inf, -inf, và nan, vì những giá trị này không tuân thủ các tiêu chuẩn JSON. Bạn không thể truy cập các khóa chứa các giá trị này qua Open Cloud.
  • Bảng
    • Các bảng chỉ phải chứa các loại dữ liệu hỗ trợ khác
    • Các khóa số được chuyển đổi thành chuỗi nếu độ dài của bảng là 0

Nếu bạn cố gắng lưu trữ một kiểu dữ liệu mà không được tuần tự hóa hỗ trợ, bạn sẽ:

  • Thất bại trong việc lưu trữ kiểu dữ liệu đó và nhận được một thông báo lỗi.
  • Thành công trong việc lưu trữ kiểu dữ liệu đó dưới dạng nil.

Để gỡ rối lý do tại sao kiểu dữ liệu của bạn được lưu trữ dưới dạng nil, bạn có thể sử dụng hàm JSONEncode. Khi bạn truyền kiểu dữ liệu Luau của mình vào hàm này, bạn nhận lại nó ở định dạng mà Roblox sẽ lưu trữ với các kho lưu trữ dữ liệu, giúp bạn xem trước và điều tra dữ liệu đã trả về.

©2026 Roblox Corporation. Roblox, logo Roblox và Powering Imagination là các nhãn hiệu đã đăng ký và chưa đăng ký của chúng tôi tại Hoa Kỳ và các quốc gia khác.