1

我使用带有一行的表来保留最后使用的 ID(我有理由不使用 auto_increment),我的应用程序应该在服务器场中运行,所以我想知道如何更新最后插入的 ID(即递增它)和一步选择新 ID 以避免线程安全问题(服务器场中服务器之间的竞争条件)。

4

6 回答 6

2

您要为数据库使用服务器场吗?这听起来并不“正确”。

您可能需要考虑将 GUID 用于 Id。它们可能很大,但没有重复项。

使用单个“下一个 id”值,您将遇到对该记录的锁定争用。我过去所做的是使用 id 范围表(RangeId、RangeFrom、RangeTo)。范围表的主键“RangeId”是一个简单的数字(例如 1 到 100)。“get next id”例程从 1 到 100 中选择一个随机数,获取第一个 id 低于随机数的范围记录。这会将锁分散到 N 条记录中。您可以使用 10、100 或 1000 的范围记录。当一个范围被完全消耗时,只需删除范围记录。

如果您真的在使用多个数据库,那么您可以手动确保每个数据库的范围记录集不重叠。

于 2009-02-23T08:34:55.270 回答
1

您需要确保您的 ID 列只能在锁中访问 - 然后只有一个人可以读取最高 ID 并设置新的最高 ID。

您可以在 C# 中使用访问表的代码周围的 lock 语句来执行此操作,或者在您的数据库中,您可以在读/写时将事务放在一起。我不知道 mysql 上的确切语法。

于 2009-02-23T08:29:47.777 回答
1

使用事务数据库并手动控制事务。这样您就可以提交多个查询,而不会有混淆的风险。此外,您可以将相关查询集存储在存储过程中,因此您可以简单地调用这些事务查询。

于 2009-02-23T09:12:03.653 回答
0

假设您的数据库配置为使用 READ_COMMITTED 或更好的事务隔离运行,然后使用一个更新行的 SQL 语句,将其设置为从行中选择的旧值加上增量。对于较低级别的事务隔离,您可能需要将 INSERT 与 SELECT FOR UPDATE 结合使用。

正如 [by Aaron Digulla] 所指出的,最好分配 ID 块,以减少查询和表锁的数量。

应用程序必须在独立于任何业务逻辑的事务中执行 ID 获取,否则任何需要 ID 的事务最终将等待每个首先请求 ID 的事务提交/回滚。

这篇文章:http ://www.ddj.com/architect/184415770解释了允许您的应用程序从多个分配器获取 ID 的 HIGH-LOW 策略。多个分配器提高了并发性、可靠性和可扩展性。

这里也有很长的讨论:http://www.theserverside.com/patterns/thread.tss?thread_id=4228 "HIGH/LOW Singleton+Session Bean Universal Object ID Generator"

于 2009-10-21T10:39:49.820 回答
0

如果您遇到性能问题,请将 ID 增加 100 并为每个“客户端”服务器使用一个线程。线程应该执行增量并为每个感兴趣的方提供一个新的 ID。这样,线程只需为 100 个 ID 访问一次数据库。

如果线程崩溃,您将丢失几个 ID,但如果这种情况并非一直发生,您不必担心。

于 2009-02-23T10:03:51.203 回答
0

AFAIK 将其从具有良好递增数字的数据库中取出的唯一方法将是数据库上的事务锁,这在性能方面是可怕的。您可以使用 GUID 获得无锁行为,但坦率地说,无论如何您都会在每个 CRUD 操作中遇到事务需求。

于 2009-02-23T10:11:32.090 回答