mysqli_rollback不回滚从临时表执行的语句时出错

Error when mysqli_rollback does not roll back statements executed from a temporary table

提问人:Jorge Palacios Zaratiegui 提问时间:10/31/2023 最后编辑:ADysonJorge Palacios Zaratiegui 更新时间:10/31/2023 访问量:57

问:

我正在尝试使用临时表和非临时计算机表执行一系列操作。 我希望它们都在一个事务中执行。

我正在测试回滚是否正常工作,方法是使用 throw new Exception('force rollback');

但是,注册始终在 machines 表中进行(它没有像我预期的那样反转)。mysqli_rollback的结果为 1。

这可能正在发生吗?

法典:

<?php 
session_start();
include_once("../utils/system_utils.php");
include_once("../models/Maquina.php");
include_once("../models/Temp.php");

set_time_limit(300);

$error      = "";
$id         = null;
// Parametros de respuesta
$success    = 0;
$message    = '';
$data       = [];

$id_maquina         = post('id_maquina');
$nombre_anterior    = post('nombre_anterior');
$nombre             = post('duplicate_name');
$reuso     = post('reuso');

registrarLog("[utils - duplicar_maquina] - POST: ".json_encode(filter_input_array(INPUT_POST)));

$conexion = db_connect();
mysqli_begin_transaction($conexion);
try {


    $query = "CREATE TEMPORARY TABLE tmp_dup SELECT * from maquinas WHERE id = ?";
    registrarLog("Params: $id_maquina - $query [Maquinas::createMaquinaTemporal]", DEBUG);
    $stmt = mysqli_prepare($conexion, $query);
    mysqli_stmt_bind_param($stmt, 'i', $id_maquina);
    if (!mysqli_stmt_execute($stmt)){
        throw new Exception(gettext('Los datos no han podido ser guardados'));
    }



    $query = "ALTER TABLE tmp_dup drop id";  
    registrarLog("$query [Temp::borrarCampoID]", DEBUG);
    $stmt = mysqli_prepare($conexion, $query);    
    if(!mysqli_stmt_execute($stmt)) {
        throw new Exception(gettext('Los datos no han podido ser guardados'));
    }


        $query = "UPDATE tmp_dup SET nombre = ?, "
                    ."estado = 0, "
                    ."accion = NULL, "
                    ."mensaje = NULL, "
                    ."fecha_estado = NULL, "
                    
                    ."fecha_alta = CURRENT_TIMESTAMP, "
                    ."fecha_actualizacion = NULL, "
                    ."fecha_lectura = NULL, "
                    ."fecha_comm = NULL, ";

        if (!$reuso){
            $query .= "ip = NULL, "
                    ."imei = CONCAT(imei, '2'), ";
        }

        $query .= "fecha_ultima_venta = NULL, "
                    ."version = '0.0.0', "
                    ."initialized = '0', "
                    ."price_changed = '0', "
                    ."unions_changed = '0', "
                    ."tft_changed = '0', "
                    ."lcd_changed = '0', "
                    ."version_changed = '0', "
                    ."coverage = NULL, "
                    ."banda = NULL, "
                    ."operador = NULL";

        registrarLog("Params: $nombre, $query [Temp::borrarCampoID]", DEBUG);
        $stmt = mysqli_prepare($conexion, $query);
        mysqli_stmt_bind_param($stmt, 's', $nombre);
        if(! mysqli_stmt_execute($stmt)){
            throw new Exception(gettext('Los datos no han podido ser guardados'));
        }



        $id = false;        
        $query = 'INSERT INTO maquinas SELECT 0, tmp_dup.* FROM tmp_dup';
        registrarLog("$query [Maquinas::createMaquinaDesdeTemp]", DEBUG);

        $stmt = mysqli_stmt_init($conexion);                
        mysqli_stmt_prepare($stmt, $query);
        if (mysqli_stmt_execute($stmt)){
            $id = mysqli_insert_id($conexion);
        }

        if(!$id){
            registrarLog('ERR - No se ha podido registrar la maquina temporal. Error: '.mysqli_stmt_error($stmt). '- [Maquina::createMaquinaDesdeTemp]');
        }
        else {
            registrarLog('Se ha registrado la maquina temporal. ID = '.$id. '- [Maquina::createMaquinaDesdeTemp]');
        } 

        if(!$id){
            throw new Exception(gettext('Los datos no han podido ser guardados'));
        } 
        

        throw new Exception('fuerzo el rollback');
        mysqli_commit($conexion);

    
} catch (\Exception $e) {
    registrarLogRedFlag("EXC - Se ha producido un error al duplicar la maquina (id = $id_maquina): Revisar posible inconsistencia en los datos.");
    $message = $e->getMessage();
    $rroll = mysqli_rollback($conexion);
    registrarLogRedFlag("rroll: ".$rroll);

}


echo getResponseArray($success, $message, $data);


php mysql mysqli 事务

评论

2赞 ADyson 10/31/2023
在你(或)命令之前添加,这将确保你的SQL查询的错误被正确地报告给PHP(在你的情况下,你的try/catch将捕获)。这样一来,你就不需要用重复的代码来弄乱你的脚本,以在mysqli命令之后继续检查错误(无论如何,你距离涵盖所有可能发生故障的命令还有很长的路要走)。mysqli_report(MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT);mysqli_connect()new mysqli()
0赞 Jorge Palacios Zaratiegui 10/31/2023
@shingo 它处于活动状态。激活时,不能保证一组 sql 命令都正确执行。甚至没有在启动时运行mysqli_begin_transaction对吧?
2赞 ADyson 10/31/2023
确定。。。但是在开发模式下,这无关紧要,您可以显示错误。在实时环境中,无论如何,您都会将所有 PHP 错误重定向到日志文件,因此在这种情况下,确切的 SQL 错误也永远不会出现。而且,至少在这种情况下,无论如何你都会捕捉到异常。
3赞 user1191247 10/31/2023
我认为您正在导致隐式提交,之后没有要回滚的活动事务。导致隐式提交的语句ALTER TABLE
2赞 user1191247 10/31/2023
自动提交状态是什么并不重要,因为当您显式启动事务时,它会有效地暂停,直到提交或回滚(显式或隐式)发生。

答: 暂无答案