SQLAlchemy não retornando dados selecionados
-
10-07-2019 - |
Pergunta
Eu estou usando SQLAlchemy como o ORM dentro de um aplicativo eu tenho vindo a construir há algum tempo.
Até agora, tem sido um grande ORM indolor para implementar e usar, no entanto, uma característica recente que estou trabalhando requer uma fila persistente e distribuída (lista & trabalhador) implementação estilo, que eu construí em MySQL e Python .
É tudo funcionou muito bem até que eu testei em um ambiente dimensionado.
Eu usei nível de linha InnoDB bloqueio para garantir cada linha só é lido uma vez, enquanto a linha é bloqueada, eu atualizar um ' in_use
' valor, para se certificar de que os outros não pegar na entrada .
Desde o MySQL não oferece um método "NOWAIT" como Postgre ou Oracle faz, eu correr em problemas de bloqueio, onde segmentos de trabalho pendurar e esperar que a linha bloqueada para se tornar disponível.
Em uma tentativa de superar essa limitação, eu tentei colocar todo o processamento necessário em uma única instrução e executá-lo através do ORM execute()
método, embora, SQLAlchemy se recusa a devolver o consulta resultado.
Aqui está um exemplo.
A minha declaração SQL é:
SELECT id INTO @update_id FROM myTable WHERE in_use=0 ORDER BY id LIMIT 1 FOR UPDATE;
UPDATE myTable SET in_use=1 WHERE id=@update_id;
SELECT * FROM myTable WHERE id=@update_id;
E eu executar esse código no console:
engine = create_engine('mysql://<user details>@<server details>/myDatabase', pool_recycle=90, echo=True)
result = engine.execute(sqlStatement)
result.fetchall()
Apenas para obter este resultado
[]
Estou certo de que a declaração está em execução desde que eu posso ver o efeito atualização tomada no banco de dados, e se eu executar através do terminal mysql ou outras ferramentas, fico com a linha modificada retornou. Ele apenas parece ser SQLAlchemy que não querem reconhecer a linha retornada.
Existe específica qualquer coisa que precisa ser feito para garantir que os picaretas ORM até a resposta?
Felicidades
Solução
Você executadas 3 consultas e MySQLdb cria um conjunto de resultados para cada um. Você tem que buscar primeiro resultado, em seguida, chamar cursor.nextset()
, buscar segundo e assim por diante.
Isso responde a sua pergunta, mas não vai ser útil para você, porque não vai resolver problema de bloqueio. Você tem que entender como FOR UPDATE funciona em primeiro lugar: ele bloqueia linhas retornadas até o fim da transação. Para evitar longa espera de bloqueio você tem que torná-lo o mais curto possível: SELECT ... FOR UPDATE
, UPDATE SET in_use=1 ...
, COMMIT
. Você realmente não precisa colocá-los em única instrução SQL, 3 chamadas execute()
será OK também. Mas você tem que se comprometer antes de tempo de computação, caso contrário bloqueio será realizada muito tempo e in_use
atualização (bloqueio off-line) não tem sentido. E com certeza você pode fazer a mesma coisa usando ORM também.