Ann*_*hko 3 mysql database-replication node.js
我有一个node.js Express项目,它使用MySQL 5.6数据库和mysql客户端连接到它。项目中没有 ORM,原始查询针对数据库运行。现在,我需要更改代码,将SELECT查询(不在事务内)路由到 MySQL 只读副本。由于我以前从未在任何其他项目上做过类似的事情,所以我想知道这样做的最佳实践是什么(在 Node.js 中)。
我发现该sequelize库具有允许单独指定读取和写入副本的配置选项,然后不同的查询将被路由到不同的数据库,但我没有在客户端库中找到任何执行此操作的选项mysql。我尝试使用sequelize,但似乎对于 RAW 查询不支持此功能。
除此之外,我想知道从架构的角度来看最好的解决方案是什么?目前,我看到的唯一选择是拥有一些具有query方法的数据库包装服务,该服务反过来封装mysql connection.query并根据提供给它的 sql 决定使用哪个数据库连接 - 读取或写入(除非它是事务 - 然后我想一切都应该在同一个数据库中完成)。这是一个相当愚蠢的解决方案,但这是我现在唯一的想法。
有人可以分享一些这方面的经验吗?不仅在 Node.js 项目中 - 欢迎任何架构想法。也许有某种方法可以在请求到达主机之前对其进行代理?感谢您提前的任何答复。
因此,最终,我以一种相当简单的方式解决了这个问题:为读取和写入数据库副本创建单独的连接池,并在我需要的地方直接使用它们:
const writePool = mysql.createPool(writeConnectionString);
const readPool = mysql.createPool(readConnectionString);
function getWriteConnection() {
return writePool.getConnection();
};
async function getReadConnection() {
const connection = await readPool.getConnection();
connection.isRead = true;
const originalQuery = connection.query;
connection.query = function (...args) {
if(!isSelectQuery(args[0])) {
throw new Error('Read connection cannot be used for the commands other than SELECT.');
}
return originalQuery.apply(this, args);
};
return connection;
};
// checking if query is SELECT
function isSelectQuery(query) {
return query.replace(/\s+/mi, '').toLowerCase().startsWith('select');
}
// release function
function release(connection) {
if(connection.isRead) {
readPool.releaseConnection(connection)
} else {
writePool.releaseConnection(connection);
}
};
Run Code Online (Sandbox Code Playgroud)
然后在代码中:
const connection = await database.getReadConnection();
await connection.query('SELECT * FROM ...');
....
database.release(connection);
Run Code Online (Sandbox Code Playgroud)
这远不是解决问题的最优雅的方法,但它相对较快地以最小的更改和随后的错误解决了我的问题。
| 归档时间: |
|
| 查看次数: |
2568 次 |
| 最近记录: |