实现思路
- 连接数据库:使用
pg
库连接到PostgreSQL数据库。
- 开启事务:在转账操作开始时,开启一个数据库事务,确保所有操作要么全部成功,要么全部失败。
- 检查账户余额:在转账前,查询转出账户的余额,确保余额足够。
- 更新账户余额:更新转出账户的余额(减少相应金额)和转入账户的余额(增加相应金额)。
- 记录交易:在
transactions
表中插入一条新的交易记录。
- 提交事务:如果所有操作都成功,提交事务;否则,回滚事务。
- 性能优化:在高并发场景下,可以考虑使用连接池管理数据库连接,减少连接创建和销毁的开销;对数据库表进行适当的索引优化,提高查询效率。
核心代码示例
const express = require('express');
const { Pool } = require('pg');
const app = express();
const pool = new Pool({
user: 'your_user',
host: 'your_host',
database: 'your_database',
password: 'your_password',
port: 5432,
});
app.post('/transfer', async (req, res) => {
const { fromAccountId, toAccountId, amount } = req.body;
let client;
try {
client = await pool.connect();
await client.query('BEGIN');
const result = await client.query('SELECT balance FROM accounts WHERE id = $1', [fromAccountId]);
if (result.rows[0].balance < amount) {
throw new Error('Insufficient balance');
}
await client.query('UPDATE accounts SET balance = balance - $1 WHERE id = $2', [amount, fromAccountId]);
await client.query('UPDATE accounts SET balance = balance + $1 WHERE id = $2', [amount, toAccountId]);
await client.query('INSERT INTO transactions (from_account_id, to_account_id, amount) VALUES ($1, $2, $3)', [fromAccountId, toAccountId, amount]);
await client.query('COMMIT');
res.status(200).send('Transfer successful');
} catch (e) {
if (client) {
await client.query('ROLLBACK');
}
res.status(500).send(`Transfer failed: ${e.message}`);
} finally {
if (client) {
client.release();
}
}
});
const port = 3000;
app.listen(port, () => {
console.log(`Server running on port ${port}`);
});
优化策略
- 连接池优化:使用
pg
库的连接池(Pool
),合理设置连接池的最大连接数、最小连接数等参数,避免频繁创建和销毁数据库连接。
- 索引优化:在
accounts
表的id
字段和balance
字段,以及transactions
表的from_account_id
、to_account_id
字段上创建索引,加快查询速度。
CREATE INDEX idx_accounts_id ON accounts (id);
CREATE INDEX idx_accounts_balance ON accounts (balance);
CREATE INDEX idx_transactions_from_account_id ON transactions (from_account_id);
CREATE INDEX idx_transactions_to_account_id ON transactions (to_account_id);
- 缓存机制:可以考虑对部分账户余额等常用数据进行缓存,减少数据库查询次数。例如使用Redis作为缓存层,在转账操作前先检查缓存中的余额,只有在缓存数据过期或不一致时才查询数据库。
- 负载均衡:如果是高并发场景,可以使用负载均衡器(如Nginx)将请求均匀分配到多个服务器实例上,减轻单个服务器的压力。
- 异步处理:确保在代码中尽可能使用异步操作,避免阻塞I/O操作,提高整体性能。如在上述代码中,使用
await
处理异步数据库操作。