NodeJS 节点+ PostgreSQL -这是执行事务的有效方式吗?

u7up0aaq  于 2023-03-01  发布在  Node.js
关注(0)|答案(1)|浏览(170)

我在Nodejs上构建了一个使用node_postgres的API。
该网站称:...if you initialize or use transactions with the pool.query method you will have problems.
我在不需要事务的地方使用pool.query。但是我创建了一个客户端,并且在每次需要事务的时候释放它。我想知道这是否是执行事务的有效方法,以及释放客户端而不是结束它是否足够,这样我就不会以并发或泄漏之类的事情结束。
他们推荐的执行事务的方法是:

const client = await pool.connect()
 
try {
  await client.query('BEGIN')
  const queryText = 'INSERT INTO users(name) VALUES($1) RETURNING id'
  const res = await client.query(queryText, ['brianc'])
 
  const insertPhotoText = 'INSERT INTO photos(user_id, photo_url) VALUES ($1, $2)'
  const insertPhotoValues = [res.rows[0].id, 's3.bucket.foo']
  await client.query(insertPhotoText, insertPhotoValues)
  await client.query('COMMIT')
} catch (e) {
  await client.query('ROLLBACK')
  throw e
} finally {
  client.release()
}

因此,我创建了一个导出池的文件:

const { Pool } = require('pg')
require('dotenv').config()

const isProduction = process.env.NODE_ENV === 'production'

if(process.env.NODE_ENV === 'development') {
    databaseName = 'dev_db'
} else if(process.env.NODE_ENV === 'production'){
    databaseName = 'prod_db'
} 

const connectionString = `postgresql://${process.env.DB_USER}:${process.env.DB_PASSWORD}@${process.env.DB_HOST}/${databaseName}`
const connectionStringProd = `postgresql://${process.env.DB_USER_PROD}:${process.env.DB_PASSWORD_PROD}@${process.env.DB_HOST_PROD}/${process.env.DB_NAME_PROD}`

const pool = new Pool({
    connectionString: isProduction ? connectionStringProd : connectionString
})

module.exports = pool

然后,当我不需要事务时,我用途:

app.get('/api/users', async (req, res) => {
    try {
        const users = await pool.query('SELECT * FROM users')
        return res.status(201).send({users: users.rows})
    } catch (error) {
        return res.status(500).send({status: 500, error: error})
    }
})

当我需要交易时:

app.post('/api/test', async (req, res) => {
    const client = await pool.connect()
    try {           
        await client.query('BEGIN')
        const {some_value, another_value} = req.body                     

        await client.query('INSERT INTO some_table(some_value) VALUES ($1)', [some_value])
        await client.query('INSERT INTO some_other_table (another_value) VALUES ($1)', [another_value])
       
        await client.query('COMMIT')
        return res.status(201).send('ok')

    } catch (error) {
        await client.query('ROLLBACK')
        return res.status(500).send({status: 500, error: error})
    } finally {
        client.release()
    }
})

因为每次我需要事务时,我都会调用const client = await pool.connect(),并以client.release()结束,所以我不确定我是否正确地管理了客户端。
这是一个有效的方法吗?谢谢

dwbf0jvd

dwbf0jvd1#

是的,每次您需要事务时,您需要使用pool.connect从池中锁定1个连接(),然后使用client.release将其释放().背后的想法是事务应该用相同的数据库连接来完成。当你通常使用池时,它会给你池中可用的空闲连接中的一个,并且每个查询都用不同的连接来执行。这就是为什么你不在单独的查询情况下锁定连接。2释放也是非常重要的。3如果你从连接池中保留了一个连接,即使在事务完成后,它仍然会被保留。因为您手动请求了连接。这样您将阻止池中的所有连接,并且数据库将被阻塞。当您从池中执行正常查询时,它会自动为您释放连接。

相关问题