【问题标题】:Is it possible to do an sql transaction across multiple function into one?是否可以将跨多个功能的 sql 事务合二为一?
【发布时间】:2016-09-02 03:01:56
【问题描述】:

我在另一个函数中使用了一些函数来更新某些内容、删除一些内容并插入,现在我的问题是,如果上面的 2 成功或 1 没有成功,则可能会导致灾难性的结果。那么是否可以对所有 3 个功能使用 1 个事务...例如:

public static function do_stuff()
{
    //run sql in function
    SELF::function_sql_one_insert();

    SELF::function_sql_two_update();

    SELF::function_sql_three_delete();
}

像这样:

public static function test()
{
    SELF::function_sql_one_insert();

    SELF::function_sql_two_update();

    SELF::function_sql_three_delete();
}

public static function function_sql_one_insert()
{
    //sql to run
    $sql = "INSERT INTO table
            (
                fake_row_one,
                fake_row_two
            )
            VALUES
            (
                ?,
                ?
            )";

    //run sql
    $fake_insert = $database->prepare($sql);
    $fake_insert->execute("yeah", "okay");
}

public static function function_sql_two_update()
{
    //sql to run
    $sql = "UPDATE table
            SET fake_row_one = ?
            WHERE fake_row_two = ?";

    //run sql
    $fake_update = $database->prepare($sql);
    $fake_update->execute("blahblah", "okay");
}

public static function function_sql_three_delete()
{
    //sql to run
    $sql = "DELETE FROM TABLE
            WHERE fake_row_two = ?";

    //run sql
    $fake_delete = $database->prepare($sql);
    $fake_delete->execute("okay");
}

我想要完成的是,如果一个失败将它们全部还原。这可能吗?如果不是,我该怎么办,如果可以,这样做有什么缺点吗?

【问题讨论】:

  • 是的,您应该能够在运行函数之前启动事务并在之后提交。您可以使内部函数返回布尔成功指标,并在需要时根据这些指标回滚。
  • 我应该在 main 函数中开始事务还是在我正在做 sql 的三个函数中开始事务?
  • 对此没有通用答案,这取决于您的需求。例如,您是否可能希望调用test() 作为已经开始的一些较大事务的一部分?那么你不应该在那里开始交易。
  • 这只是我的看法,但如果不执行所有三个操作可能会导致灾难性结果,我不想创建任何一开始就只执行其中一个的函数。

标签: php pdo


【解决方案1】:

PHP 函数与数据库事务完全无关。这只是无关紧要的事情。

数据库事务仅绑定到数据库连接。因此,只要你所有的函数都使用相同的连接,在一个事务中运行这三个函数是没有问题的。

【讨论】:

    【解决方案2】:

    您应该为此使用数据库事务。

    基本上,

    1. 您开始交易,
    2. 您执行 SQL 查询
    3. 如果某处失败,则执行回滚,否则执行提交

    但是有一些问题,例如某些 sql 语句会自行提交,因此请阅读您正在使用的数据库的所有官方文档。

    更多信息:http://php.net/manual/en/pdo.begintransaction.php

    但请记住,并非所有数据库一开始都支持事务。 例如。 MySQL 中的 MyISAM 表不支持事务。

    您可能希望将这些表转换为 InnoDB,请参见此处,例如:How to convert all tables from MyISAM into InnoDB?

    【讨论】:

      【解决方案3】:

      我是这样用的:

      class Teste {
      public $mysqli;
      public $erro = array();
      
              public function __construct(){
              $this->mysqli = new \mysqli(DB_HOST,DB_USERNAME,DB_PASSWORD,DATABASE);
              $this->mysqli->set_charset("utf8");
              }
      
              public function start_trans(){
                   $this->mysqli->autocommit(false);
              }
      
              public function end_trans(){
      
                  if(count($this->erro) == 0){
                  $this->mysqli->commit();
                  echo "success";
                  } else {
                  $this->mysqli->rollback();
                  echo "error";
                  }
      
              }
      
      
              public function example1(){
      
                  $stmt = $this->mysqli->query("insert into veiculos (placa, modelo) values (1,1)");
      
                  if(!$stmt){
                  $this->erro[] = "Erro #143309082017 <code>" . $this->mysqli->error . "</code>";
                  }
      
                  return (count($this->erro) < 1)? true : false;
      
              }
      
      
              public function example2(){
      
                  $stmt = $this->mysqli->query("insert into veiculos (placa, modelo) values (2,2)");
      
                  if(!$stmt){
                  $this->erro[] = "Erro #143309082017 <code>" . $this->mysqli->error . "</code>";
                  }
      
                  return (count($this->erro) < 1)? true : false;
      
              }
      
      
              public function example3(){
      
                  $this->mysqli->autocommit(false);
      
                  $stmt = $this->mysqli->query("insert into veiculos (placa, modelo) values (3,3)");
      
                  if(!$stmt){
                  $this->erro[] = "Erro #143309082017 <code>" . $this->mysqli->error . "</code>";
                  }
      
                  return (count($this->erro) < 1)? true : false;
      
              }
      }
      
      
              $action = new Teste;
      
              $action->start_trans();
      
              $action->example1();
              $action->example2();
              $action->example3();
      
              $action->end_trans();
      

      【讨论】:

        【解决方案4】:

        也许你可以试试这样的:

        $working = true;
        try
        {
             SELF::function_sql_one_insert();
        } catch (Exception $e)
        {
            if($e != "")
                $working = false;
        }
        

        尝试所有功能。如果 $working 为 true,则可以执行所有命令。

        【讨论】:

        • 我不认为try...catch 是数据库事务的有用替代品。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多