触发器不尊重自动提交选项?

时间:2015-09-18 11:54:52

标签: mysql triggers innodb mysql-5.6

MySQL触发器主体不尊重AUTOCOMMIT选项并始终在事务中运行?

真实世界场景

我只有AFTER UPDATE触发器设置一些计数器(例如标志更改将减少旧标志的计数器并增加新标志)并且有两个服务器具有相对较高的负载变化标志所有时间......有时它会陷入僵局:)

测试设置

我已经设置了这两个表:

test (
    id INT NOT NULL AUTO_INCREMENT,
    data TEXT DEFAULT NULL,
    PRIMARY KEY (id)
)

test2 (
    id INT NOT NULL AUTO_INCREMENT,
    val INT DEFAULT 0,
    PRIMARY KEY (id)
)

插入一些虚拟数据:

INSERT INTO test (data) VALUES (RAND());
INSERT INTO test2 (id, val) VALUES
    (1, 0),
    (2, 0);

创建模拟数据计算的触发器(故意让我有时间运行第二次查询)并对test2表中的数据进行虚拟更改:

DELIMITER $$
CREATE TRIGGER `test_AUPD` AFTER UPDATE ON `test` FOR EACH ROW
BEGIN
    UPDATE test2
    SET val = val + 1
    WHERE id = 1;

    SELECT SLEEP(30) INTO @void;

    UPDATE test2
    SET val = val - 1
    WHERE id = 2;

END $$

当然:

SHOW VARIABLES LIKE 'autocommit';
-- autocommit, ON

测试结果

我打电话的时候:

UPDATE test SET data = RAND();

在两个连接中,第一次连接需要30秒才能完成更新,但第二次连接需要大约55秒

问题

  • 这种行为记录在哪里(我花了几个小时挖掘InnoDB事务锁等等,但没有运气)? 我想这是打开复制时的合理行为。

  • 同步触发更新同一个表中的计数器的正确方法是什么? OR 如何处理这种情况?

1 个答案:

答案 0 :(得分:0)

调试此方法的好方法似乎是从INFORMATION_SCHEMA选择锁和交易信息:

SELECT 
    PS.id AS conneciton_id, PS.HOST AS host, PS.INFO AS query_full, INNOLOCK.lock_id,
    INNOLOCK.lock_mode, INNOLOCK.lock_type, INNOLOCK.lock_table, INNOLOCK.lock_rec, 
    INNOTRX.trx_query, INNOTRX.trx_state, INNOTRX.trx_requested_lock_id
FROM INFORMATION_SCHEMA.INNODB_LOCKS AS INNOLOCK
INNER JOIN INFORMATION_SCHEMA.INNODB_TRX AS INNOTRX 
    ON INNOLOCK.lock_trx_id = INNOTRX.trx_id
INNER JOIN INFORMATION_SCHEMA.PROCESSLIST AS PS ON PS.ID = INNOTRX.trx_mysql_thread_id;

这将获取这样的数据:

+-----------------------++-------------------------------+-----------------------------+
| connection_id         || *****                         | *****                       |
| host                  || *****:*****                   | *****:*****                 |
| query_full            || UPDATE test SET data = RAND() | SELECT SLEEP(30) INTO @void |
| lock_id               || 1234567890:12345678:2:3       | 0124567890:01234567:1:2     |
| lock_mode             || X                             | X                           |
| lock_type             || RECORD                        | RECORD                      |
| lock_table            || `test`                        | `test`                      |
| lock_rec              || 2                             | 2                           |
| trx_query             || UPDATE test SET data = RAND() | SELECT SLEEP(30) INTO @void |
| trx_state             || LOCK WAIT                     | RUNNING                     |
| trx_requested_lock_id || 0124567890:01234567:1:2       |                             |
+-----------------------++-------------------------------+-----------------------------+

立即告诉您第一列中显示的查询正在等待锁0124567890:01234567:1:2,而0124567890:01234567:1:2中的锁定SELECT SLEEP(30)的交易现在正在等待<asp:Panel ID="SearchPanel" runat="server"> <%--put all the controls here--%> </asp:Panel>