carlosasjr 0 Denunciar post Postado Dezembro 1, 2018 Senhores, Este é o meu primeiro post neste forúm... O Problema é o seguinte: Tenho uma conexão PDO no padrão SingleTon, porém não consigo controlar as transações. Se inicio uma transação e executo dois updates, sendo que o primeiro esta tudo correto e o segundo forçando um erro, mesmo caindo no roolback o primeiro update é commitado.. Segue a baixo todos os códigos: <?php /** * TConn.class [ CONEXÃO ] * Classe abstrata de conexão. Padrão SingleTon. * Retorna um objeto PDO pelo método estático getConn(); * @copyright (c) 2018, Carlos Junior */ abstract class TConn { private static $Host = HOST; private static $User = USER; private static $Pass = PASS; private static $Dbsa = DBSA; private static $Type = TYPE; /** @var PDO */ private static $Connect = null; /* * ************************************************ */ /* * ************* METODOS PRIVADOS ***************** */ /* * ************************************************ */ /** * Conecta com o banco de dados com o pattern singleton. * Retorna um objeto PDO! */ private static function Conectar() { try { if (self::$Connect == null) : switch (self::$Type) { case 'mysql': $dsn = 'mysql:host=' . self::$Host . ';dbname=' . self::$Dbsa; $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8']; self::$Connect = new PDO($dsn, self::$User, self::$Pass, $options); break; case 'sqlite': $dsn = 'sqlite:' . self::$Dbsa; self::$Connect = new PDO($dsn); case 'ibase': $dsn = 'firebird:dbname=' . self::$Dbsa; self::$Connect = new PDO($dsn, self::$User, self::$Pass); break; default: $dsn = 'mysql:host=' . self::$Host . ';dbname=' . self::$Dbsa; $options = [PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES UTF8']; self::$Connect = new PDO($dsn, self::$User, self::$Pass, $options); break; } endif; } catch (PDOException $e) { PHPErro($e->getCode(), $e->getMessage(), $e->getFile(), $e->getLine()); } self::$Connect->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); return self::$Connect; } /** Retorna um objeto PDO Singleton Pattern. */ protected static function getConn() { return self::Conectar(); } /* * ************************************************ */ /* * ************* METODOS PUBLICOS ***************** */ /* * ************************************************ */ } <?php /** * TConn.class [ TRANSAÇÃO ] * Classe final de Transação. * Inicia uma transação no banco de dados * @copyright (c) 2018, Carlos Junior */ final class TTransaction extends TConn { /* * ************************************************ */ /* * ************* METODOS PRIVADOS ***************** */ /* * ************************************************ */ /** @var PDO */ private static $Conn; /* Método __construct() * Está declarado como private para impedir que se crie uma instância de TTransaction */ private function __construct() {} /* * ************************************************ */ /* * ************* METODOS PUBLICOS ***************** */ /* * ************************************************ */ public static function Open() { if (empty(self::$Conn)): self::$Conn = parent::getConn(); endif; self::$Conn->beginTransaction(); } public static function Get() { return self::$Conn; } public static function Rollback() { if (self::$Conn): self::$Conn->rollBack(); self::$Conn = NULL; endif; } public static function Close() { if (self::$Conn): self::$Conn->commit(); self::$Conn = NULL; endif; } } <?php /** * TSQLUpdate.class [ SQLInstruction ] * Esta classe provê meios para manipulação de uma instrução de UPDATE no banco de dados * @copyright (c) 2018, Carlos Junior */ class TSQLUpdate extends TSqlInstruction { private $Dados; // Array com o Dados para Instrução public $Result; /* * ************************************************ */ /* * ************* METODOS PRIVADOS ***************** */ /* * ************************************************ */ /** <b>Metodo getInstruction</b> * Retorna a instrução de UPDATE em forma de string * @return string Instrução SQL- UPDATE * */ protected function getInstruction() { $this->Sql = "UPDATE {$this->Entity}"; //monta os pares; coluna=valor,... if ($this->Dados): foreach ($this->Dados as $column => $value) { $set[] = "{$column} = :{$column}"; } $this->Sql .= ' SET ' . implode(', ', $set); //retorna a clausula WHERE do objeto $this->Criterio if ($this->Criterio): $this->Sql .= ' WHERE ' . $this->Criterio->dump(); endif; endif; } /* * ************************************************ */ /* * ************* METODOS PUBLICOS ***************** */ /* * ************************************************ */ /** <b>Metodo __construct</b> * Instancia um novo objetio do tipo SQLUpdate * @param String $Entity = 'Nome da Tabela' * @param Array $Dados = Array associativo com os dados a serem alterados [campo => valor] * */ public function __construct($Entity, $Dados, TCriterio $Criterio) { $this->Entity = (string) $Entity; $this->Dados = (array) $Dados; if (!$Criterio): WSErro("<b>Critério do objeto TSQLUpdate não foi informado:</b>", 999); die; else: $this->setCriterio($Criterio); endif; } /** <b>Metodo Execute</b> * Executa uma instrução UPDATE no banco de dados * @return Result = Retorna na propriedade [Result] se os dados foram alterados [True ou False] * */ public function Execute() { $this->getInstruction(); parent::Connect(); try { parent::$Statement->execute($this->Dados); $this->Result = True; } catch (PDOException $e) { WSErro("<b>Erro ao executar a atualização:</b> {$e->getMessage()}", $e->getCode()); } } } <?php include_once './PROJETO/APP.CONFIG/Config.inc.php'; try { TTransaction::Open(); $conn = TTransaction::Get(); $famosos = ['nome' => 'Samuel Henrique']; $criterio = new TCriterio(); $criterio->add(new TFilter('codigo', '=', 8)); $update = new TSQLUpdate('famosos', $famosos, $criterio); $update->Execute(); if ($update->Result): echo "1 update Alterado com sucesso.."; endif; $famosos = ['nome_' => 'Maria Eugenia dos Santos']; $criterio = new TCriterio(); $criterio->add(new TFilter('codigo', '=', 7)); $update = new TSQLUpdate('famosos', $famosos, $criterio); $update->Execute(); if ($update->Result): echo "2 update Alterado com sucesso.."; endif; TTransaction::Close(); } catch (Exception $exc) { TTransaction::Rollback(); echo $exc->getTraceAsString(); } Compartilhar este post Link para o post Compartilhar em outros sites
Williams Duarte 431 Denunciar post Postado Dezembro 2, 2018 Os inserts/updates e query executados dentro da própria transação: try { $pdo->beginTransaction(); ... $pdo->commit(); } sempre serão bem sucedidos. Ou seja sempre vai retornar TRUE Correto e que esteja fora do bloco try{} a transaction $pdo->beginTransaction(); try { // insert/update query $pdo->commit(); } catch (PDOException $e) { $pdo->rollBack(); } Desta forma você pode forçar os erros com a PDOException() throw new PDOException('bla bla bla') Compartilhar este post Link para o post Compartilhar em outros sites
carlosasjr 0 Denunciar post Postado Dezembro 3, 2018 Amigo, fiz da forma que sugeriu, mas deu na mesma, o primeiro update foi executado apesar do erro do segundo.. Compartilhar este post Link para o post Compartilhar em outros sites
Williams Duarte 431 Denunciar post Postado Dezembro 4, 2018 Como eu disse, você pode forçar os erros com throw new PDOException Poste a Classe TCriterio Provavelmente você não está forçando o erro na classe encapsulada "TCriterio". Tem que forçar o retorno do erro para a transação ser negada. Compartilhar este post Link para o post Compartilhar em outros sites
carlosasjr 0 Denunciar post Postado Dezembro 4, 2018 3 hours ago, Williams Duarte said: Como eu disse, você pode forçar os erros com throw new PDOException Poste a Classe TCriterio Provavelmente você não está forçando o erro na classe encapsulada "TCriterio". Tem que forçar o retorno do erro para a transação ser negada. Amigo, resolvido, na verdade o problema estava no banco de dados, não estava como InnoDB e eu não tinha percebido.. Agradeço a ajuda... Compartilhar este post Link para o post Compartilhar em outros sites