PHP PDO——单例模式实现数据库操作

PHP PDO——单例模式实现数据库操作

(原创内容,转载请注明来源,谢谢)

一、概述

PDO是PHP访问数据库的轻量、持久的接口,其提供一个抽象访问层。启用方法是在php.ini中把extension=php_pdo.dll的注释去掉即可。

PDO包含三个预定义类,PDO、PDOStatement、PDOException,其中PDOException是对Exception类的扩展。

下面的这些类的方法很常用,故列出来进行说明。

1)PDO

PDO类主要实现PHP和数据库的连接,重要方法如下:

a.PDO:构造器,构造新的PDO对象。

b.beginTransaction:开始事务。

c.commit:提交事务。

d.exec:执行SQL并返回影响条数。

e.getAttribute:返回一个数据库连接属性。

f.lastInsertId:返回最小插入数据库的行。

g.prepare:为执行准备SQL语句,配合绑定操作等,返回语句后需要执行PDOStatement。

h.query:指向SQL并返回结果集。

i.quote:返回添加引号的字符串,使其可以用于SQL。

j.roolBack:回滚一个事务。

k.setAttribute:设置一个数据库连接的属性。

2)PDOStatement

PDOStatement类主要是对PDO类的prepare方法预处理的语句进行执行,并处理执行后的结果集。

a.bindColumn:绑定一个PHP变量到结果集的输出列。

b.bindParam:绑定一个PHP变量到预处理语句中的参数。

c.bindValue:绑定一个值与处理语句中的参数。

d.columnCount:返回结果集中列的数量。

e.execute:执行一条prepare预处理的语句。

f.fetch:从结果集中取出一行。

g.fetchAll:从结果集中取出一个包含所有行的数组。

h.fetchColumn:返回结果集中某一列数据。

i.getAttribute:返回一个PDOStatement属性。

j.getColumnMeta:返回结果集中某一列的结构。

k.nextRowset:返回下一结果集。

l.rowCount:返回SQL执行后的影响条数。

m.setAttribute:设置一个PDOStatement属性。

n.setFetchMode:设置PDOStatement获取数据的方式。

二、PHP使用PDO实现增删改查

1)单例模式实现类的实例化(重点:privatestatic $inc、private __construct、__clone、public getInstance )

         privatestatic $ins;//判断是否实例化         private$conn;//数据库连接         private$sql;//拼接的字符串         //单例模式
         publicstatic function getInstance(){                   if(null== self::$ins || !(self::$ins instanceof DbDealer)){
                            self::$ins= new DbDealer();                   }
                   returnself::$ins;         }  //防止被构造和克隆
         privatefunction __construct(){}
         privatefunction __clone(){}

2)实例化PDO类,并连接mysql

         public function getConnection($server='localhost', $username='root', $password='root',$database='test'){

                   $dbConnection= new PDO('mysql:host='.$server.';dbname='.$database.'',$username,$password);
                   $this->conn= $dbConnection;                   return$this;         }

3)定义两个私有方法,一个是用于foreach循环下的bindParam,另一个是判断where条件时输入的contidion是否含有大于小于号,使得where判断不仅限于等于,还可以灵活的用于大于、小于、不等于等。

         //绑定sql
         privatefunction bindSql($query, $arrData){        foreach($arrDataas $col => &$val){

                     $col= ':'.$col;
                       $query->bindParam($col,$val);                }                return$query; 
         }         //判断输入的where条件是否需要加上等于号
         privatefunction checkNeedEqual($condition){
                   $arrAllow= array('>', '>=', '<', '<=', '!=', '=');
                   $statusWorld= isset($condition[0]) ? $condition[0] : '';
                   $statusWorlds= isset($condition[1]) ? $condition[0].$condition[1] : '';
                   $isCalcu= in_array($statusWorld, $arrAllow) || in_array($statusWorlds, $arrAllow) ?true : false;   
                   return$isCalcu;         }

4)查找:采用魔术方法__call,更加灵活,可以动态的判断是否需要where,以及需要where的条件

         //格式:get_tablename_by_condintions1_conditions2(val1,val2)
         publicfunction __call($name, $args){
                   $arrName= explode('_', $name);
                   $this->sql= ' select * from '.$arrName[1];                   if(count($arrName)<3){                            return$this->conn->query($this->sql);                   }else{
                            $this->sql.= ' where ';
                            $arrCond= array();                            for($i=3;$i<count($arrName);$i++){
                                     $this->sql.= ' '.$arrName[$i].' = :'.$arrName[$i].' ';                                     if($i<count($arrName)-1){
                                               $this->sql.= ' and ';                                     }
                                     $arrCond[$arrName[$i]]= $args[$i-3];                            }
                            $pre= $this->conn->prepare($this->sql);
                            $pre->execute($arrCond);                            return$pre;                   }         }
5)修改               //updatearrData=array(col1=>val1,col2=>val2),arrWhere=array(cond1=>status1,cond2=>status2)
         publicfunction update($table, array $arrData, array $arrWhere){                   if(empty($arrData)|| empty($arrWhere)){
                            returnnull;                   }else{
                            $this->sql= ' update '.$table.' ';
                            $this->sql.= ' set ';                            foreach($arrDataas $col => $val){
                                     $this->sql.= ' '.$col.' = :'.$col.', ';                            }                            //去掉最后一个逗号
                            $this->sql= substr($this->sql,0,strlen($this->sql)-2);
                            $this->sql.= ' where ';                            foreach($arrWhereas $cond => $status){
                                     $this->sql.= ' '.$cond.' ';                                     if($this->checkNeedEqual($status)){
                                               $this->sql.= ' "' . $status . '" ';                                     }else{
                                               $this->sql.= '= "' . $status . '" ';                                     }
                                     $this->sql.= ' and ';                            }
                            $this->sql= substr($this->sql,0,strlen($this->sql)-4);                                         
                            //调用prepare绑定数组
                            $query= $this->conn->prepare($this->sql);                            //绑定
                            $query= $this->bindSql($query, $arrData);                      
                            //执行sql
                            $query->execute();                            //获取插入的id
                            $rowCount= $query->rowCount();                            return  $rowCount;                                   
                   }         }

6)删除

                  //删除arrWhere=array(cond1=>status1,cond2=>status2)
         publicfunction delete($table, array $arrWhere){
                            $this->sql= ' delete from '.$table.' ';
                            $this->sql.= ' where ';                            foreach($arrWhereas $cond => $val){
                                     $this->sql.= ' '.$cond.' ';                                     //判断是否是等于                                     if($this->checkNeedEqual($val)){
                                               $this->sql.= ' "' . $val . '" and ';                                     }else{
                                               $this->sql.= ' ="' . $val . '" and ';                                     }                                   
                            //去掉最后一个and
                            $this->sql= substr($this->sql,0,strlen($this->sql)-4);                                         
                            //调用prepare绑定数组
                            $query= $this->conn->prepare($this->sql);            
                            //执行sql
                            $query->execute();                            //获取插入的id
                            $rowCount= $query->rowCount();                            return  $rowCount;                         
                   }                
         }

7)新增

                  //insert单条arrData=array(col1=>val1,col2=>val2)
         publicfunction insert($table, array $arrData){                            //获取列名,拼接字符串并绑定
                            $columns= array_keys($arrData);
                            $this->sql= ' insert into '.$table.'( ';                            foreach($columnsas $col){
                                     $this->sql.= $col . ', ';                            }                            //去掉最后一个逗号
                            $this->sql= substr($this->sql,0,strlen($this->sql)-2);
                            $this->sql.= ') values (';                            foreach($columnsas $col){                                     //绑定
                                     $this->sql.= ' :'.$col.', ';                            }                            //去掉最后一个逗号
                            $this->sql= substr($this->sql,0,strlen($this->sql)-2);                       
                            $this->sql.= ') ';                            //调用prepare绑定数组
                            $query= $this->conn->prepare($this->sql);                            //绑定
                            $query= $this->bindSql($query, $arrData);                            //执行sql
                            $query->execute();                            //获取插入的id
                            $id= $this->conn->lastInsertId();                            return$id;                          
         }

三、总结

1)PHP的PDO是操作数据库的利器,可以自己写好一个熟悉的类,以后其他项目都可以使用此方法查询数据库。

2)实际上增删改查的过程类似,都是拼接SQL。为了利用PDO的安全性,因此在拼接SQL时,需要将用户输入的参数使用占位符进行替换(即在拼接时使用冒号+字段名,或者使用问号),并且在完成sql拼接以及PDO类的prepare方法后,使用PDOStatement的bindParam进行绑定。

3)查询可以做的更加灵活,后续将继续改进,逐步考虑加入连表、union、分页等方法。

4)如果需要保证sql执行过程的原子性,即若干步骤一步失败全部撤销,则可以使用事务,首先要注意mysql的MyISAM不支持事务,需要把表格设置成InnoDB引擎。

使用方法:在execute方法前,插入一个PDO类的方法beginTransaction(),在完成所有执行语句后后再使用PDO类的方法commit()。

5)经过测试,PDO的增删改查效率比PHP的原生MySQL操作(即mysql_*系列函数)速度低5%~15%。但稳定性方面,PDO比原生的方式更稳定。因此,在项目中通常还是使用PDO来操作数据库,至于效率可以采用优化sql语句、优化架构、优化处理逻辑、分表、读写分离等方式进行改进。

—written by linhxx 2017.07.25

评论 (0)

发表评论