在 Postgresql 中打开和关闭连接的最佳时机是啥时候?

Posted

技术标签:

【中文标题】在 Postgresql 中打开和关闭连接的最佳时机是啥时候?【英文标题】:When is the best moment to open and close the connection in Postgresql?在 Postgresql 中打开和关闭连接的最佳时机是什么时候? 【发布时间】:2022-01-20 12:41:33 【问题描述】:

我正在尝试从一个数组在数据库中进行多次插入,但是...我在断开与数据库的连接和断开连接时遇到问题

例如,在这段代码中,我只插入了第一个元素,然后我得到了一个错误,因为对数据库的访问已经断开。

async function saveData(destinations)
    let ddbb = new PostgresqlDDBB();
    ddbb.connect();
    await destinations.forEach(async (country, index) => 
        let params = [country.countryName, country.countryCode, country.urlProperties];
        let id = await ddbb.insertData(2, params);
        destinations[index].id = id;
    );
    ddbb.disconnect()

对象 PostgresqlDDBB 有这样的代码:

import Result from "../../com/result";
import clientPG from "./pg_connection";
import selectQuery from "../queries/pg_queries";

class PostgresqlDDBB
    constructor()
        this.query = null;
    

    set query(id)
        this.__query = selectQuery(id);
    

    get query()
        return this.__query;
    

    async connect()
        await clientPG.connect();
    

    disconnect()
        clientPG.end();
    
    
    /**
     * 
     * @param * id_query ID of query to run
     * @param * params params to pass to the query
     * @returns The last id save in the database
     */
    async insertData(id_query, params)
        let result;

        try
            let query = selectQuery(id_query);
            if (params !== null)
                result = await clientPG.query(query, params);
            else
                result = await clientPG.query(query);
            return result.rows[0].id;
        catch(err)
            console.log(err.stack);
        
    


module.exports.PostgresqlDDBB = PostgresqlDDBB;

Postgress 的客户端有这样的代码:

import Client from "pg";
import config from "../../config";


    const clientPG = new Client(
        user: config.db_postgres.user,
        password: config.db_postgres.password,
        database: config.db_postgres.name,
        host: config.db_postgres.host,
        //ssl: config.db_postgres.ssl    
    );
    
    module.exports.clientPG = clientPG;

找saveData的代码我不知道为什么forEach不等待完成所有元素的插入。

如果我用 for 代替 forEach 做同样的事情并调用该函数两次:

async function saveData(destinations)
    let ddbb = new PostgresqlDDBB();
    await ddbb.connect();
    for(let i = 0; i < destinations.length; i++)
        let country = destinations[i];
        let params = [country.countryName, country.countryCode, country.urlProperties];
        let id = await ddbb.insertData(2, params);
    
    ddbb.disconnect();
    console.log("Voy a salir!!!");
;

saveData(list);
saveData(list);

第一次运行正常,但第二次出现此错误:

Voy a salir!!!

/home/josecarlos/Workspace/BlueCode/Youmalou/mapping-service/node_modules/pg/lib/client.js:94
      const err = new Error('Client has already been connected. You cannot reuse a client.')
                  ^

Error: Client has already been connected. You cannot reuse a client.

我们第二次运行该函数时,连接仍然打开。这怎么可能?

打开连接的最佳时机是什么时候?打开连接而不是关闭它是一个很好的做法,因为当对象也会被删除时,连接也会被删除?

如何打开、插入数据、关闭连接、再次打开连接、插入数据、关闭连接等?

我做错了吗?

编辑我:

如果我修改我的代码以使等待连接/断开连接。我第二次尝试运行 saveData 方法时遇到此错误。

      const err = new Error('Client has already been connected. You cannot reuse a client.')
                  ^

Error: Client has already been connected. You cannot reuse a client.

方法的代码是:

async function saveGIATAData(countries)
    let ddbb = new PostgresqlDDBB();
    await ddbb.connect();
    for(let i = 0; i < countries.length; i++)
        let country = countries[i];
        let params = [country.countryName, country.countryCode, country.urlProperties];
        let id = await ddbb.insertData(2, params);
    
    await ddbb.disconnect();
    console.log("Voy a salir!!!");

对象PostgresqlDDBB的代码是:

import Result from "../../com/result";
import clientPG from "./pg_connection";
import selectQuery from "../queries/pg_queries";

class PostgresqlDDBB
    constructor()
        this.query = null;
    

    set query(id)
        this.__query = selectQuery(id);
    

    get query()
        return this.__query;
    

    async connect()
        await clientPG.connect();
    

    async disconnect()
        await clientPG.end();
    
    
    /**
     * 
     * @param * id_query ID of query to run
     * @param * params params to pass to the query
     * @returns The last id save in the database
     */
    async insertData(id_query, params)
        let result;

        try
            let query = selectQuery(id_query);
            if (params !== null)
                result = await clientPG.query(query, params);
            else
                result = await clientPG.query(query);
            return result.rows[0].id;
        catch(err)
            console.log(err.stack);
        
    


module.exports.PostgresqlDDBB = PostgresqlDDBB;

而客户端的代码是:

import Client from "pg";
import config from "../../config";

const clientPG = new Client(
    user: config.db_postgres.user,
    password: config.db_postgres.password,
    database: config.db_postgres.name,
    host: config.db_postgres.host,
    //ssl: config.db_postgres.ssl    
);

module.exports.clientPG = clientPG;

而且,就像我之前所说的,我第二次尝试运行该方法时出现错误,告诉我客户端已经打开。

发生了什么?我不明白发生了什么。

【问题讨论】:

在异步函数中,应始终等待数据库连接/断开连接。 @JGH 感谢您的赞赏帮助,但它仍然对我不起作用:(我在原帖中添加了更多信息。 您确定destinations.forEach 支持异步处理程序并返回 Promise? @Anatoly 根据我的经验,array.forEach 不支持异步处理程序。因此,我通过 for 循环进行了更改。通过使用 for,但是,使用 for 我可以插入第一次调用该方法的所有插入,但是当我尝试打开连接时第二次尝试调用该方法时,出现错误,因为尽管我之前已经关闭,但连接仍然打开。而且,这就是我不明白的。这怎么可能? @JoséCarlos 你已经确实创建了一个全局单例(在 module.exports.clientPG 中),只在该模块中创建了一个 new Client,这是个坏主意。跨度> 【参考方案1】:

错误明确指出You cannot reuse a client,这意味着您需要创建一个新的客户端实例才能在关闭前一个实例后使用它。

我建议您使用池而不是创建客户端,请参阅Pooling

总而言之,您无需在每次执行查询后关闭客户端连接。在您即将关闭应用程序之前将其关闭。

【讨论】:

以上是关于在 Postgresql 中打开和关闭连接的最佳时机是啥时候?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Java servlet 时何时打开以及何时关闭 mysql 连接?

如何自动关闭 PostgreSQL 中的空闲连接?

最佳实践:每次传输后保持 TCP/IP 连接打开还是关闭?

JSF 中 MQ 连接的生命周期 - 连接已关闭

将 OleDbConnection 刷新到 Access DB - 最佳实践

“致命:数据库系统正在关闭”,同时创建与 PostgreSQL 的连接