Ir para conteúdo

POWERED BY:

Arquivado

Este tópico foi arquivado e está fechado para novas respostas.

CrazyLOL

Mysqli Commit e Rollback

Recommended Posts

Galera, estou com uma dúvida...

Estou usando os recursos de Commit e Rollback do Mysqli e está tranquilo, meu problema está sendo quando estou inserindo uma informação que possui uma dependencia.. por exemplo..

 

Insiro uma informação na tabela A e ela gera um ID único, quando vou inserir na tabela B preciso pega o ID da tabela A, o problema é que quando estou usando estes recursos o Commit será feito apenas no final caso todas as querys foram executadas com sucesso, como não foi feito commit ainda no momento que fiz o insert na tabela B 'tecnicamente' ainda não existe o ID único gerado na tabela A..

 

Em outras palavras, como que posso trabalhar de uma forma correta essas informações e para o final, caso tenha sido feito tudo com sucesso, seja feito o commit ou rollback?

 

Agradeço a ajuda!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Exatamente essa é a mágica das transações (commit/rollback)!

 

Você vai fazer as queries normalmente... pega o ID da tabela A, joga na B (sim, esse ID existe, mesmo que a transação não tenha sido "commitada"), e somente após tudo estar OK, você efetiva.

 

Se der qualquer problema no meio do caminho, o rollback vai remover a linha em A e o que você mexeu na B.

 

Não tenho certeza se te ajudei, pq a pergunta estava meio confusa, mas espero que sim. Se não, por favor, poste seu código e o que está acontecendo / deveria estar acontecendo.

 

Abraços!

Compartilhar este post


Link para o post
Compartilhar em outros sites

Foi exatamente como você falou mesmo..

Imaginei que não daria esse lance do commit e rollback por causa dessa dependência dos id únicos...

 

Obrigado Matheus, resolveu a minha dúvida..

 

Agradeço pela resposta.

Compartilhar este post


Link para o post
Compartilhar em outros sites

Matheus, desculpe reviver o topico porém não tive exito no teste...

 

Fiz da seguinte maneira:

$DB->mConnect();
$DB->Mysqli->autocommit(false);

$er = true;

$query = "insert into tabela_a (descricao) values ('testes')";
$er = !$DB->Mysqli->query($query) ? false : true;
$codigo = $DB->Mysqli->insert_id;

$query2 = "insert into tabela_b (cod_pai, descricao) values (".$codigo.", 'teste filho')";
$er = !$DB->Mysqli->query($query2) ? false : true;

$er ? $DB->Mysqli->commit() : $DB->Mysqli->rollback();

var_dump($err);

Porém quando faço o insert na tabela B da erro de chave primária pois a mesma não existe na tabela A.

 

Fiz o debug o "last_insert_id" está retornando sim o código mas a tabela B não reconhece o código. o que será que pode ser feito?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Acredito que está incorreto a sintaxe...

insert into (descricao) values ('testes');
ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '(descricao) values ('testes')' at line 1

De qualquer forma, você deu atenção ao tipo de Engine na sua tabela?


Fiz um exemplo aqui pra você se ligar como funciona transactions focando exclusivamente no SQL... (e sintaxe que foi um dos erros no seu post).


Vamos criar um banco apenas pro teste... 'dbtst'

CREATE DATABASE dbtst;
use dbtst;


CREATE TABLE descricao(
	 id int (8) not null primary key AUTO_INCREMENT
	,nome varchar(250)
);

Repare que não Informei o tipo do Engine neste caso ele assume o default/padrão que é MyIsam

Bora dar um Insert tradicional....

INSERT INTO descricao (nome) values ('Produto legal');

E agora dar um start na transação e inserir mais um registro...

START TRANSACTION; /*ou BEGIN*/
INSERT INTO descricao (nome) values ('Produto Chato');

Vamos trabalhar com 2 conexões diferentes para testar se está tudo 'OK'

-- Conexão 1:

mysql> SELECT * FROM descricao;
+----+---------------+
| id | nome          |
+----+---------------+
|  1 | Produto legal |
|  2 | Produto Chato |
+----+---------------+
2 rows in set (0.00 sec)


Aqui você abre uma conexão diferente para verificar se está valendo a transaction....
-- Conexão 2: (A diferente dos INSERTS/TRANSACTION)

mysql> SELECT * FROM descricao;
+----+---------------+
| id | nome          |
+----+---------------+
|  1 | Produto legal |
|  2 | Produto Chato |
+----+---------------+
2 rows in set (0.00 sec)

Ou seja efetuar o comando 'START TRANSACTION' não valeu de m.rd@ nenhuma.... já que a Engine tabela é MyIsam

Ok... e como essa budegas funciona?!



Vamos refazer o processo agora definindo o Engine da tabela como InnoDb...

DROP TABLE descricao; /* Apaga */
CREATE TABLE descricao(
	 id int (8) not null primary key AUTO_INCREMENT
	,nome varchar(250)
)Engine=InnoDb;

Agora passei o Engine InnoDb

INSERT INTO descricao (nome) values ('Produto legal');


START TRANSACTION; /*ou BEGIN*/
INSERT INTO descricao (nome) values ('Produto Chato');


Selectzinho basico...

-- Conexão 1:

mysql> SELECT * FROM descricao;
+----+---------------+
| id | nome          |
+----+---------------+
|  1 | Produto legal |
|  2 | Produto Chato |
+----+---------------+
2 rows in set (0.00 sec)

/* Aqui abrimos uma conexão diferente e verificaos que só tem um registro 'Produto legal' isto por que apenas no Engine=InnoDb funciona transactions ....*/
-- Conexão 2: (A diferente dos INSERTS/TRANSACTION)

mysql> SELECT * FROM descricao;
+----+---------------+
| id | nome          |
+----+---------------+
|  1 | Produto legal |
+----+---------------+
2 rows in set (0.00 sec)

tada.jpg




Agora sim..
A alteração só vai entrar quando você efetuar o

 

-- Conexão 1:

COMMIT;


-- Conexão 2: (A diferente dos INSERTS/TRANSACTION) só que agora depois do Commit...

mysql> SELECT * FROM descricao;
+----+---------------+
| id | nome          |
+----+---------------+
|  1 | Produto legal |
|  2 | Produto Chato |
+----+---------------+
2 rows in set (0.00 sec)



Ficou grande pacaralhos husahsa, mas acho q deu pra pegar o conceito...

Resumo de tudo acima para o seu caso é...

  • Reveja a Sintaxe do seu SQL
  • Reveja se ao usar transaction no SQL está com a Engine que da suporte ao mesmo.

PS: Isso não quer dizer que a Engine Myisam é ruim....

Se liga nessa comparação:
http://pt.stackoverflow.com/questions/41672/quais-as-diferenças-entre-myisam-e-innodb


Abraços

Compartilhar este post


Link para o post
Compartilhar em outros sites

Opa agradeço pela resposta, porém eu escrevi apenas como exemplo, e na hora da digitação esqueci de colocar o nome das "tabelas" kkk, mas fiz a correção no topico para não ter problemas futuros.

 

Referente ao tipo de tabela está sim como InnoDb.

 

Pelo phpMyAdmin, consigo sim executar a Transaction com sucesso... Problema que preciso fazer isto via PHP, como citei eu fiz o debug na tabela Pai e ele me gera sim um código mas quando inserimos na segunda tabela já da o erro..

 Cannot add or update a child row: a foreign key constraint fails (`empresas_clientes_conjugue`

Compartilhar este post


Link para o post
Compartilhar em outros sites

Então pode ser o retorno do php.

 

Durante o seu processo, verificou se o código está retornado corretamente?

 

Da uma olhadinha assim:

echo $codigo;
die();

Compartilhar este post


Link para o post
Compartilhar em outros sites

Sim, ele está retornando o código porém o erro está sendo nas tabelas filhas, diz que o código nao existe, de certa maneira o código existe temporariamente mas a lógica deveria funcionar não é?

Compartilhar este post


Link para o post
Compartilhar em outros sites

Deveria funcionar desde que....

Como expliquei acima você trabalhe com apenas uma conexão.

 

Por favor confirme essa informação, porem acredito o problema é que sempre o seu método query

Mysqli->query($query2) 

Você acaba criando uma nova conexão... (reveja o post #5, conexão1, conexão2)

 

Uma maneira de contornar isto seria aplicando o padrão Singleton no seu código.

https://pt.wikipedia.org/wiki/Singleton

 

 

"Você deve ser cauteloso quando for usar o padrão “Singleton” já que pela sua própria natureza ele introduz um estado global na sua aplicação reduzindo a possibilidade de realização de testes. Na maioria dos casos Injeção de Dependências pode (e deve) ser usado no lugar de uma classe do tipo Singleton. Usar Injeção de Dependências significa não introduzir acoplamento desnecessário no design da sua aplicação, já que o objeto usando o recurso global ou compartilhado não necessita de conhecimento sobre uma classe concretamente definida."

 

Links interessantes:

http://php.net/manual/pt_BR/features.persistent-connections.php

http://stackoverflow.com/questions/25515710/singleton-class-and-mysqli-transaction

http://br.phptherightway.com/pages/Design-Patterns.html

Compartilhar este post


Link para o post
Compartilhar em outros sites

×

Informação importante

Ao usar o fórum, você concorda com nossos Termos e condições.