PostgreSQL读写异常:读操作先于写操作返回旧数据
问题根源:Sequelize事务使用错误 + PostgreSQL事务隔离特性
嘿,这个问题其实是代码层面的异步处理不当,再结合PostgreSQL的事务特性共同导致的,咱们一步步拆解清楚:
1. 先看你写操作代码里的核心问题
你的updateObject函数里有两处关键的异步操作没处理到位,这是导致旧数据读取的主要原因:
Object.updateObject = async function(info){ const t = await sequelize.transaction(); const currentObject = await Object.findOne(); // 这里updateAttributes是异步方法,没加await会直接返回Promise,不会等待更新完成 const updatedObject = currentObject.updateAttributes(info, t); // commit也是异步操作,没加await会在更新完成前就提交事务 t.commit(); return updatedObject; }
这会导致两个问题:
- 事务在更新操作还没执行完毕的时候就提交了,写操作可能还没真正落地到数据库
updateObject的Promise会在事务真正提交完成前就resolve,导致你在then回调里调用getObject时,数据库的更新还没生效
另外还有个小问题:你在事务内执行Object.findOne()时,没有把事务对象t传入查询参数,这个查询会在事务外部执行,拿到的对象可能和事务内的数据库视图不一致。
2. 修正后的写操作代码
给你调整后的版本,补上异步等待、事务关联和异常回滚逻辑:
Object.updateObject = async function(info){ const t = await sequelize.transaction(); try { // 将查询关联到当前事务,确保拿到的是事务内的视图数据 const currentObject = await Object.findOne({ transaction: t }); // 等待更新操作完成 const updatedObject = await currentObject.updateAttributes(info, { transaction: t }); // 等待事务提交完成,确保写操作真正落地 await t.commit(); return updatedObject; } catch (err) { // 出错时回滚事务,避免脏数据 await t.rollback(); throw err; } }
3. 再聊聊PostgreSQL的事务隔离机制
PostgreSQL默认的事务隔离级别是READ COMMITTED,这个级别下:
- 每个读查询只能看到在查询开始前已经提交的事务数据
- 写事务完全提交后,后续的读查询才能看到更新后的结果
你之前的问题本质上不是PostgreSQL的机制问题,而是代码没等写事务真正提交就发起了读请求。修正代码后,await t.commit()会确保事务提交完成后,updateObject的Promise才会resolve,这时候再调用getObject就能拿到最新的数据了。
内容的提问来源于stack exchange,提问作者TK Tang
相关产品推荐
相关产品推荐

