Ótimo vídeo. Gostaria que falasse mais sobre os níveis de isolamento de transações, como o "read uncommitted", "read committed", "snapshot", repeatble read" e "serializable".
Muito bom! Sempre gostei da abordagem pessimista (porque eu sempre acho que tudo vai dar errado... rs) ainda que haja custos de performance. Não conhecia a abordagem otimista. Muito legal saber como aplicar essa técnica. ✌️
Mais uma explicação com excelente didática. Além de explicar os conceitos muito bem você trouxe os trade-offs de cada solução. Além do mais, usar uma ferramenta para teste de carga torna o exemplo mais rico e embasado em qual solução adotar. 👏🏼 Ah, locks de banco de dados são normalmente traduzidos para o português como bloqueios. 😀
acontece que uso de for update pode causar serios colaterais em alta concorrencia, como deadlocks. esses erros gerados no teste de carga nao deveriam acontecer, independente se obteve sucesso nos 10. Esses erros geram log, alem de inchar o arquivo de log, derruba desempenho, aumenta latencia. aconselharia outros 2 NOWAIT, onde irá falhar de imediato de nao puder ser obtido, em vez de esperar. SKIP LOCKED, simplesmente ignorará a linha bloqueada nao gerando fila. Se os 10 produtos ja foram trancados, o demais passam batidos. Nao geram fila, e com isso nao ira gerar erros. podendo ser tratado com uma mensagem amigavel ao usuario. usar FOR UPDATE tem mais maleficios que beneficios existe FOR SHARE tambem, ai deem uma pesquisada ai. alem de SERIALIZABLE, READ COMMITTED e seus outros 2 coirmaos, so nao usem UNCOMMITTED para dados criticos. quando for critico, ideal mesmo e o SERIALIZABLE. Mas vai de como é a criticidade.
Muito bom. Por esses dias, tive um debate sobre esse tema, com essa explicação, agora consegui desafogar a mente da quantidade enorme de informações que obtive a respeito
gostei das abordagem, só ficou uma duvida no caso de criar um campo versão, não seria mais pratico aplicar Estoque >0, se entendi, as querys vão ser executadas enfileiradas pelo mysql, então o update que for deixar negativo, não vai acontecer.
Ótima pergunta! Pra esse caso em específico, sim. Só verificar o estoque seria suficiente. Mas no mundo real, há mais colunas sendo atualizadas. Talvez uma das colunas tenha sido mantida intacta enquanto outra foi mexida. Talvez uma atualização tenha sido feita em outra parte do produto, e assim em diante. Por isso é mais comum utilizar um timestamp (o famoso updated_at) ou uma coluna de versão. A técnica de optimistic locking não é só pro cenário de compras como o do vídeo. Foi só um exemplo mesmo. :-D
@@DiasDeDev eu tenho código para lock aqui, e é bem mais complexo que esse que tu mostrou ae, tiver até que conferir. utilizo uma tabela para controle =/. tenho uma programação paralela que atualiza o numero to ultimo lote de nfe, ae me surgiu uma duvida, não vou causar um problema de deadlock se eu fazer o controle com o controle de transação do mysql? ja que eu vou ter uma conexao com pdo para cada arquivo executado? no meu caso é aberto uma thread para cada execução
Primeiramente, quero dizer que seus conteúdos são tops e agregam valor demais para o nosso dia a dia como Dev. A dúvida que tenho é, a instrução SELET FOR UPDATE locka apenas a linha ou a tabela? se for a tabela, em um ambiente onde o cenário envolve termos mais de um pod em execução, o ideal seria ter um SELECT FOR UPDATE SKIP LOCKED?
A instrução trava os registros encontrados pra atualização. Ter mais de um pod não muda o cenário. Só vai ser impedido de acessar o registro quem, dentro de uma transação também, tentar bloquear o registro "for update". Select "normal" não fica bloqueado nesse cenário.
top demais dias, eu tinha esse pensamento de primeiro consultar e depois executar, vai me ajudar bastante. Duvida.... quando o usuário entra no beginTransaction e o select informa que tem estoque, até o usuário realmente fazer a compra, o sistema vai estar segurando o estoque, correto?
Com o SELECT FOR UPDATE dentro de uma transação, outras transações não podem obter lock para o mesmo registro, ou seja, quando outra conexão tentar fazer o SELECT FOR UPDATE também, ela vai ficar esperando a primeira liberar o lock, entende?
Essa estratégia é interessante, já à vi sendo utilizada em outras linguagens que executam de forma assíncrona. Mas fiquei com uma dúvida, ao invés de utilizar uma coluna auxiliar chamada versão, não poderia no update ser usado a quantidade em estoque recuperada na primeira query? Por exemplo: UPDATE produtos SET estoque = estoque - 1 WHERE id = 1 AND estoque = $quantidade; Ou em uma solução em que permita atualizar mesmo se o estoque não seja exatamente o mesmo, mas maior que 0 : UPDATE produtos SET estoque = estoque - 1 WHERE id = 1 AND estoque > 0;
Muito boa pergunta. Eu até respondi ela em outro comentário. Pro exemplo do vídeo, super resolveria. Mas no mundo real, mais colunas podem ser modificadas, etc. Então a abordagem de optimistic locking é geralmente utilizando um timestamp (famoso updated_at) ou uma coluna de versão.
Eu não conheço nenhuma biblioteca ou coisa do tipo pra isso. Você pode fazer um grande número de requisições de forma concorrente usando Guzzle ou outro cliente e, no final, garantir que o resultado é o esperado.
Ótimo vídeo.
Gostaria que falasse mais sobre os níveis de isolamento de transações, como o "read uncommitted", "read committed", "snapshot", repeatble read" e "serializable".
Opa, ótima ideia! Vou preparar sim.
Nossa?! nunca pensaria nisso, essa canal mostra pontos chave bem pontuais. Parabéns!!!!!
Que bom que gostou! :-D
Real, o cara trás conteúdo diferenciado
Eu tento. :-D
Se 1% dos vídeos no TH-cam fossem úteis como esse, o mundo era outro!!! Parabéns!
Fico feliz que tenha gostado! :-D
Conteúdo enriquecedor, parabéns!
Valeu, xará!
Muito bom !!!!!
:-D Que bom que gostou!
Muito bom! Sempre gostei da abordagem pessimista (porque eu sempre acho que tudo vai dar errado... rs) ainda que haja custos de performance.
Não conhecia a abordagem otimista. Muito legal saber como aplicar essa técnica.
✌️
Eu também tendo a tomá-la como padrão. :-D
Mais uma explicação com excelente didática. Além de explicar os conceitos muito bem você trouxe os trade-offs de cada solução. Além do mais, usar uma ferramenta para teste de carga torna o exemplo mais rico e embasado em qual solução adotar. 👏🏼 Ah, locks de banco de dados são normalmente traduzidos para o português como bloqueios. 😀
Opa, que honra, mestre! Fico muito feliz que tenha curtido.
nao seria melhor usar serializable ? ou de repente ate mesmo um nivel abaixo para nao perder tanto na latencia ?
acontece que uso de for update pode causar serios colaterais em alta concorrencia, como deadlocks. esses erros gerados no teste de carga nao deveriam acontecer, independente se obteve sucesso nos 10. Esses erros geram log, alem de inchar o arquivo de log, derruba desempenho, aumenta latencia.
aconselharia outros 2
NOWAIT, onde irá falhar de imediato de nao puder ser obtido, em vez de esperar.
SKIP LOCKED, simplesmente ignorará a linha bloqueada nao gerando fila. Se os 10 produtos ja foram trancados, o demais passam batidos. Nao geram fila, e com isso nao ira gerar erros. podendo ser tratado com uma mensagem amigavel ao usuario.
usar FOR UPDATE tem mais maleficios que beneficios
existe FOR SHARE tambem, ai deem uma pesquisada ai.
alem de SERIALIZABLE, READ COMMITTED e seus outros 2 coirmaos, so nao usem UNCOMMITTED para dados criticos.
quando for critico, ideal mesmo e o SERIALIZABLE. Mas vai de como é a criticidade.
Muito bom. Por esses dias, tive um debate sobre esse tema, com essa explicação, agora consegui desafogar a mente da quantidade enorme de informações que obtive a respeito
Fico feliz que tenha sido útil.
😁
Esse assunto é muito interessante, é muito importante pensar em problemas de concorrência na aplicação, ótima explicação
Que bom que gostou! 😁
Já usei bastante
Boa!
Excelente !
Eu desenvolvi um nosql que ja tem o lock pessimista integrado
Que maneiro!
gostei das abordagem, só ficou uma duvida no caso de criar um campo versão, não seria mais pratico aplicar Estoque >0, se entendi, as querys vão ser executadas enfileiradas pelo mysql, então o update que for deixar negativo, não vai acontecer.
Ótima pergunta!
Pra esse caso em específico, sim. Só verificar o estoque seria suficiente.
Mas no mundo real, há mais colunas sendo atualizadas. Talvez uma das colunas tenha sido mantida intacta enquanto outra foi mexida. Talvez uma atualização tenha sido feita em outra parte do produto, e assim em diante. Por isso é mais comum utilizar um timestamp (o famoso updated_at) ou uma coluna de versão.
A técnica de optimistic locking não é só pro cenário de compras como o do vídeo. Foi só um exemplo mesmo. :-D
@@DiasDeDev eu tenho código para lock aqui, e é bem mais complexo que esse que tu mostrou ae, tiver até que conferir. utilizo uma tabela para controle =/. tenho uma programação paralela que atualiza o numero to ultimo lote de nfe, ae me surgiu uma duvida, não vou causar um problema de deadlock se eu fazer o controle com o controle de transação do mysql? ja que eu vou ter uma conexao com pdo para cada arquivo executado? no meu caso é aberto uma thread para cada execução
Não existe deadlock com acesso a um único recurso.
Primeiramente, quero dizer que seus conteúdos são tops e agregam valor demais para o nosso dia a dia como Dev. A dúvida que tenho é, a instrução SELET FOR UPDATE locka apenas a linha ou a tabela? se for a tabela, em um ambiente onde o cenário envolve termos mais de um pod em execução, o ideal seria ter um SELECT FOR UPDATE SKIP LOCKED?
A instrução trava os registros encontrados pra atualização.
Ter mais de um pod não muda o cenário.
Só vai ser impedido de acessar o registro quem, dentro de uma transação também, tentar bloquear o registro "for update".
Select "normal" não fica bloqueado nesse cenário.
@@DiasDeDev obrigado pelo retorno!
Obrigado!
:-D
Muito útil 👏
Que bom que gostou. 😁
Muito top!
Que bom que gostou! :-D
@Dias de Dev, poderia fazer um video OWASP
Tenho anotado alguns tópicos específicos, como alguns ataques do top 10. :-D
top demais dias, eu tinha esse pensamento de primeiro consultar e depois executar, vai me ajudar bastante. Duvida.... quando o usuário entra no beginTransaction e o select informa que tem estoque, até o usuário realmente fazer a compra, o sistema vai estar segurando o estoque, correto?
Com o SELECT FOR UPDATE dentro de uma transação, outras transações não podem obter lock para o mesmo registro, ou seja, quando outra conexão tentar fazer o SELECT FOR UPDATE também, ela vai ficar esperando a primeira liberar o lock, entende?
@@DiasDeDev entendi, muito obg
para complementar, se a fila for grande os timeouts tbm serao.
Essa estratégia é interessante, já à vi sendo utilizada em outras linguagens que executam de forma assíncrona.
Mas fiquei com uma dúvida, ao invés de utilizar uma coluna auxiliar chamada versão, não poderia no update ser usado a quantidade em estoque recuperada na primeira query?
Por exemplo:
UPDATE produtos SET estoque = estoque - 1 WHERE id = 1 AND estoque = $quantidade;
Ou em uma solução em que permita atualizar mesmo se o estoque não seja exatamente o mesmo, mas maior que 0 :
UPDATE produtos SET estoque = estoque - 1 WHERE id = 1 AND estoque > 0;
Muito boa pergunta.
Eu até respondi ela em outro comentário. Pro exemplo do vídeo, super resolveria. Mas no mundo real, mais colunas podem ser modificadas, etc. Então a abordagem de optimistic locking é geralmente utilizando um timestamp (famoso updated_at) ou uma coluna de versão.
Opa pessoal, alguém saberia se consigo fazer um teste com phpunit testando concorrência?
Eu não conheço nenhuma biblioteca ou coisa do tipo pra isso.
Você pode fazer um grande número de requisições de forma concorrente usando Guzzle ou outro cliente e, no final, garantir que o resultado é o esperado.
@@DiasDeDev vou fazer assim, obrigado