Python操作PostgreSQL创建数据库报错:无法在事务块内执行CREATE DATABASE
问题原因及解决方案
问题出在with connection上下文管理器的行为上:psycopg2在进入这个上下文时会自动启动一个事务,而你是进入上下文之后才设置autocommit=True,此时事务已经存在,执行CREATE DATABASE自然会触发"不能在事务块内执行"的报错。
两种可行的解决方法
方法一:创建连接时直接开启自动提交
在调用psycopg2.connect()时直接传入autocommit=True参数,让连接从一开始就处于自动提交模式,这样上下文管理器就不会自动启动事务:
try: with psycopg2.connect( host=host, user=rootUser, password=rootPassword, autocommit=True # 直接开启自动提交 ) as connection: with connection.cursor() as cursor: # 用psycopg2.sql模块构造安全SQL,避免注入风险 from psycopg2 import sql cursor.execute(sql.SQL(""" CREATE DATABASE {} WITH OWNER = {} ENCODING = 'UTF8' CONNECTION LIMIT = -1 IS_TEMPLATE = False; """).format(sql.Identifier(db_name), sql.Identifier(user))) except Exception as e: print(f"错误信息: {e}")
方法二:回滚已启动的事务后再设置自动提交
如果需要在连接建立后再开启自动提交,必须先回滚上下文管理器自动启动的事务,再设置autocommit=True:
try: with psycopg2.connect( host=host, user=rootUser, password=rootPassword, ) as connection: connection.rollback() # 回滚自动开启的事务 connection.autocommit = True with connection.cursor() as cursor: from psycopg2 import sql cursor.execute(sql.SQL(""" CREATE DATABASE {} WITH OWNER = {} ENCODING = 'UTF8' CONNECTION LIMIT = -1 IS_TEMPLATE = False; """).format(sql.Identifier(db_name), sql.Identifier(user))) except Exception as e: print(f"错误信息: {e}")
额外提醒
不要直接用字符串拼接SQL语句,这会带来SQL注入风险。psycopg2提供了sql模块,可以安全地处理数据库名、用户名这类标识符,上面的示例已经采用了这种写法。
内容的提问来源于stack exchange,提问作者dodle
相关产品推荐
相关产品推荐

