Quando faço uma única linha INSERT
em uma tabela que possui uma AUTO_INCREMENT
coluna, gostaria de usar a LAST_INSERT_ID()
função para retornar o novo AUTO_INCREMENT
valor 'ed armazenado para essa linha.
Como muitos desenvolvedores e administradores do Microsoft SQL Server, sem dúvida, estão cientes de que a funcionalidade equivalente no SQL Server ( SCOPE_IDENTITY
e @@IDENTITY
) não foi isenta de problemas .
Eu sei que o estado dos documentos do MySQL:
O ID que foi gerado é mantido no servidor por conexão . Isso significa que o valor retornado pela função para um determinado cliente é o primeiro
AUTO_INCREMENT
valor gerado para a declaração mais recente que afeta umaAUTO_INCREMENT
coluna por esse cliente . Este valor não pode ser afetado por outros clientes, mesmo que geremAUTO_INCREMENT
valores próprios. Esse comportamento garante que cada cliente possa recuperar seu próprio ID sem se preocupar com a atividade de outros clientes e sem a necessidade de bloqueios ou transações.
e até chega a dizer:
Usar
LAST_INSERT_ID()
eAUTO_INCREMENT
colunas simultaneamente de vários clientes é perfeitamente válido.
Existem riscos ou cenários conhecidos que podem fazer com que LAST_INSERT_ID()
não retorne o valor correto?
Estou usando o MySQL 5.5 no CentOS 5.5 x64 e Fedora 16 x64 e o mecanismo InnoDB.
Algumas advertências que gostaria de apontar ao usar
LAST_INSERT_ID
:Eu sei que você mencionou inserções de linha única. Mas ao fazer inserções de várias linhas,
LAST_INSERT_ID()
retornará o valor da primeira linha inserida (não a última).Se a inserção falhou,
LAST_INSERT_ID()
seria indefinido. O mesmo vale para rollbacks automáticos de transações (devido a erros).Se você fizer uma inserção em uma transação bem-sucedida e ainda emitir um
ROLLBACK
,LAST_INSERT_ID()
será deixado como estava antes da reversão.Há algumas advertências ao usar
AUTO_INCREMENT
eLAST_INSERT_ID
na replicação baseada em instrução. O primeiro sendo quando usado em um trigger ou função. O segundo é o cenário menos comum em que sua coluna auto_increment faz parte de uma chave primária composta e não é a primeira coluna da chave.Para expandir ainda mais o ponto número 2 na resposta dada por DTest:
Nas versões do MySQL que usei, é uma boa ideia redefinir explicitamente o valor de LAST_INSERT_ID antes de cada bloco de código em que você planeja executar uma inserção.
Isso pode ser feito assim:
Depois que a série de instruções acima for executada, você saberá se a inserção teve algum efeito verificando se LAST_INSERT_ID ainda estava definido como "some_flag_init_value_of_your_choice" no final da execução.
Caso contrário, você pode acabar com a seguinte situação problemática:
Como a segunda inserção falhou , você pode estar esperando que a segunda chamada para LAST_INSERT_ID retornaria NULL ou produziria um conjunto de resultados vazio (zero linhas). O fato de ele ainda retornar um identificador inteiro válido pode induzir você a pensar que a segunda inserção foi SUCEDIDA quando não o fez.
As coisas ficam AINDA MAIS ESTRANHAS quando você considera que LAST_INSERT_ID continuará a preservar e repetir o último ID exclusivo bem-sucedido, mesmo se as instruções de inserção com falha subsequentes estiverem direcionando tabelas diferentes da tabela que produziu o último ID exclusivo bem-sucedido. Em outras palavras, você insere na tabela TA e obtém um id de 5, depois insere em TB (mas falha), mas ainda vê um 5. Com base nisso, você acha que acabou de criar uma nova linha no TA com id de 5 e uma nova linha em TB com id de 5, enquanto na realidade não existe nenhuma linha em TB com id 5, ou existe tal linha, mas na verdade não tem nada a ver com qualquer código que você acabou de correu.