注意:以下情况中,psycopg2 的 isolation_level 不是 autocommit mode。
使用 psycopg2 操作 pg(postgresql) 时,经常会用到事务(Transaction)。
按照一般数据库的做法,我们一般会认为,事务一般是用在 INSERT
/UPDATE
/DELETE
和其他对数据库有更改的 SQL 语句中,如下就是处理事务的代码写法:
同时,我们一般也会认为,查询语句(SELECT)之类不对数据产生影响的语句,就不需要做事务处理了。
但是,在 psycopg2 中,这么做是错误的,一旦 SELECT 语句出错抛出异常(如:psycopg2.ProgrammingError)后,继续运行 SQL 语句便会抛出事务异常;
psycopg2.InternalError: current transaction is aborted, commands ignored until end of transaction block
于是,psycopg2 的 connection 对象便无法使用,每次执行 SQL 都会抛出异常(详情见上),必须运行 rollback() 后才能继续执行其他 SQL 语句;
- 错误代码
- 正确代码
出现这种情况大多在单连接项目,如果每次操作都创建一个新的 connection 对象的话,这个错误也就不会发生了。
官方文档 Transactions control 中对此有所警告,警告原文如下:
Warning:By default even a simple SELECT will start a transaction: in long-running programs, if no further action is taken, the session will remain “idle in transaction”, a condition non desiderable for several reasons (locks are held by the session, tables bloat…). For long lived scripts, either make sure to terminate a transaction as soon as possible or use an autocommit connection.