2017-09-24 113 views
0

我有一个节点js服务器正在运行并配置为自动缩放。此服务器正在访问我想要版本的AWS上的postgresql数据库。这里的目标是允许我推送代码中的服务器更新,以便根据需要更改表。到目前为止我所做的是创建一个BaseDatabase类,它在服务器启动时连接到数据库(在我启动express js应用程序之前,因此没有网络流量)。同步节点js服务器上的postgresql数据库访问

一旦连接到数据库,我检查使用(以打字稿)的当前版本:

let transactionComplete = false; 
try { 
    await client.query("BEGIN"); 
    let currentVersion = await client.query("SELECT current_setting('info.version')::int"); 
    if (currentVersion < version) { 
    try { 
     await upgradeDatabase(client, currentVersion, version); 
    } catch (e) { 
     // Handle error 
    } 
    } 
    await client.query(`SELECT set_config('info.version', ${version}, false)`); 
    transactionComplete = true; 
} catch (e) { 
    try { 
    await createDatabase(client); 
    transactionComplete = true; 
    } catch (e) { 
    // Handle error 
    } 
} finally { 
    if (transactionComplete) { 
    await client.query('COMMIT'); 
    } else { 
    await client.query('ROLLBACK'); 
    } 
    client.release(); 
} 

我所有的测试工作的,我可以在不同的端口上运行我的服务器的多个实例,我能够创建/更新我的数据库只有一次。我担心我只是幸运。我有一种感觉,即使这是一笔交易,但我认为,它的前提条件是第一个SELECT,它在最后的COMMIT之前解决。看起来像这样做的正确方法是在我的查询中使用条件并一起执行所有操作。我已经能够创造这样:

DO $$ 
BEGIN 
IF (SELECT current_setting('info.version')::int) < ${version} THEN 
    RAISE NOTICE 'database requires update'; 
END IF; 
END; 
$$; 

以上的作品,我相信就完全是原子的,如果我能得到的,如果在我的升级语句。问题是,我不知道我需要哪些陈述,直到我查询info.version。无论如何,当我做这些查询时锁定整个数据库?或者,也许同步所有我的节点js服务器实例?或者我还没有想到的其他东西?

这里的最终目标是我可以在代码中放入对数据库的任何更改,并且当我推送新的服务器版本时,它们将被执行一次。然后,我可以在进行数据库更改之前对我的团队进行代码审查等,并且可以在本地复制我的prod环境。

+0

张贴在怀疑与事实一个问题是戳在天空中孔。首先确定问题,然后寻找解决方案。 –

+0

我不知道我关注。问题是我希望能够对我的数据库进行版本化并使用JavaScript对其进行修改。我担心的是,我所拥有的并不能保持同步。我的问题是,如何以安全的方式执行相同的操作。 – TheHebrewHammer

回答

0

我发现,似乎是工作的解决方案:

// This is actually a bit more complex to allow for the first instance when 
// info.version is not yet defined. 
let currentVersion: number = await client.query(
    "SELECT current_setting('info.version')"); 
if (this.version === currentVersion) { 
    return; 
} 
let query: string = currentVersion === null 
    ? await this.onCreate(client) 
    : await this.onUpgrade(client currentVersion, this.version); 
query = this.getSqlStatment(currentVersion, this.version, query); 
try { 
    await client.query(query); 
} catch (e) { 
} finally { 
    client.release(); 
} 

private getSqlStatement(fromVersion: number, toVersion: number, query: string): string { 
    return `DO \$\$ 
DECLARE version integer; 
BEGIN 
version := current_setting('info.version')::integer; 
EXCEPTION 
    WHEN SQLSTATE '42704' THEN version := NULL; 
IF version ${fromVersion ? `= ${fromVersion} : "IS NULL"} THEN 
    ${query} 
    PERFORM set_config('info.version', '${toVersion}', false); 
END IF; 
END; 
\$\$`; 
} 
相关问题