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

原文发布于微信公众号 - 决胜机器学习(phpthinker)

原文发表时间:2017-07-25

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏chenssy

【死磕Sharding-jdbc】---基于ssm

本篇文章讲解如何在ssm(spring、springmvc、mybatis)结构的程序上集成sharding-jdbc(版本为1.5.4.1)进行分库分表; 假...

932
来自专栏容器云生态

Golang读写文件操作

最近在使用Golang进行文件读写的过程中,遇到几个细节问题导致程序写入数据时有一定脏数据的残留,最后发现是使用os.OpenFile在进行文件操作的时候没有使...

3917
来自专栏程序员叨叨叨

【PHP】Propel的使用,看这一篇就够了

本文为学习Propel框架使用的笔记,默认已经安装好Propel环境,若有读者不知如何安装Propel,可参考《听说你PHP配置Composer遇到了一些困境》...

715
来自专栏salesforce零基础学习

salesforce零基础学习(八十七)Apex 中Picklist类型通过Control 字段值获取Dependent List 值

注:本篇解决方案内容实现转自:http://mysalesforceescapade.blogspot.com/2015/03/getting-dependen...

590
来自专栏一“技”之长

iOS中动态更新补丁策略JSPatch运用基础二

    上篇博客中介绍了iOS开发中JSPatch引擎进行动态热修复的一些基础功能,其中包括向Objective-C类中添加类方法与成员方法、添加临时成员变量,...

672
来自专栏Hongten

python开发_pickle

pickle模块使用的数据格式是python专用的,并且不同版本不向后兼容,同时也不能被其他语言说识别。要和其他语言交互,可以使用内置的json包使用pickl...

542
来自专栏向治洪

浅谈前端JavaScript编程风格

前言 多家公司和组织已经公开了它们的风格规范,具体可参阅jscs.info,下面的内容主要参考了Airbnb的JavaScript风格规范。当然还有google...

1887
来自专栏chenssy

【死磕Sharding-jdbc】---基于 SSM 集成sharding-jdbc2.0.3

本篇文章讲解如何在ssm(spring、springmvc、mybatis)结构的程序上集成sharding-jdbc(版本为2.0.3)进行分库分表; 假设分...

361
来自专栏何俊林

Android开发基础规范(二)

前言:Android中一些开发规范,避免给自己和别人少留坑。 二、代码相关 2.2.15 Field Ordering 属性排序 在类文件顶部声明的任何属性都...

1787
来自专栏康怀帅的专栏

Laravel 数据库操作

原生 SQL 插入 insert 使用 ? 绑定参数。 DB::insert('insert tb1 values(?,?,?)',[null,'tom',10...

3317

扫描关注云+社区