Mysql
 sql >> Base de Dados >  >> RDS >> Mysql

várias solicitações para o problema de sincronização do node express mysql


Eu não conheço o knex em detalhes e, a partir de uma pesquisa rápida, o knex atualmente não suporta o uso de "limite" nas instruções de atualização, portanto, apenas uma descrição da abordagem geral.

Primeiro, faça uma atualização para a linha que corresponde aos critérios e, em seguida, selecione essa linha atualizada.

Então, primeiro faça uma operação de atualização que atribui o ID do usuário atual à primeira linha não processada que não tem nenhum usuário atribuído ou que já tem o mesmo usuário atribuído:
update rows 
    set assignedTo = user.id 
    where assignedTo=0 or assignedTo=user.id 
    order by createdAt asc 
    limit 1

Eu acho que pode funcionar assim com knex usando uma consulta bruta, mas não tentei isso:
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid  order by createdAt asc limit 1', {userid: user.id})

Isso procurará a primeira linha (mais antiga criada em) que não foi atribuída ou já foi atribuída ao mesmo usuário e, em seguida, atribuirá esse usuário. Isso acontece de uma vez.

Você pode procurar a linha atribuída ao usuário:
const notProcessed = await knex('rows')
    .select('*'')
    .whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
    .orderByRaw('createdAt asc')
    .first();

Observe como agora procuramos explicitamente apenas uma linha já atribuída ao usuário.

Combinado
await knex.raw('update rows set assignedTo = :userid where assignedTo=0 or assignedTo= :userid  order by createdAt asc limit 1', {userid: user.id})
const notProcessed = await knex('rows')
    .select('*'')
    .whereRaw(`status='Not-Processed' and assignedTo=${user.id}`)
    .orderByRaw('createdAt asc')
    .first();

Obviamente você não precisa do select se não quiser trabalhar com a linha imediatamente.

O problema é que, quando várias solicitações são tratadas ao mesmo tempo, você precisa imaginar várias instâncias do código sendo executadas ao mesmo tempo em paralelo. Portanto, com seu código original, duas solicitações podem fazer sua seleção ao mesmo tempo antes que qualquer uma delas faça uma atualização. Assim, ambos terão a mesma linha retornada.

Ao atualizar imediatamente a linha dentro da instrução, mesmo quando duas instruções são executadas em paralelo, o banco de dados garantirá que elas não vejam a mesma linha.

Uma abordagem alternativa para uma solução seria usar um mutex (como, por exemplo, async-mutex ) em torno de seu código original para garantir que sua operação de seleção e atualização original seja atômica (acontece de uma só vez), mas isso provavelmente aumentará o tempo de resposta do seu aplicativo porque em algumas situações uma operação de manipulação de solicitação terá que esperar outra um para continuar.