2017-09-24 118 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; 
\$\$`; 
} 
相關問題