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)