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

Foi útil?

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.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top