mySQL - 表锁定与行锁定

标签 mysql database transactions insert

应用说明

我有一张表,其中存储了代表 map 上区域的 ID。每张 map 包含 1000 个区域。 领土是 map 上任意数量的相互接触的区域。用户争夺 map 不同区域的所有权。

数据库设计

目前我有一张 map 表、一张领土表和一张区域表。

tblMaps: MapID, MapName

tblTerritories: TerrID (unique game wide), MapID, OwnerID, Status, Modified

tblAreas: AreaID (1-1000), TerrID

目前 tblAreas 仅存储 map 中的占用区域 - 无论是否有人拥有它,它都不包含每张 map 1000 条记录。

当用户试图取得某些区域的所有权时,应用程序必须连接这三个表并查询该 map 中所有取得的区域。如果其中任何一个被拿走,它应该拒绝他的所有权尝试。如果所有区域都是免费的,则应创建一个新区域并将相关区域添加到 tblAreas 中。

问题

我意识到我需要一个基于交易的系统,这样两个用户就不会试图同时“拥有”该区域。现在据我所知,我必须要么锁定整个 Area 表,查询以查看这些区域是否空闲,插入一个新的领土及其区域,提交并解锁表......或者 Areas 表应该包含所有 1000每个 map 的区域和锁应该只应用于该 map 的行。

希望有更好的选择,因为据我所知。锁定表将意味着在那一秒内所有区域数据都不可访问,或者使用行锁定表充满无用的未占用区域。

最佳答案

如果您在 tblAreas.AreaID 上有一个索引,那么任何包含 WHERE tblAreas.AreaID in (...) 的事务都会锁定这些条目的索引。行本身是否存在并不重要。该锁将阻止另一个事务为这些 ID 插入任何条目。所以我认为你不需要做任何一个建议。只需查询是否所有区域都可用于您的领地,您就可以获得自动插入领地所需的锁。

这可能有点问题,因为您的区域 ID 不是游戏范围内唯一的,因此在不同 map 中具有相同 ID 的区域之间可能存在一些错误的序列化。将 mapID 添加到您的 tblAreas 表可能会有所帮助,这样您就可以创建一个 (mapID, areaID) 索引来查找,这将避免索引上的错误冲突。 (这会使您的模式非规范化,您可能出于其他原因不想这样做。)

关于mySQL - 表锁定与行锁定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1726129/

相关文章:

mysql - SQL 查询从存储的表数据生成事件

用于 MYSQL 中 NOT IN 查询的 PHP PDO

database - 值得尝试 MonetDB 吗?

python - 在sqlalchemy中使用数据库名称限定表名

java - 从 Android 应用程序进行休息调用时,注册休息服务无法正常工作

java - 如何让 Spring @Transactional 回滚所有未捕获的异常?

java - org.springframework.transaction.CannotCreateTransactionException : Could not open Hibernate Session for transaction

mysql - 如何用以前的非空值替换空值?

mysql - 高度事务性系统中的触发器

mysql - 选择不同的值并按同一列(值)排序