MySQL InnoDB引擎是否会自动排队数据库触发器?

Aak*_*ash 5 mysql triggers deadlock innodb

假设我在服务器上收到1000个请求来更新单个MySQL表.在这种情况下不可避免地会出现死锁问题.我们已经重新发布了针对死锁建议的事务,但它们仍然存在.

我们正在考虑在下面提出替代解决方案.

  1. 创建表A,B,C.
  2. 写入请求到服务器以将表D更新为A或B或C.
  3. 分别在表A,B和C上创建一个INSERT触发器,它将依次写入表D中的数据,而不是直接将表D暴露给来自服务器的1000个请求.

所以我们的问题是当这种情况发生并且多行被写入表A,B和C时,表A,B和C上的底层触发器可能同时触发以更新表D.

MySQL InnoDB引擎是否会自动对这些触发器进行排队,还是我们必须在代码中处理这个问题?

任何帮助深表感谢.

现在所有这些请求直接更新的表D以及发生死锁的位置如下所示.

v_user_email    varchar(60) NO  PRI     
v_device_IMEI   varchar(40) NO  PRI     
i_adid          int(11)         NO  PRI     
i_impressions   int(4)          YES 0   
dt_pulllogdttm  datetime    NO          
c_created_by    char(15)    NO          
dt_created_on   datetime    NO          
c_modified_by   char(15)    YES         
dt_modified_on  datetime    YES 
Run Code Online (Sandbox Code Playgroud)

在此表中插入/更新行的PHP如下所示.您将看到我们尝试将事务发布3次,如果它由于死锁而失败但是有些事务甚至失败并且由于死锁而导致日志显示.

$updateQuery = "UPDATE tb_ad_pull_log SET i_impressions = (i_impressions + 1), dt_pulllogdttm = SYSDATE(), c_modified_by = '$createdBy', dt_modified_on = SYSDATE() WHERE v_user_email = '$email' AND i_adid = $adId";
        if(ExecuteDeadLockQuery($updateQuery, "UPDATE", __LINE__) == 0) // If there is no record for this ad for the user, insert a new record
        {
            $insertQuery = "INSERT INTO tb_ad_pull_log VALUES('$email', '$device_IMEI', $adId, 1, SYSDATE(), '$createdBy', SYSDATE(), NULL, NULL)";
            ExecuteDeadLockQuery($insertQuery, "INSERT", __LINE__);
        }    
Run Code Online (Sandbox Code Playgroud)

ExecuteDeadLockQuery函数看起来像这样 -

function ExecuteDeadLockQuery($query, $activity, $lineNumber)
    {
        global $errorLoggingPath;
        $maxAttempts = 3;
        $currentTry = 1;
        $noOfAffectedRows = -1;

        while($currentTry <= $maxAttempts)
        {
            $currentTry++;

            mysql_query($query);

            if( mysql_errno() <> 0 ) // If error occured
            {
                continue;
            }
            else
            {
                $noOfAffectedRows = mysql_affected_rows();
                break;
            }           
        }

        if($noOfAffectedRows == -1) // Query never executed successfully
        {
            LogError($activity . " failed in tb_ad_pull_log: " . mysql_error(), __FILE__, $lineNumber , $errorLoggingPath);
        }

        return $noOfAffectedRows;
    }
Run Code Online (Sandbox Code Playgroud)

有没有更清洁的方法来避免这种僵局?这是我们的一些日志.

ERROR:  08-21-2011 14:09:57  UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  83
ERROR:  08-21-2011 14:09:57  INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  86
ERROR:  08-21-2011 14:09:57  INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  86
ERROR:  08-21-2011 14:09:57  UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction   LINE  83
ERROR:  08-21-2011 14:09:57  INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  86
ERROR:  08-21-2011 14:09:57  UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  83
ERROR:  08-21-2011 14:09:59  UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  83
ERROR:  08-21-2011 14:09:59  UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  83
ERROR:  08-21-2011 14:10:01  UPDATE failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  83
ERROR:  08-21-2011 14:10:01  INSERT failed in tb_ad_pull_log: Deadlock found when trying to get lock; try restarting transaction    LINE  86
Run Code Online (Sandbox Code Playgroud)

第83行是PHP中的UPDATE语句,86是INSERT.请记住,这些数据可以每秒5-8个事务的速率写入此表.

附加信息

对表D中的每个INSERT和UPDATE执行一个更新TABLE X和TABLE Y的触发器.这是表D保持锁定的原因,因此传入的请求会出现死锁吗?

终于得到了问题,但我不知道如何解决它.表D上的AFTER INSERT和AFTER UPDATE触发器在触发表时会锁定表,因此传入的请求会死锁.为什么我这么肯定是因为一旦我删除了这些触发器,日志就会停止记录死锁消息

触发器代码的片段.

    CREATE DEFINER=CURRENT_USER TRIGGER tuadmin.t_update_CPM_updateBalance
AFTER UPDATE
ON tb_ad_pull_log
FOR EACH ROW
BEGIN

    DECLARE `cpm_value` decimal(10,4);
    DECLARE `clientid` int(4);

    /* Execute the below block if the requested ad is not the default ad */
    IF NEW.i_adid <> 1 THEN

        SET SESSION TRANSACTION ISOLATION LEVEL READ COMMITTED;
            //do updates to TABLE X and Y logic
END
Run Code Online (Sandbox Code Playgroud)

这是我不明白为什么这些触发器会锁定表D并且不允许任何插入/更新同时发生的地方.

如果我们删除触发器并从PHP调用SP来完成工作,这会避免所有问题吗?

ruh*_*lde 0

在这种情况下,MYSQL DBA 使用的是一种称为“复制”的功能,即根据需要将单个服务器划分为多个服务器以平衡负载。您可以使用单个强大的硬件来实现这一点,该硬件分为 2 个或更多虚拟服务器,在具有 VirtualBox、VirtualPC 或您的虚拟化风格的虚拟设备内运行,并启用 MYSQL 复制功能。

您可以调整单个服务器以进行写入(在本例中为更新),并调整其他服务器以进行读取数据的查询。请参阅此处MYSQL 复制文档