我在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()
结束,所以我不确定我是否正确地管理了客户端。
这是一个有效的方法吗?谢谢
1条答案
按热度按时间dwbf0jvd1#
是的,每次您需要事务时,您需要使用pool.connect从池中锁定1个连接(),然后使用client.release将其释放().背后的想法是事务应该用相同的数据库连接来完成。当你通常使用池时,它会给你池中可用的空闲连接中的一个,并且每个查询都用不同的连接来执行。这就是为什么你不在单独的查询情况下锁定连接。2释放也是非常重要的。3如果你从连接池中保留了一个连接,即使在事务完成后,它仍然会被保留。因为您手动请求了连接。这样您将阻止池中的所有连接,并且数据库将被阻塞。当您从池中执行正常查询时,它会自动为您释放连接。