2015-10-26 37 views
4

當我通過PHP mysqli API在PHP進程中對Windows上的預準備語句執行簡單插入時,定義的AUTO_INCREMENT列將增加2而不是1:Windows上的PHP/MySQLi:插入到MySQL innoDB表中將AUTO_INCREMENT列增加2

INSERT INTO `table` (`name`) VALUES (?) 

在一個PHP進程中執行多次插入(逐個事務)時,它會增加1。

當我通過phpmyadmin使用相同的SQL查詢時,它總是會增加1。

在上述INSERT之前或之後沒有其他INSERTUPDATE陳述。以前只有一個SHOW和一些SELECT陳述。

我找不到這個問題的原因。造成這種行爲的原因是什麼?

這裏主要代碼部分:

<?php 

class DB 
{ 
    private function __construct($host, $username, $password, $schema, $port, $socket) 
    { 
     if(is_null(self::$DB)) 
     { 
      self::$DB = new \MySQLi((string) $host, (string) $username, (string) $password, (string) $schema, (int) $port, (string) $socket); 
      self::$DB->set_charset('utf8'); 

     } 
    } 
    // [...] 
    public function __destruct() 
    { 
     if(!is_null(self::$DB)) 
      self::$DB->close(); 
    } 
    // [...] 
    public static function connect($host = '', $username = '', $password = '', $schema = '', $port = 0, $socket = '') 
    { 
     if(is_null(self::$instance)) 
     { 
      $MD = new \MySQLi_driver(); 
      $MD->report_mode = MYSQLI_REPORT_ERROR | MYSQLI_REPORT_STRICT; 
      // [...] 
      self::$instance = new self($host, $username, $password, $schema, $port, $socket); 
     } 

     return self::$instance; 
    } 
    // [...] 
    public static function __callStatic($name, $args) 
    { 
     self::connect(); 

     switch(true) 
     { 
      case in_array($name, array('insert', 'select', 'update', 'delete', 'show', 'describe', 'explain')): 

      $query = isset($args[0]) ? (string) $args[0] : ''; 
      $vals = isset($args[1]) ? $args[1] : array(); 
      $select = isset($args[2]) ? trim((string) $args[2]) : 'array'; 
      $empty = isset($args[3]) ? $args[3] : array(); 
      $types = isset($args[4]) ? trim((string) $args[4]) : ''; 

      return self::dml(in_array($name, array('show', 'describe', 'explain')) ? 'select' : $name, $query, $vals, $select, $empty, $types); 

      break; 
     } 
    //[...] 
    } 

    // [...] 
    public static function dml($type, $query, $vals = array(), $select = 'array', $empty = array(), $types = '') 
    { 
     // [...] 
     if(!empty($vals) || mb_strpos($query,'?') !== false) 
     { 
      if(!$stmt = self::$DB->prepare($query)) 
       throw new DBException('Failed to prepare statement '.htmlspecialchars($query).PHP_EOL.self::$DB->error.' ('.self::$DB->sqlstate.').'); 

      $args = array(); 

      if(empty($types)) 
      { 
       foreach($vals as &$val) 
       { 
        $t = gettype($val); 

        if($t == 'string' || $t == 'NULL') 
         $types.= 's'; 
        elseif($t == 'integer' || $t == 'boolean') 
         $types.= 'i'; 
        elseif($t == 'double' || $t == 'float') 
         $types.= 'd'; 
        else 
         throw new DBException('Its not possible to automatically assign a value of type '.$t.'. Please specify the corresponding types manually.'); 
        $args[] = $val; 
       } 
      } 
      else 
      { 
       foreach($vals as &$val) 
        $args[] = $val; 
      } 

      array_unshift($args, $types); 

      $RC = new \ReflectionClass($stmt); 

      $RM = $RC->getMethod('bind_param'); 

      if(!$RM->invokeArgs($stmt, $args)) 
       throw new DBException('Failed to bind params.'.PHP_EOL.self::$DB->error.' ('.self::$DB->sqlstate.').'); 

      if(!$stmt->execute()) 
       throw new DBException('Failed to execute Statement.'.PHP_EOL.self::$DB->error.' ('.self::$DB->sqlstate.').'); 

      if($type == 'select') 
      { 
       // [...] 
      } 
      else 
      { 
       $return = $type == 'insert' && self::$DB->insert_id > 0 ? self::$DB->insert_id : self::$DB->affected_rows; 
       $stmt->close(); 
       return $return; 
      } 
     } 
     else 
     { 
      // [...] 
     } 
    } 
} 
?> 

AND:

echo DB::insert("INSERT INTO `table` (`name`) VALUES (?)", ["test"]); 

該查詢日誌顯示2個插入。這會導致額外的增量。但是,當我把回聲放入相應的DB :: dml() - 方法中時,它只輸出一次,因此調用一次。 mysql-query-log:

151026 12:54:49  3 Connect [email protected] on XXX 
3 Query SET NAMES utf8 
     3 Query SELECT DATABASE() AS `schema` 
     3 Query SHOW GRANTS FOR CURRENT_USER 
     3 Prepare INSERT INTO `table` (`name`) VALUES (?) 
     3 Execute INSERT INTO `table` (`name`) VALUES ('testinsert22') 
     3 Close stmt  
     3 Quit 
     4 Connect [email protected] on XXX 
     4 Query SET NAMES utf8 
     4 Query SELECT DATABASE() AS `schema` 
     4 Query SHOW GRANTS FOR CURRENT_USER 
     4 Prepare INSERT INTO `table` (`name`) VALUES (?) 
     4 Execute INSERT INTO `table` (`name`) VALUES ('testinsert22') 
     4 Close stmt  
     4 Quit 
+0

請向我們展示完整的PHP腳本。 – wkyip

回答

0

好的。我終於明白了。 問題是:我將所有請求重定向到我的index.php,並使用PHP完成所有其他請求。我用簡單的輸出測試了一些類的行爲。其中一項測試導致了上述問題。 我檢查了Apache訪問日誌並注意到重複的favicon.ico請求。這些請求 - 由主流瀏覽器自動生成(另請參閱How to prevent favicon.ico requests?) - 也涉及到index.php - 並且看起來像重定向到瀏覽器? 通常這都是在我的應用程序框架中處理的,但我在測試時禁用了它。