這個數據庫類主要處理了單例模式下建立數據庫對象時,若是有兩次較長時間的間隔去執行sql操做,再次處理會出現鏈接失敗的問題,利用一個cache數組存放pdo對象與時間戳,把兩次執行之間的時間進行了比較,若是間隔超過了10秒就再次new PDO建立鏈接,沒有超過的狀況下會繼續使用原來的鏈接,而且由於每次使用後會使鏈接續期,cache數組裏的時間戳也進行了續期.
每次執行操做都會從cache數組中獲取下鏈接,屢次執行不超過10秒的狀況下,只會有一個鏈接php
代碼中實現讀寫分離,判斷sql語句前面6個字符是select的就查詢從庫,其他操做查詢主庫.主庫和從庫就是分別在配置數組中0和1建立不一樣的PDO對象鏈接mysql
代碼以下:sql
<?php class SinaPdoAdapter{ const MASTER = 0; const SLAVE = 1; const DEFAULT_CACHE_EXPIRETIME = 10; private static $options = array( PDO::ATTR_AUTOCOMMIT => true, PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, //PDO::ATTR_PERSISTENT => true, ); private $dsn = null; private $username = null; private $password = null; private $timeout = null; private $charset = null; private $conns = array(); private $conn = null; private $stmt = null; private static $obj=null; private function __construct($dsn, $username, $password, $timeout = null, $charset = null){ $this->dsn = $dsn; if (!is_array($username)) { $this->username = array($username); } else { $this->username = $username; } if (!is_array($password)) { $this->password = array($password); } else { $this->password = $password; } $this->timeout = intval($timeout); $this->charset = $charset; } private function getConnection($id = self::MASTER){ if (!isset($this->dsn[$id])) { $id = self::MASTER; } $conn = $this->getCachedConn($id); if ($conn) { return $conn; } $opts = self::$options; if ($this->timeout > 0) { $opts[PDO::ATTR_TIMEOUT] = $this->timeout; } $username = isset($this->username[$id]) ? $this->username[$id] : $this->username[self::MASTER]; $password = isset($this->password[$id]) ? $this->password[$id] : $this->password[self::MASTER]; $conn = new PDO($this->dsn[$id], $username, $password, $opts); $this->cacheConn($id, $conn); if ($this->charset) { $conn->exec('set names ' . $this->charset); } return $conn; } public function execute($sql, $params = array()){ $cmd = substr($sql, 0, 6); if (strcasecmp($cmd, 'select') === 0) { $conn = $this->getConnection(self::SLAVE); } else { $conn = $this->getConnection(self::MASTER); } $stmt = $conn->prepare($sql); $stmt->execute($params); $this->stmt = $stmt; $this->conn = $conn; } public function fetch(){ return $this->stmt->fetch(); } public function fetchAll(){ return $this->stmt->fetchAll(); } public function lastInsertId(){ return $this->conn->lastInsertId(); } public function rowCount(){ return $this->stmt->rowCount(); } public static function getInstance($conf){ if(self::$obj == null){ self::$obj = new self($conf->dsn,$conf->username,$conf->password,$conf->timeout,$conf->charset); } return self::$obj; } private function getCachedConn($id){ if (!isset($this->conns[$id])) { return null; } list($conn, $timeout) = $this->conns[$id]; if (time() < $timeout) { $this->cacheConn($id, $conn); return $conn; } else { return null; } } private function cacheConn($id, $conn){ $timeout = time(); if ($this->timeout) { $timeout += $this->timeout; } else { $timeout += self::DEFAULT_CACHE_EXPIRETIME; } $this->conns[$id] = array($conn, $timeout); } } $config=new stdClass(); $config->dsn=array( "mysql:host=127.0.0.1;port=3306;dbname=surframe",//主庫 "mysql:host=127.0.0.2;port=3306;dbname=surframe"//從庫 ); $config->username=array( 'root', 'root', ); $config->password=array( 'taoshihan1', 'taoshihan1', ); $config->timeout=10; $config->charset="utf8"; $db=SinaPdoAdapter::getInstance($config); $db->execute("select * from admin_users");//使用的從庫 $rows=$db->fetchAll(); var_dump($db); $db=SinaPdoAdapter::getInstance($config); $db->execute("select * from admin_users");//使用的從庫 $rows=$db->fetchAll(); var_dump($db);