Transações Seguras com PHP+MySQL

530 views
Skip to first unread message

Andrews Lince

unread,
Aug 14, 2009, 2:48:44 PM8/14/09
to LISTA PHP
Pessoal, estou tentando implementar um controle de transações com
MySQL através do PDO, mas não estou conseguindo. Tentei montar meu
banco o mais estruturado possível, com tabelas separadas para cada
campo multivalorado (email, telefone, endereco etc.), de modo que um
usuário possa cadastrar mais de um e-mail e estes registros fiquem em
uma tabela somente de e-mails com a referência deste usuário (id).

Pois bem, depois que é feito o cadastro de usuário, estou pegando esse
id que foi inserido e usando para o cadastro na tabela de e-mail. O
problema é que, ao que me parece, o rollBack não está sendo feito,
pois fiz um teste alterando umas das colunas na 2ª query pra testar se
ele ia ser feito e não funcionou. A 2ª query não é executada, mas a 1ª
é!!! Gostaria de saber se estou esquecendo de alguma coisa ou fazendo
algo de errado. Segue abaixo uma amostra de como estou fazendo.

function PDOCadastrarUsuario($arrayDados){
try{
$conexao = dbConexao::ConectarNoBanco();

//Inicia a transação
$conexao->beginTransaction();

$sql ="insert into usuario (nome, cpf) values (:Nome, :Cpf)";
$sth = $conexao->prepare($sql);
$sth->bindValue(":Nome",$arrayDados['txtNome']);
$sth->bindValue(":Cpf",$arrayDados['txtCpf']);
$sth->execute();

$ultimoId = $conexao->lastInsertId();

$sql2 ="insert into email (idusuario, email) values
(:IdUsuario, :Email)";
$sth = $conexao->prepare($sql2);
$sth->bindValue(":IdUsuario",$ultimoId);
$sth->bindValue(":Email",$arrayDados['txtEmail']);
$result = $sth->execute();

//Commita a transação
$this->dbh->commit();
}catch (PDOException $e){
echo $e;
$this->dbh->rollBack();
}

$this->dbh = null;

if ($result) {
return true;
} else {
return false;
}
}

Valeu pela atenção!!!

Felipe Hlibco

unread,
Aug 15, 2009, 6:47:44 PM8/15/09
to LISTA PHP
Olá Andrews,

como você não passou o schema de criação das suas 2 tabelas, muito
menos do banco, acredito que você esteja trabalhando com tabelas
MyISAM (as quais não possuem suporte a transactions), ao invés de
tabelas InnoDB. Aconselho a dar uma olhada no tipo de tabelas que está
usando, e no padrão do seu banco, pois se ele estiver criando tabelas
MyISAM por padrão, você pode alterá-lo para criar tabelas InnoDB.

Espero ter ajudado,

abraços,

--Felipe Hlibco

Andrews Lince

unread,
Aug 17, 2009, 8:01:15 AM8/17/09
to list...@googlegroups.com
Olá Felipe,

realmente peço desculpas por não ter mencionado isso, mas estou trabalhando com tabelas innoDB. Pra falar a verdade, estava batendo cabeça com esse sistema neste fim de semana e consegui fazer funcionar, mas gostaria que vocês da lista dessem uma olhada, pois não sei se foi a melhor solução. Até mesmo porque, esse é a 1ª vez que eu deixo de trabalhar com tabelas MyISAM e implemento o controle de transações, então ainda sou iniciante nesse assunto. A minha função ficou exatamente como segue abaixo. Se puderem dar sugestões de melhoria, serei muito grato.

function cadastrarUsuarioDAO($arrayDados) {
     $status = false;

     try{
$conexao = Conexao::ConectarNoBanco();

//Inicia o controle de transações
$conexao->beginTransaction();

//Cadastra os dados da tabela 'usuario'
$sql1 = "insert into usuario (nome, cpf, sexo, datanascimento, login, senha) values (:Nome, :Cpf, :Sexo, :DataNascimento, :Login, :Senha)";
$sth1 = $conexao->prepare($sql1);
$sth1->bindValue(":Nome",$arrayDados['txtNome']);
$sth1->bindValue(":Cpf",$arrayDados['txtCpf']);
$sth1->bindValue(":Sexo",$arrayDados['rbtSexo']);
$sth1->bindValue(":DataNascimento",$arrayDados['txtNascimento']);
$sth1->bindValue(":Login",$arrayDados['txtLogin']);
$sth1->bindValue(":Senha",$arrayDados['txtSenha']);
$sth1->execute();
$ultimoIdInserido = $conexao->lastInsertId();

if ($ultimoIdInserido != 0) {
//Cadastra os dados da tabela 'endereco'
$sql2 = "insert into endereco (idusuario, idhospital, idbairro, logradouro, numerocasa, complemento) values (:IdUsuario, :IdHospital, :IdBairro, :Logradouro, ucase(:NumeroCasa), :Complemento)";
$sth2 = $conexao->prepare($sql2);
$sth2->bindValue(":IdUsuario",$ultimoIdInserido);
$sth2->bindValue(":IdHospital",null);
$sth2->bindValue(":IdBairro",$arrayDados['selectBairro']);
$sth2->bindValue(":Logradouro",$arrayDados['selectTipoLogradouro']." ".$arrayDados['txtEndereco']);
$sth2->bindValue(":NumeroCasa",$arrayDados['txtNumero']);
$sth2->bindValue(":Complemento",$arrayDados['txtComplemento']);
if ($sth2->execute()) {
//Cadastra os dados da tabela 'email'
$sql3 = "insert into email (idusuario, idcontatohospital, email) values (:IdUsuario, :IdContatoHospital, lcase(:Email))";
$sth3 = $conexao->prepare($sql3);
$sth3->bindValue(":IdUsuario",$ultimoIdInserido);
$sth3->bindValue(":IdContatoHospital",null);
$sth3->bindValue(":Email",$arrayDados['txtEmail']);
if ($sth3->execute()) {
//Cadastra os dados da tabela 'telefone'
$sql4 = "insert into telefone (idusuario, idcontatohospital, telefone) values (:IdUsuario, :IdContatoHospital, :Telefone)";
$sth4 = $conexao->prepare($sql4);
$sth4->bindValue(":IdUsuario",$ultimoIdInserido);
$sth4->bindValue(":IdContatoHospital",null);
$sth4->bindValue(":Telefone",$arrayDados['txtTelefone']);
if ($sth4->execute()) {
//Verifica o perfil de usuário informado
switch ($arrayDados['selectTipoUsuario']) {
case "1" :  //Perfil 'Médico'
//Cadastra os dados da tabela 'usuariomedico'
$sql5 = "insert into usuario_medico (idusuario, crm, especialidade) values (:IdUsuario, :Crm, :Especialidade)";
$sth5 = $conexao->prepare($sql5);
$sth5->bindValue(":IdUsuario",$ultimoIdInserido);
$sth5->bindValue(":Crm",$arrayDados['txtCrm']);
$sth5->bindValue(":Especialidade",$arrayDados['txtEspecialidade']);
break;
default :   //Outros perfis
//Cadastra os dados da tabela 'usuariogeral'
$sql5 = "insert into usuario_geral (idusuario, idtipousuario) values (:IdUsuario, :IdTipoUsuario)";
$sth5 = $conexao->prepare($sql5);
$sth5->bindValue(":IdUsuario",$ultimoIdInserido);
$sth5->bindValue(":IdTipoUsuario",$arrayDados['selectTipoUsuario']);
break;
}
if ($sth5->execute()) {
$status = true;
}
}
}
}
}
if ($status) {
//Commita a transação
$conexao->commit();
} else {
//Cancela a transação
$conexao->rollBack();
}
}catch (PDOExecption $e){
echo "erro: ".$e;
$conexao->rollBack();
}
$conexao = null;
return ($status) ? true : false;
}


Valeu!!!!!!!!

2009/8/15 Felipe Hlibco <hli...@gmail.com>
Reply all
Reply to author
Forward
0 new messages