Python I';我得到一个';鬼';从sqlalchemy回滚,但在postgres中使用psql时不回滚
我在postgres+sqlalchemy中有一种奇怪的行为 我调用了一个插入到表中的函数,但当从sqlalchemy调用时,它会在最后返回,当从psql调用时,它会成功: sqlalchemy调用时的日志(由日志报告): 如果使用psql:Python I';我得到一个';鬼';从sqlalchemy回滚,但在postgres中使用psql时不回滚,python,transactions,sqlalchemy,postgresql-9.2,Python,Transactions,Sqlalchemy,Postgresql 9.2,我在postgres+sqlalchemy中有一种奇怪的行为 我调用了一个插入到表中的函数,但当从sqlalchemy调用时,它会在最后返回,当从psql调用时,它会成功: sqlalchemy调用时的日志(由日志报告): 如果使用psql: Jan 21 13:28:47 intersec.local postgres[3561]: [20-9] STATEMENT: SELECT name, suffix FROM doc_codes('195536d95bd155b9ea412154b3
Jan 21 13:28:47 intersec.local postgres[3561]: [20-9] STATEMENT: SELECT name, suffix FROM doc_codes('195536d95bd155b9ea412154b3e920761495681a');
请注意,根本不是事务
这是我的python代码:
def getCon(self):
conStr = "postgresql+psycopg2://%(USER)s:%(PASSWORD)s@%(HOST)s/%(NAME)s"
config = settings.DATABASES['default']
#print conStr % config
con = sq.create_engine(
conStr % config,
echo=ECHO
)
event.listen(con, 'checkout', self.set_path)
self.con = con
self.meta.bind = con
return con
def getDocPrefixes(self, deviceId):
f = sq.sql.func.doc_codes(deviceId, type_=types.String)
columns = [
sq.Column('name', types.String),
sq.Column('suffix', types.String)
]
return [dict(x.items()) for x in self.con.execute
(
select(columns).
select_from(f)
).fetchall()]
sync = dbSync('malab')
for k in sync.getDocPrefixes('195536d95bd155b9ea412154b3e920761495681a'):
print k['name'], '=', k['suffix']
什么会触发回滚
我的数据库功能:
CREATE OR REPLACE FUNCTION next_letter (
table_name TEXT,
OUT RETURNS TEXT
)
AS
$$
DECLARE
result TEXT = 'A';
nextLetter TEXT;
num INTEGER;
BEGIN
SELECT INTO num nextval('letters');
nextLetter := chr(num);
result := nextLetter;
WHILE true LOOP
--RAISE NOTICE '%', result;
IF EXISTS(SELECT 1 FROM DocPrefix WHERE Name=result AND TableName=table_name) THEN
SELECT max(SUBSTRING(name FROM '\d+'))
FROM DocPrefix WHERE Name=result AND TableName=table_name
INTO num;
result := nextLetter || (coalesce(num,0) + 1);
ELSE
EXIT;
END IF;
END LOOP;
RETURNS = result;
END;
$$
LANGUAGE 'plpgsql';
-- Retorna el prefijo unico para la tabla/dispositivo.
CREATE OR REPLACE FUNCTION prefix_fordevice (
table_name TEXT,
device_id TEXT,
OUT RETURNS TEXT
)
AS
$$
DECLARE
result TEXT = NULL;
row RECORD;
BEGIN
IF NOT(EXISTS(SELECT 1 FROM DocPrefix WHERE MachineId=device_id AND TableName=table_name)) THEN
INSERT INTO DocPrefix
(Name, MachineId, TableName)
VALUES
(next_letter(table_name), device_id, table_name);
END IF;
SELECT name FROM DocPrefix WHERE
MachineId=device_id AND TableName=table_name
INTO result;
RETURNS = result;
END;
$$
LANGUAGE 'plpgsql';
--Retornar los prefijos exclusivos para el ID de dispositvo
CREATE OR REPLACE FUNCTION doc_codes(device_id TEXT) RETURNS TABLE("name" TEXT, "suffix" TEXT) AS $$
SELECT name, prefix_fordevice(name, device_id) AS suffix FROM doccode;
$$ LANGUAGE SQL;
这里的反模式是,当您执行以下操作时,您混淆了连接的SQLAlchemy
引擎
:
con = sq.create_engine(<url>)
result = con.execute(statement)
con=sq.创建引擎()
结果=con.execute(语句)
引擎作为连接源与连接池相关联。在引擎上调用execute()方法时,它会从池中签出连接,运行语句并返回结果;当结果集耗尽时,它返回到池的连接。在该阶段,池将完全关闭连接,或者重新池连接。将连接存储在池中意味着必须清除任何剩余的事务状态(请注意,DBAPI连接在使用时始终位于事务中),因此它会发出回滚
您的程序应该在模块级别为每个URL创建一个引擎
,当需要连接时,应该调用Engine.connect()
文档解释了所有这些。我终于在这里找到了答案:
问题是,函数可以插入数据,也可以返回一个SELECT,因此,sqlalchemy认为这是一个正常的SELECT,而实际上函数也会更改数据并需要提交。好的,我现在将创建引擎放在类之外。然后为getCon请求con.connect()。然而,仍然看到同样的事情。然后切换到NullPool,也一样。这是在django应用程序内部运行的..我在django外部检查并运行它。同样的结果,因此与django无关。如果您正在执行一个需要提交的语句,并且它是一个存储过程,SQLA的autocommit将无法识别这一点。是的,您需要像上面那样运行begin(),或者使用autocommit。同样,这都在我链接的文档-自动提交中,具体如下:
con = sq.create_engine(<url>)
result = con.execute(statement)
def getDocPrefixes(self, deviceId):
f = sq.sql.func.doc_codes(deviceId, type_=types.String)
columns = [
sq.Column('name', types.String),
sq.Column('sufix', types.String)
]
with self.con.begin():
return [dict(x.items()) for x in self.con.execute
(
select(columns).
select_from(f)
).fetchall()]