Contexto: A estrutura usada é Spring e todas as consultas são executadas com JdbcTemplate. A versão do Mysql Server é 5.6.19. O padrão table
é um InnoDB table
e o padrão auto commit
de leitura repetível e nível de isolamento está definido.
Problema : Insert
acontece dentro de uma transação e uma select
que lê os mesmos dados inseridos não os vê. As select
corridas após o insert
e depois da insert
transação tem commited
.
Eu habilitei o log de bin e o log geral no mysql. Registros relevantes abaixo
bin-log:
SET TIMESTAMP=1438265764/*!*/;
BEGIN
/*!*/;
# at 249935389
#150730 14:16:04 server id 1 end_log_pos 249935606 CRC32 0xa6aca292 Query thread_id=40 exec_time=0 error_code=0
SET TIMESTAMP=1438265764/*!*/;
insert into user_geo_loc_latest(user_id, lat, lng) values(x,y,z) on duplicate key update lat=y, lng=z
/*!*/;
# at 249935606
#150730 14:16:06 server id 1 end_log_pos 249936255 CRC32 0x2a52c734 Query thread_id=40 exec_time=0 error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table(txnid) VALUES ('885851438265675046')
/*!*/;
# at 249936255
#150730 14:16:06 server id 1 end_log_pos 249936514 CRC32 0x6cd85eb5 Query thread_id=40 exec_time=0 error_code=0
SET TIMESTAMP=1438265766/*!*/;
INSERT INTO table2(x) VALUES (y)
/*!*/;
# at 249936514
#150730 14:16:06 server id 1 end_log_pos 249936545 CRC32 0xceb9ec56 Xid = 9406873
COMMIT/*!*/;
Log de consulta
150730 14:16:04 40 Query ...
....
40 Query select count(*) from table where txnid = '885851438265675046'
40 Query select @@session.tx_read_only
40 Query INSERT INTO table(txnid) VALUES ('885851438265675046')
40 Query select @@session.tx_read_only
40 Query INSERT INTO table2(x) values(y)
40 Query commit
....
150730 14:16:07 36 Query select pp.*, b.create_date from table pp left join bill b on pp.bill_id = b.bill_id where pp.txnid = '885851438265675046'
Curiosamente, First insert
(249935389) não deve fazer parte da transação. É uma chamada de API separada e completamente independente. Pode ser primavera misturando-o com a transação ou estou lendo o log errado? AFAIK, pois está no mesmo encadeamento, implica que a inserção está na transação.
Os próximos dois inserts
fazem parte da transação e parece que eles confirmam. (249936514). Agora a consulta de seleção (a última no log geral) é executada após a confirmação e não vê os dados. Retorna 0 linhas. Como isso pode acontecer considerando os dados committed
? Ou é o que commit
não está no fio 40? Uma vez que não possui o ID do segmento.
Para resumir, tenho duas perguntas.
O que está
BEGIN
no binlog antes daINSERT INTO user_geo_loc
(que não faz parte da transação), é um erro do spring / Jdbc ou MySql simplesmente faz isso porque sabe que essa transação já foi confirmada (como as transações são gravadas no binlog quando conseguiu) e, portanto, nunca seria revertida.Dado que a confirmação ocorre antes da seleção (a confirmação é às 14:16:06 e a seleção às 14:16:07), como é que a seleção não retorna a linha inserida pela transação?
Isso é extremamente desconcertante. Qualquer ajuda seria apreciada
Nota: As consultas no compartimento e no log de consultas foram editadas para remover informações confidenciais. Mas a essência das consultas permanece a mesma
Editar: atualizado com o log geral e o log de consulta com um exemplo detalhado.
fonte
BEGIN
ouSTART TRANSACTION
. Você está usandoautocommit=0
? (Eu prefiro começar ... cometer, que torna a extensão da transação clara.)Respostas:
Eu tento fazer uma hipótese sobre a segunda pergunta:
As transações são gerenciadas pelo Spring. Portanto, seria possível que antes de executar a
select
mola tenha levantado umastart transaction
ou já tenha usado a conexão para executar outra consulta.Inicio uma primeira sessão em que simulo uma inserção em uma tabela
t
:Crio uma nova sessão, session2, em que
autocommit
está definido como 0. Nesta nova sessão, uma transação é iniciada implicitamente ao executar uma seleção.Vá para session1 para confirmar a inserção.
Agora vá novamente para a sessão2:
Session2 não pode ver a linha inserida. Se a
commit
for gerado na sessão2, podemos ver uma nova linha inserida na sessão1O log geral se parece com:
A primeira linha está relacionada à sessão 2. É quando a sessão 2 abre a transação.
Não sei se é isso que acontece no seu caso. Você pode verificar em seu log geral se o connection_id 36 foi usado para outras consultas. Deixe-nos saber.
fonte