【问题标题】:Laravel 4 exclusive transaction with update and selectLaravel 4 独家事务更新和选择
【发布时间】:2013-06-15 08:56:20
【问题描述】:

我需要从设置为空闲的 SQLite 数据库中选择一行,然后将该行标记为已占用。至关重要的是,选择和更新是原子操作,并且不会有两个用户将同一行免费返回的风险。

不幸的是,Laravel 在调用 DB::transaction 时似乎没有提供事务类型的选择,如果我将它作为 DB::statement 运行,那么我将不会获得返回值。

另外,由于 SQLite 不支持变量,我无法在选择和更新之间存储主键,所以我不确定是否可以从 SQLite 数据库中运行它。

是否可以使用 Laravel 和 SQLite?

如果没有,那么我需要将下一个空闲 ID 存储在与 SQLite 数据库相关的 MySQL 表中,并在该行上使用锁定。在 MySQL 中按行锁定有什么主要的语法差异吗? (我不能不小心锁定整个表)

我正在查看类似于以下的语法:(当然 SQLite 不支持变量除外)

BEGIN EXCLUSIVE TRANSACTION
  SET @free = SELECT InternalID FROM main WHERE Called = 0 LIMIT 1;
  UPDATE main SET Called = 1 WHERE InternalID = @free;
  SELECT * FROM main LEFT JOIN lead ON main.InternalID = lead.InternalID WHERE main.InternalID = @free;
END TRANSACTION

因为我确定有人会问“你为什么使用两个数据库系统!?!”:

SQLite 数据库包含需要灵活列数的数据。这些数据将每周使用几天,持续几个月,然后可以存档。需要有相当多的这些“小型数据库”。这些数据无法有效地存储在 MySQL 中(我要替换的以前的系统尝试过这个,它变得非常慢)。每个 SQLite db 的并发性会非常低,但绝对不可能有两个用户获得相同的行,这一点至关重要 - 在旧系统中已经发生过几次。

【问题讨论】:

    标签: mysql sql sqlite transactions laravel


    【解决方案1】:

    我会忘记尝试锁定表和/或在事务中执行此操作,对此有更好的模式:

    • 生成唯一令牌
    • 将该令牌分配给下一条可用记录
    • 读取哪一行得到了令牌,并处理它

    这样你根本不需要锁定和事务(因为数据库只会将你的令牌分配给一个未使用的记录)。

    伪代码:

    $token = time(); //Only you have very low concurrency. Otherwise use something more unique, like a GUID or an identity value from a tokens table.
    
    EXEC SQL: "UPDATE mytable SET token = $token WHERE token IS NULL LIMIT 1"
    
    EXEC SQL: "SELECT id FROM mytable WHERE token = $token"
    
    process($id);
    

    【讨论】:

    • 谢谢!我还可以使用用户的帐户 ID 作为我的令牌,因为每个用户一次只使用一行。
    • SQLite 在更新中不支持LIMIT,所以我不得不使用UPDATE main SET CallerToken = ? WHERE InternalID IN (SELECT InternalID FROM main WHERE CallState = 0 AND CallerToken IS NULL LIMIT 1)
    • 非常感谢这个帖子。您首先将所需记录标记为更新锁定,然后使用选择查询它们的模式 - 非常聪明! :-) 这让我很烦恼,我自己没有想到这个想法,哈哈......无论如何,这真的帮助了我解决一个相关的问题!谢谢!
    猜你喜欢
    • 2017-02-22
    • 1970-01-01
    • 2013-07-30
    • 1970-01-01
    • 2014-12-22
    • 1970-01-01
    • 2017-12-27
    • 2013-01-28
    • 2014-09-07
    相关资源
    最近更新 更多