我们的系统在Ubuntu,python 3.4,postgres 9.4.x和psycopg2上运行。
我们(将在未来)使用模式在dev
,test
和prod
环境之间进行分割。我创建了一种方便的方法来创建与数据库的连接。它使用json连接配置文件来创建连接字符串。我想配置连接以使用返回的连接为所有后续查询使用特定模式。我不希望我的查询有硬编码模式,因为我们应该可以根据我们是否处于开发,测试或生产阶段/环境中轻松切换它们。
目前,便捷方法如下所示:
def connect(conn_config_file = 'Commons/config/conn_commons.json'):
with open(conn_config_file) as config_file:
conn_config = json.load(config_file)
conn = psycopg2.connect(
"dbname='" + conn_config['dbname'] + "' " +
"user='" + conn_config['user'] + "' " +
"host='" + conn_config['host'] + "' " +
"password='" + conn_config['password'] + "' " +
"port=" + conn_config['port'] + " "
)
cur = conn.cursor()
cur.execute("SET search_path TO " + conn_config['schema'])
return conn
只要你给它时间来执行set search_path
查询,它就可以正常工作。不幸的是,如果我执行以下查询的速度太快,则会在search_path
未设置的情况下发生竞争条件。我已尝试在conn.commit()
之前执行return conn
强制执行,但是,这会将search_path
重置为默认架构postgres
,因此它不会#&# 39; t使用,比方说,prod
。在数据库或应用程序层的建议是可取的,但是,我知道我们可能也可以在操作系统级别解决这个问题,也欢迎任何有关这方面的建议。
示例json配置文件如下所示:
{
"dbname": "thedatabase",
"user": "theuser",
"host": "localhost",
"password": "theusers_secret_password",
"port": "6432",
"schema": "prod"
}
非常感谢任何建议。
答案 0 :(得分:10)
我认为更优雅的解决方案是在[Serializable()]
class NodeTag : ISerializable
{
public NodeTag(string Subnet)
{
Broadcast_Address = Stuff;
Network_Name = Stuff;
CIDR_Value = Stuff;
}
public string Network_Name { get; set; }
public string CIDR_Value { get; set; }
public string Broadcast_Address { get; set; }
//Deserializer - loads back from file data
//This is an overloaded function that defines the data object when it is being reconstituted
public NodeTag(SerializationInfo info, StreamingContext context)
{
Network_Name = (String)info.GetValue("Network_Name", typeof(string));
CIDR_Value = (String)info.GetValue("CIDR_Value", typeof(string));
Broadcast_Address = (String)info.GetValue("Broadcast_Address", typeof(string));
}
//Serializer - loads into file data
public void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Network_Name", Network_Name);
info.AddValue("CIDR_Value", CIDR_Value);
info.AddValue("Broadcast_Address", Broadcast_Address);
}
}
的{{1}}参数中设置search_path
,如下所示:
options
当然,您可以使用"选项"作为连接字符串的一部分。但是使用关键字参数会阻止字符串连接的所有麻烦。
我在此psycopg2 feature request中找到了此解决方案。至于"选项"参数本身,它提到了here。
答案 1 :(得分:6)
我认为更好的想法是让像DatabaseCursor这样的东西返回你用来执行查询的游标" SET search_path ..."而不是连接。 我的意思是这样的:
class DatabaseCursor(object):
def __init__(self, conn_config_file):
with open(conn_config_file) as config_file:
self.conn_config = json.load(config_file)
def __enter__(self):
self.conn = psycopg2.connect(
"dbname='" + self.conn_config['dbname'] + "' " +
"user='" + self.conn_config['user'] + "' " +
"host='" + self.conn_config['host'] + "' " +
"password='" + self.conn_config['password'] + "' " +
"port=" + self.conn_config['port'] + " "
)
self.cur = self.conn.cursor()
self.cur.execute("SET search_path TO " + self.conn_config['schema'])
return self.cur
def __exit__(self, exc_type, exc_val, exc_tb):
# some logic to commit/rollback
self.conn.close()
和
with DatabaseCursor('Commons/config/conn_commons.json') as cur:
cur.execute("...")