我有一个sqlalchemy脚本,可以创建和使用代表许多用户连接的许多引擎实例。所有引擎都配置为指向同一个postgres数据库。
我有一个引擎,oSuperEngine
可以做超级东西。我为鲍勃提供了另一个引擎'oBobsEngine`。
现在我正在做这样的事情:
sSQL = "GRANT ALL PRIVILEGES ON TABLE \"NICE_TABLE\" to bob;"
oSuperEngine.execute(sSQL)
sSQL = "insert into \"NICE_TABLE\" (foo) values (bar)"
oBobsEngine.execute(sSQL) # ERROR HERE
得到:
ProgrammingError: (ProgrammingError) permission denied for relation NICE_TABLE
为什么会这样?
psql中的 \dp
告诉我bob从未被授予权限。如果我用超级用户登录psql并手动授予bob他的权限,那么一切正常。在这种情况下,我通过sqlalchemy执行完全相同的命令。
有些东西没有正确冲洗吗? sqlalchemy出于某种原因在尝试授予语句时是否会无声地失败?我怎样才能做到这一点?
不包含更多代码的道歉,代码库是适度错综复杂的。我已经使用日志确认了事件的顺序...如果您需要更多代码以便了解我的问题,请告诉我。
一些日志
2014-03-10 10:07:24,767 - common.sqlalchemy_tools - DEBUG - connection string = "postgresql+psycopg2://super:password@localhost/db_name"
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - BEGIN;
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - GRANT ALL PRIVILEGES ON TABLE "MY_TABLE" to bob;
2014-03-10 10:07:24,767 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,768 - sqlalchemy.engine.base.Engine - INFO - COMMIT;
2014-03-10 10:07:24,768 - sqlalchemy.engine.base.Engine - INFO - {}
...
2014-03-10 10:07:24,804 - common.sqlalchemy_tools - DEBUG - connection string = "postgresql+psycopg2://bob:password@localhost/db_name"
2014-03-10 10:07:24,814 - sqlalchemy.engine.base.Engine - INFO - BEGIN;
2014-03-10 10:07:24,815 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,827 - sqlalchemy.engine.base.Engine - INFO - insert into "MY_TABLE" (stuff) values (other stuff);
2014-03-10 10:07:24,827 - sqlalchemy.engine.base.Engine - INFO - {}
2014-03-10 10:07:24,828 - sqlalchemy.engine.base.Engine - INFO - ROLLBACK
第一堆东西发生在oSuperEngine
,第二堆发生在bob的引擎上。错误看起来像:
ProgrammingError: (ProgrammingError) permission denied for relation MY_TABLE
'insert into "MY_TABLE" (stuff) values (stuff);' {}
答案 0 :(得分:6)
我遇到了完全相同的问题。通过这样做固定:
sSQL = "GRANT ALL PRIVILEGES ON TABLE \"NICE_TABLE\" to bob;"
with oSuperEngine.begin() as conn:
conn.execute(sSQL)
答案 1 :(得分:2)
如果您执行上面的脚本,则会遇到事务隔离问题。实际上我前段时间遇到了类似的问题。这里需要记住的是,Bob的事务没有看到Super引擎所做的更改,因为事务仍在进行,隔离不允许进行非公开读取。 Postgres对此有extensive documentation,但其实质是:在postgres 中无法进行无法读取。
显然,您的解决方案是首先从超级引擎提交更改,然后在另一个事务中使用它。如果没有尝试过,但我的猜测是你必须保持默认的 Read committed 隔离级别(因为更高的隔离不允许检测自事务以来的更改 - 在这种情况下Bobs - 已经启动)。
因此,在执行Bobs查询之前:
oSuperEngine.execute("COMMIT")
然而,这引发了一个侧面问题,有效地打破了交易带来的令人敬畏的事情:由于已经提交了更改,因此无法轻松回滚。你在这里基本上想要的是保存点的反面:
虽然保存点尚未存储对数据库的更改,但它确保回滚只会返回到特定点,而不是一直返回到特定点。你想要相反:将它存储在数据库中,但能够回滚并再次从中删除它。我不知道这样的事情,我高度怀疑它是否存在,因为它违反了事务隔离的原则。
我对此问题的解决方案是编写自定义回滚例程,我会调用异常,以便我可以手动撤消更改。这是相当多的工作,从长远来看是高维护。最后,在我的情况下,我重新考虑了我的解决方案并放弃了多引擎方法(但这是你必须自己做出的决定)。