Ir para conteúdo

Arquivado

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

carlosasjr

Transação com SingleTon

Recommended Posts

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

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

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
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

×

Informação importante

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