数据存储

*此内容使用人工智能(Beta)翻译,可能包含错误。若要查看英文页面,请点按 此处

DataStoreService 允许您存储需要在会话之间持久化的数据,例如玩家库存中的物品或技能点。数据存储在每个游戏中是一致的,因此游戏中的任何位置都可以访问和更改相同的数据,包括不同服务器上的位置。

如果您想为数据存储添加细粒度的权限控制,并在 Studio 或 Roblox 服务器之外访问它们,可以使用 开放云 API 来获取数据存储

要通过 Creator Hub 查看和监视游戏中的所有数据存储,请使用 数据存储管理器

对于需要频繁更新或访问的临时数据,请使用 内存存储

启用 Studio 访问

默认情况下,在 Studio 中测试的游戏无法访问数据存储,因此您必须首先启用它们。在 Studio 中访问数据存储对实时游戏是危险的,因为 Studio 访问与客户端应用程序相同的数据存储。为了避免覆盖生产数据,请不要为实时游戏启用此设置。相反,请为游戏的单独测试版本启用它。

要在 发布的 游戏中启用 Studio 访问:

  1. 打开 Studio 的 文件 ⟩ 体验设置 窗口。
  2. 转到 安全性
  3. 启用 启用 Studio 访问 API 服务 切换。
  4. 点击 保存

访问数据存储

要在游戏中访问数据存储:

  1. DataStoreService 添加到服务器端的 Script
  2. 使用 GetDataStore() 函数并指定您想要使用的数据存储的名称。如果数据存储不存在,则在您第一次保存游戏数据时,Studio 会创建一个。

local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")

创建数据

数据存储本质上是一个字典,类似于 Luau 表。每个值在数据存储中都有一个唯一的 ,例如用户的唯一 Player.UserId 或游戏促销的命名字符串。

用户数据键
3125060850
35167597920
50530609278000
促销数据键
ActiveSpecialEventSummerParty2
ActivePromoCodeBONUS123
CanAccessPartyPlacetrue

要创建新条目,请调用 SetAsync(),并提供键名和一个值。


local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, errorMessage = pcall(function()
gameStore:SetAsync("User_1234", 50)
end)
if not success then
print(errorMessage)
end

更新数据

要更改数据存储中的任何存储值,请调用 UpdateAsync(),并传递条目的键名和一个回调函数,定义您要如何更新条目。该回调函数接收当前值并根据您定义的逻辑返回新值。如果回调返回 nil,则写入操作将被取消,值不会更新。


local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local function makeNameUpper(currentName)
local nameUpper = string.upper(currentName)
return nameUpper
end
local success, updatedName = pcall(function()
return nicknameStore:UpdateAsync("User_1234", makeNameUpper)
end)
if success then
print("大写名称:", updatedName)
end

设置与更新

使用设置快速更新特定键。SetAsync() 函数:

  • 如果两个服务器尝试同时设置相同的键,则可能会导致数据不一致
  • 仅计入写入限制

使用更新处理多服务器尝试。UpdateAsync() 函数:

  • 从最后更新该键的服务器读取当前键值,然后进行任何更改
  • 在写入之前读取,因此较慢
  • 计入读取和写入限制

读取数据

要读取数据存储条目的值,请调用 GetAsync(),并提供条目的键名。


local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, currentGame = pcall(function()
return gameStore:GetAsync("User_1234")
end)
if success then
print(currentGame)
end

增量数据

要在数据存储中递增一个整数,请调用 IncrementAsync(),并提供条目的键名和一个数字,表示要多少改变该值。IncrementAsync() 是一个便利函数,让您避免调用 UpdateAsync() 并手动增加整数。


local DataStoreService = game:GetService("DataStoreService")
local gameStore = DataStoreService:GetDataStore("PlayerGame")
local success, newGame = pcall(function()
return gameStore:IncrementAsync("Player_1234", 1)
end)
if success then
print(newGame)
end

删除数据

要删除条目并返回与键相关联的值,请调用 RemoveAsync()


local DataStoreService = game:GetService("DataStoreService")
local nicknameStore = DataStoreService:GetDataStore("Nicknames")
local success, removedValue = pcall(function()
return nicknameStore:RemoveAsync("User_1234")
end)
if success then
print(removedValue)
end

元数据

与键相关联的元数据有两种类型:

  • 服务定义的:默认只读元数据,例如最近的更新时间和创建时间。每个对象都有服务定义的元数据。
  • 用户定义的:用于标记和分类的自定义元数据。使用 DataStoreSetOptions 对象和 SetMetadata() 函数定义。

要管理元数据,请扩展 SetAsync()UpdateAsync()GetAsync()IncrementAsync()RemoveAsync() 函数。

  • SetAsync() 接受可选的第三和第四个参数:

    • UserIds 的表。这可以帮助内容版权和知识产权的跟踪和移除。

    • DataStoreSetOptions 对象,在其中您可以使用 SetMetadata() 函数定义自定义元数据。


      local DataStoreService = game:GetService("DataStoreService")
      local gameStore = DataStoreService:GetDataStore("PlayerGame")
      local setOptions = Instance.new("DataStoreSetOptions")
      setOptions:SetMetadata({["GameElement"] = "Fire"})
      local success, errorMessage = pcall(function()
      gameStore:SetAsync("User_1234", 50, {1234}, setOptions)
      end)
      if not success then
      print(errorMessage)
      end
  • GetAsync()IncrementAsync()RemoveAsync()DataStoreKeyInfo 对象中返回第二个值。这个第二个值包含服务定义的属性和获取用户定义元数据的函数。


    local DataStoreService = game:GetService("DataStoreService")
    local gameStore = DataStoreService:GetDataStore("PlayerGame")
    local success, currentGame, keyInfo = pcall(function()
    return gameStore:GetAsync("User_1234")
    end)
    if success then
    print(currentGame)
    print(keyInfo.Version)
    print(keyInfo.CreatedTime)
    print(keyInfo.UpdatedTime)
    print(keyInfo:GetUserIds())
    print(keyInfo:GetMetadata())
    end
  • UpdateAsync() 的回调函数在 DataStoreKeyInfo 对象中接受一个额外参数,描述当前键的状态。它返回修改后的值、与 UserIds 相关的键及键的元数据。


    local DataStoreService = game:GetService("DataStoreService")
    local nicknameStore = DataStoreService:GetDataStore("Nicknames")
    local function makeNameUpper(currentName, keyInfo)
    local nameUpper = string.upper(currentName)
    local userIDs = keyInfo:GetUserIds()
    local metadata = keyInfo:GetMetadata()
    return nameUpper, userIDs, metadata
    end
    local success, updatedName, keyInfo = pcall(function()
    return nicknameStore:UpdateAsync("User_1234", makeNameUpper)
    end)
    if success then
    print(updatedName)
    print(keyInfo.Version)
    print(keyInfo.CreatedTime)
    print(keyInfo.UpdatedTime)
    print(keyInfo:GetUserIds())
    print(keyInfo:GetMetadata())
    end

有关定义元数据时的限制,请参见 元数据限制

有序数据存储

默认情况下,数据存储不会对其内容进行排序。如果您需要以有序的方式获取数据,例如在持久排行榜统计中,请调用 GetOrderedDataStore(),而不是 GetDataStore()


local DataStoreService = game:GetService("DataStoreService")
local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")

有序数据存储支持与默认数据存储相同的基本功能,以及独特的 GetSortedAsync() 函数。该函数可根据特定的排序顺序、页面大小以及最小/最大值检索 多个排序的键

以下示例将角色数据按降序排序成每页三个条目的页面,然后遍历这些页面并输出每个角色的名称和年龄。


local DataStoreService = game:GetService("DataStoreService")
local characterAgeStore = DataStoreService:GetOrderedDataStore("CharacterAges")
-- 填充有序数据存储
local characters = {
Mars = 19,
Janus = 20,
Diana = 18,
Venus = 25,
Neptune = 62
}
for char, age in characters do
local success, errorMessage = pcall(function()
characterAgeStore:SetAsync(char, age)
end)
if not success then
print(errorMessage)
end
end
-- 将数据按降序排序,分成每页三个条目
local success, pages = pcall(function()
return characterAgeStore:GetSortedAsync(false, 3)
end)
if success then
while true do
-- 获取当前(第一)页
local entries = pages:GetCurrentPage()
-- 遍历页面上的所有键值对
for _, entry in entries do
print(entry.key .. " : " .. tostring(entry.value))
end
-- 检查是否已达到最后一页
if pages.IsFinished then
break
else
print("----------")
-- 进入下一页
pages:AdvanceToNextPageAsync()
end
end
end
©2026 Roblox Corporation、Roblox、Roblox 标志及 Powering Imagination 是我们在美国及其他国家或地区的注册与未注册商标。