2011-11-14 49 views
-2

我目前使用PHP,ORACLE,PDO和JNDI的組合將我的應用程序連接到數據庫。我無法理解以面向對象的方式管理連接池的最佳方法。因此,當我嘗試執行批量插入(32插入以上(我的最大池大小設置爲))時,我會收到最大連接警告。PHP:面向對象方法管理連接池

考慮這個例子:

Main File: 
//User uploads excel document which I parse into an array 
$car = array(); 
foreach($array as $index => $data){ 
    $car[$index] = new Car(null,$data["make"],$data["model"]); 
    $car[$index]->insert(); 
} 
//return car array of objects 

在類別:

//Car Class 
class Car{ 

    protected $pkey; 
    protected $make; 
    protected $model; 
    protected $db; 

    public function __construct($pkey,$make,$model){ 
     $this->pkey = $pkey; 
     if(isset($make) && ($make != '')){ 
      $this->make = $make; 
     }else{ 
      throw new Exception("Car must have make"); 
     } 
     if(isset($model) && ($model != '')){ 
      $this->model = $model; 
     }else{ 
      throw new Exception("Car must have model"); 
     } 
     $this->db = new Database(); 
    } 

    public function insert(){ 
     $sql = "INSERT INTO TABLE (...) VALUES (..)"; 
     $data = array(
      ":make"=>$this->make, 
      ":model"=>$this->model, 
     ); 
     try{ 
      $this->pkey = $this->db->insert($sql,$data); 
      return true; 
     }catch(Exception $err){ 
      //catch errors 
      return false; 
     } 
    } 
} 

在這個例子中,假設最大池被設置爲32,任何陣列大於32將導致我超過最大池大小,因爲每個汽車對象都與活動數據庫連接一起存儲。爲了解決這個問題,我嘗試了對這個類實現以下修復。

//Car Class 
class Car{ 

    protected $pkey; 
    protected $make; 
    protected $model; 
    protected $db; 

    public function __construct($pkey,$make,$model){ 
     $this->pkey = $pkey; 
     if(isset($make) && ($make != '')){ 
      $this->make = $make; 
     }else{ 
      throw new Exception("Car must have make"); 
     } 
     if(isset($model) && ($model != '')){ 
      $this->model = $model; 
     }else{ 
      throw new Exception("Car must have model"); 
     } 
     //$this->db = new Database(); //Moved out of the constructor 
    } 

    public function insert(){ 
     $this->establishDBConn(); 
     $sql = "INSERT INTO TABLE (...) VALUES (...)"; 
     $data = array(
      ":make"=>$this->make, 
      ":model"=>$this->model, 
     ); 
     try{ 
      $this->pkey = $this->db->insert($sql,$data); 
      $this->closeDBConn(); 
      return true; 
     }catch(Exception $err){ 
      //catch errors 
      $this->closeDBConn(); 
      return false; 
     } 
    } 

    protected function establishDBConn(){ 
     if(!$this->db){ 
      $this->db = new Database(); 
     } 
    } 

    public function closeDBConn(){ 
     if($this->db){ 
      $this->db->close(); 
      $this->db = null; 
     } 
    } 
} 

理論上這種改變應該強制在實際插入過程中只保持一個活動的連接。但是,通過此更改,我繼續達到最大連接池限制。作爲最後的努力,我將所有插入邏輯移出汽車類並創建了批量插入功能。這個函數忽略了一個對象的概念,它只是接收一個數據數組,它循環並插入到單個數據連接中。這很有效,但我很想找到一種方法來解決我在面向對象編程約束中的問題。

有關如何改進我的代碼以便更有效地使用對象和數據庫連接的任何建議?

僅供參考這是我的數據庫類的樣子:

class Database { 

    protected $conn; 
    protected $dbstr; 

    public function __construct() { 
     $this->conn = null; 
     $this->dbstr = "jndi connection string"; 
     $this->connect(); 
    } 

    public function connect(){ 
     try{ 
      $this->conn = new PDO($this->dbstr); // Used with jndi string 
     } catch (PDOException $e){ 
      //  print $e->getMessage(); 
     } 
     return ""; 
    } 

    public function insert($query, $data){ 
     try{ 
      $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
      /* Execute a prepared statement by passing an array of values */ 
      $sth = $this->conn->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); 
      $count = $sth->execute($data); 
      return $this->oracleLastInsertId($query); 
     }catch(PDOException $e){ 
      throw new Exception($e->getMessage()); 
     } 
    } 
    public function oracleLastInsertId($sqlQuery){ 
     // Checks if query is an insert and gets table name 
     if(preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $sqlQuery, $tablename)){ 
      // Gets this table's last sequence value 
      $query = "select ".$tablename[1]."_SEQ.currval AS last_value from dual"; 
      try{ 
       $temp_q_id = $this->conn->prepare($query); 
       $temp_q_id->execute(); 
       if($temp_q_id){ 
        $temp_result = $temp_q_id->fetch(PDO::FETCH_ASSOC); 
        return ($temp_result) ? $temp_result['LAST_VALUE'] : false; 
       } 
      }catch(Exception $err){ 
       throw new Exception($err->getMessage()); 
      } 
     } 
     return false; 
    } 

    public function close(){ 
     $this->conn = null; 
    } 
} 
+0

剛看了介紹,但是你是否真的爲每一個單獨的插入使用不同的連接? (或者爲什麼你在32個插入後沒有連接?)那就是......廢話^^ – KingCrunch

回答

0

正確的做法似乎是使用基於單數據庫類這樣:

class Database { 

    protected $conn; 
    protected $dbstr; 

    // keep the one and only instance of the Database object in this variable 
    protected static $instance; 

    // visibility changed from public to private to disallow dynamic instances 
    private function __construct() { 
     $this->conn = null; 
     $this->dbstr = "jndi connection string"; 
     $this->connect(); 
    } 

    // added this method 
    public static function getInstance() { 
     if (!isset(self::$instance)) { 
     self::$instance = new Database(); 
     } 
     return self::$instance; 
    } 

    // everything below this comment is as it was; I made no changes here 
    public function connect(){ 
     try{ 
      $this->conn = new PDO($this->dbstr); // Used with jndi string 
     } catch (PDOException $e){ 
      //  print $e->getMessage(); 
     } 
     return ""; 
    } 

    public function insert($query, $data){ 
     try{ 
      $this->conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); 
      /* Execute a prepared statement by passing an array of values */ 
      $sth = $this->conn->prepare($query, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY)); 
      $count = $sth->execute($data); 
      return $this->oracleLastInsertId($query); 
     }catch(PDOException $e){ 
      throw new Exception($e->getMessage()); 
     } 
    } 
    public function oracleLastInsertId($sqlQuery){ 
     // Checks if query is an insert and gets table name 
     if(preg_match("/^INSERT[\t\n ]+INTO[\t\n ]+([a-z0-9\_\-]+)/is", $sqlQuery, $tablename)){ 
      // Gets this table's last sequence value 
      $query = "select ".$tablename[1]."_SEQ.currval AS last_value from dual"; 
      try{ 
       $temp_q_id = $this->conn->prepare($query); 
       $temp_q_id->execute(); 
       if($temp_q_id){ 
        $temp_result = $temp_q_id->fetch(PDO::FETCH_ASSOC); 
        return ($temp_result) ? $temp_result['LAST_VALUE'] : false; 
       } 
      }catch(Exception $err){ 
       throw new Exception($err->getMessage()); 
      } 
     } 
     return false; 
    } 

    public function close(){ 
     $this->conn = null; 
    } 
}