【问题标题】:How to lock a single row如何锁定单行
【发布时间】:2011-04-22 04:13:55
【问题描述】:

我有一个user 表,字段为lastusedecnumber

我需要访问并增加lastusedecnumber

在访问期间,我需要锁定特定的用户行(而不是整个表)。

我该怎么做?

表格类型为MyISAM

【问题讨论】:

标签: mysql locking myisam


【解决方案1】:

我不想从 myisam 转换我的整个数据库。所以我只是尝试创建一个基于我要锁定的记录的 id 命名的新表。如果创建表成功,做我的工作并在最后删除表。建表不成功,停止。

【讨论】:

    【解决方案2】:

    MySQL 仅使用来自 MyISAM 表的表级锁定。如果可以,请切换到 InnoDB 进行行级锁定。

    这里是 MySQL 站点的链接,该站点描述了由 SQL 语句为 InnoDB 表设置的锁。 http://dev.mysql.com/doc/refman/5.0/en/innodb-locks-set.html

    【讨论】:

    • 这个锁是只对那个事务有效还是对整个数据库永久有效?
    • 有时用于事务,有时用于全局。在使用它之前,您应该仔细阅读并理解锁定。例如,有不同类型的锁,如“全局读锁”。有时锁会在提交时自动释放,其他锁可能会在事务开始时释放。您的要求应该规定您应该使用哪种类型的锁定以及如何使用它。
    【解决方案3】:

    有点晚了,但希望对某人有所帮助:

    UPDATE user SET lastusedecnumber = LAST_INSERT_ID(lastusedecnumber + 1);
    SELECT LAST_INSERT_ID();
    

    将为您提供 lastusedecnumber 的原子增量,并能够使用 SELECT LAST_INSERT_ID() 读取 lastusedecnumber 字段的新值(增量后)。

    【讨论】:

    • 这是一个很好的建议,因为它允许您更新行并读取值(尽管当前写入它读取更新后的值,而不是旧值)。它没有提到的是,由于它是对表的写入,它会在更新行的同时锁定整个表,这就是 MyISAM 所做的 - 这是无法避免的。
    【解决方案4】:

    更好的解决方法是创建一个包含时间戳的列。每当您想锁定行时,您都会将其更新为当前时间。将更新解锁到过去至少 x 分钟的时间。然后检查它是否被锁定,检查时间戳是否至少 x 分钟。

    这样,如果进程崩溃(或用户从未完成他们的操作),锁会在 x 分钟后有效地过期。

    【讨论】:

    • 不好 - 因为检查和更新不是一个单一的操作,这允许两个连接在不知道彼此的情况下锁定同一行。 (可能有一种方法可以做到这一点,但它会很复杂而且很容易搞砸。)
    • 永远不要使用计时来代替锁定。
    【解决方案5】:

    作为一种解决方法,您可以在表中添加一列,例如 locked TINYINT(1) - 每当您想要锁定该行时,您将其设置为 1。当您现在尝试访问此行时,您要做的第一件事是检查是否设置了 locked 字段。

    要解锁该行,只需再次将其设置为0。不好,但一个非常简单的解决方法。

    【讨论】:

    • 如果连接被关闭,比如关闭浏览器等。如果它自动为其他人解锁?我认为它不会这样做。我说得对吗?
    • 不,当然不会。您可以提供一种作业,定期检查触发行锁的用户是否有打开的会话。当然,您必须在表格中添加一些用户信息。
    • 但这就像一个不能消除竞争条件的坏信号量。如果 2 个并发查询认为 LOCK=0,那么它们都进入了临界区,both 都设置了 LOCK=1,并且您有一个隐藏的竞争条件错误。
    • 在 MySQL 内部更新和写入锁。一次只有一个实际写入,因此如果您的 UPDATE 有一个用于 lock=0 的 where 子句,则不应创建竞争条件。
    • @JRL 这不是真的。我经历过。
    猜你喜欢
    • 1970-01-01
    • 2016-04-18
    • 2012-02-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多