PHP 数据库读写操作的设计 (一)

数据库连接类的设计

网站系统中的数据是存放在数据库中,所以就无法避免地要对数据库进行频繁的读写操作。虽然 PHP 提供了很好的方法,但每次都得写一长串也是个麻烦,所以设计了一个易用的读写数据库类别。

一、利用单例模式(Singleton)创建数据库连接类

数据库连接对象通常会在整个项目中被共享使用,没有必要在每一次使用时都实例化一个对象,不仅低效而且浪费资源。因此采用单例模式的类来确保它在整个应用系统中是唯一的。

单例模式的类通常是采用静态的类方法 getInstance() 来实现的,这个静态方法只返回一个该类的唯一实例。在第一次调用此方法时,该方法将创建一个实例,存放在一个私有的静态变量中,并返回该实例。在下一次调用时,将不再创建新的实例,而是返回第一次所创建的实例。

采用单例模式的类的构造函数通常设为私有,以便防止直接实例化该类而创建新的实例。


Class DBConnect 
{
    private static $Instance = null;

    public static function getInstance() {
        if( !isset(self::$Instance) ) {
            self::$Instance = new self();
        }
        return self::$Instance;        
    }

    private function __construct() { … }
    private function __clone() {}
}
?>

二、利用简单工厂模式(Simple Factory)取得数据库连接类的实例

在一个应用系统中,虽然一开始就会决定采用何种数据库系统,但也不是不可能更换,所以加入简单工厂模式的设计,可以降低将来更换后修改的工作量。

首先定义一个基楚的数据库连接接口:


interface IDBHelper
{
    public static function getInstance();
    public function close();
    public function getOne($SQL, $aAry);
    public function query($SQL, $aAry=null, $bAll=false);
    public function execute($SQL, $aAry);
}
?>

然后针对不同的数据库设计相对应的类,令其继承自 IDBConnect 接口,例如:

class MySqlHelper implements IDBHelper { … }
class SqlServerHelper implements IDBHelper { … }
class OracleHelper implements IDBHelper { … }

最后设计一个简单工厂模式的 DBFactory 类依不同状况来取得数据库实例。

class DBFactory
{
    Public static function create() {
        return DBFactory::createBy(‘MySQL’);
    }

    public static function createBy($szType) {
        switch($szType) {
            case 'MySQL' :
                return MySqlHelper::getInstance(); break;
            default:
                die("无法识别的数据库型态:$szType");
                exit();
        }
    }
}

三、实作数据库连接类

从 IDBHelper 接口中可以看出,数据库连接类除了负责连接数据库之外,也得肩负数据库存取的功能,所以有简单的取得一笔数据 getOne()、多笔数据或其他查询 query() 及 execute() 执行新增、修改、删除等动作。

MySqlHelper 类采用 PDO 的方式来操控 MySQL 数据库,其程序代码如下:


/**
*   需要读入一个外部档 password.php。 
 */
require_once('IDBHelper.php');

class MySqlHelper implements IDBHelper
{    
    private static $Instance = null;
    protected $aConn         = null;    
    protected $bTransaction  = false;

    public static function getInstance() {
        if( !isset(self::$Instance) ) {
            self::$Instance = new self();
        }
        return self::$Instance;        
    }

    private function __construct() {
        require('password.php');        

        $dsn = "mysql:dbname=$szDBName;host=$szHost;port=$szPort";

        try {
           $ary = array(PDO::MYSQL_ATTR_INIT_COMMAND =>'SET NAMES \'UTF8\'');
           $this->aConn = new PDO($dsn, $szUser, $szPWD, $ary);
        } catch (PDOException $e) {
           $this->PrintError('Connection failed: '.$e->getMessage());
           $this->aConn = null;
           exit();
        }
    }

    function __destruct() {
        $this->close();
    }

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

    // 以对象的方式传回。
    public function getOne( $SQL, $aAry ) {
        $sth = $this->aConn->prepare( $SQL );
        $sth->execute( $aAry );
        return $sth->fetchObject();
    }

    public function query( $SQL, $aAry=NULL, $bAll=false ) {
        $sth = $this->aConn->prepare($szQuery);
        $sth->execute($aAry);

        if( $bAll )
            return $sth->fetchAll(PDO::FETCH_ASSOC);
        else
            return $sth->fetch(PDO::FETCH_BOTH);
    }

    //  只执行命令,不传回结果。
    public function execute( $SQL, $aAry=NULL ) {
        $sth = $this->aConn->prepare( $SQL );
        $waiting = true;
        while($waiting) {
            try {
                if( $this->beginTransaction() ) {
                    $sth->execute($aAry);
                    $this->commit();
                    $waiting = false;
                }
            } catch(PDOException $e) {
                $res = stripos($e->getMessage(), 'DATABASE IS LOCKED');
                if( $res !== false) {
                    $this->commit();
                } else {
                    $this->rollback();
                    $waiting = false;
                    throw $e;
                }
            }
        }
    }    

    private function beginTransaction() {
       if( $this->bTransaction ) {
           return false;
       } else {
           $this->aConn->setAttribute(PDO::ATTR_ERRMODE,
                                      PDO::ERRMODE_EXCEPTION);
           $this->bTransaction = $this->aConn->beginTransaction();
           return $this->bTransaction;
       }    
    }

    private function commit() {
        $this->aConn->commit();
        $this->bTransaction = false;
    }

    private function rollback() {
        $this->aConn->rollBack();
        $this->bTransaction = false;
    }        
}
?>

结语

MySqlHelper 类负责对数据库的直接操作,给予什么样的 SQL 命令,就会依指示办事。这里只实作出 MySqlHelper 的部份,至于 SqlServerHelper 及 OrcalHelper,因我个人没用到,所以就没实作过。

参考资料:
《PHP 从入门到精通》 陈超等编着 化学工业出版社

你可能感兴趣的:(PHP)