mysql 连接池、并发事务和@user 变量

问题描述

我想弄清楚我在应用程序中使用 MysqL 数据库的方式是否有问题。 我正在运行 nodejs、express、MysqL2,并使用连接池和多个语句查询我有多个服务器,运行不同的服务,访问同一个数据库

在每个MysqL指令集的开头,我设置了一些用户变量来检查用户凭据、最新状态等……在下面的说明中,我使用这些变量来有条件地访问一些数据,或者也做插入、修改数据。 这里涉及不同的参与者(nodejs、MysqL2 驱动程序、MysqL 规范、innoDb 引擎),我不确定哪个对以下问题有明确的答案:

  • 我的多语句查询中的所有指令都将一次性运行,还是我需要担心来自不同查询和/或服务器交错的不同指令?
  • 每个连接都维护用户变量。如果指令可以交错,我最终可能会用不同的事务来弄乱彼此的用户变量。将查询包装在 START TRANSACTION; .... COMMIT; 中会解决问题吗?

现在,我的查询的高级视图是:

const MysqL2 = require('MysqL2');
const pool = MysqL2.createPool({
    multipleStatements: 'true',// other options...
}).promise();
[rows,fields] = await pool.query(`
    // Clear variables,in case no result in found in following SELECT:
    SET @enable=NULL,@status=NULL,...;
    // Check credentials,status,others:
    SELECT blah_blah INTO @enable FROM ...
    SELECT more_blah INTO @status FROM ...
    //Do stuff based on these variables
    SELECT some_stuff FROM somewhere WHERE @enable IS NOT NULL;
    INSERT INTO someplace ... // conditioned on @status and others
`);

谢谢!

解决方法

更好的做法是获取一个连接,并在运行多个语句时保持该连接。此处的答案中有一个完整示例:node.js mysql pool beginTransaction & connection

该示例显示了对具有多个查询的事务使用连接,但对于不属于同一事务的多个语句也应该使用该连接。或者换句话说,在该连接被释放回池之前,可以在同一个连接上运行多个事务。

当一个线程持有一个连接并将其用于后续查询和/或事务时,池不会与其他线程共享它。我不是 node.js 开发人员,所以我不了解 node.js 实现的第一手资料,但这是连接池的唯一合理实现。

此外,用户变量和其他会话状态不会泄露给其他线程。当连接返回到池中时,所有会话状态都将被擦除。为了安全起见,这也是连接池实现中默认的最佳实践。您不希望您的银行路由号码存储在用户变量或临时表中,然后发现下一个用户可以读取它,因为他们偶然从池中获取了相同的连接。

PS:我从来没有发现任何需要 multipleStatements 选项的情况,而且 MySQL 的前工程总监告诉我:“多查询作为一项功能存在没有正当理由。”

>