Linfinity

Never say never.
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

MySQLi扩展与PDO扩展

Posted on 2019-01-05 14:22  Linfinity  阅读(464)  评论(0)    收藏  举报

一、MySQLi扩展

1.1 mysqli扩展的基本介绍

(1) mysqli扩展和mysql扩展都可以完成对mysql数据库的操作.

(2) mysqli扩展可以看做是mysql扩展的升级版, i = improve

(3) mysqli扩展的性能比mysql扩展好,因此我们在新项目开发中,就不再使用mysql扩展, 新项目对mysql数据库的操作使用(mysqli, pdo).

(4) mysqli扩展支持面向对象开发, mysqli也支持面向过程

(5) 使用mysqli扩展前,需要引入一个dll文件, 该文件是 php_mysqli.dll, 该文件是安装php时有,在 ~/php/ext/php_mysqli.dll

 

 

1.2 mysqli 使用的细节说明

(1).如果执行的是dml语句,则返回bool

举例:

 

(2).mysql_result 对象取出数据的方式有4

 

小结:在实际的开发中,我们推荐使用第一种方式,因为第一种的可读性更好。

 

(3).细节-如何判断我们的dml语句是否真正影响了表

 

 (4).如何获取到刚刚添加的自增长id的值

 

1.3 开发一个DAOMySQLi.class.php 工具类 

基本的介绍: 封装一个更加完善的DAOMysqli.class.php 数据库操作类,方便我们以后可以在项目开发中直接使用。

使用的场景: 我们在一个项目中,会经常使用到对mysql数据库的各种操作(crud),我们可以将这些操作封装到一个类中,当我们需要操作数据库时,直接new一个对象然后使用对象来操作数据库即可。

说明:

(1) DAO, data access object, 数据访问对象,专门对mysql进行操作.

(2) DAOMySQLi.class.php  单例模式

 

代码实现:

 

<?php

class DaoMySQLi{
    //基本配置
    private $_host;
    private $_user;
    private $_pwd;
    private $_dbname;
    private $_port;
    private $_charset;
    
    //单例对象
    private static $_instance;
    //mysqli连接对象
    private $_mySQLi;
    
    private function __construct(array $option){
        $this->_host = isset($option['host'])?$option['host']:'';
        $this->_user = isset($option['user'])?$option['user']:'';
        $this->_pwd = isset($option['pwd'])?$option['pwd']:'';
        $this->_dbname = isset($option['dbname'])?$option['dbname']:'';
        $this->_port = isset($option['port'])?$option['port']:'';
        $this->_charset = isset($option['charset'])?$option['charset']:'';
        
        $this->_mySQLi = new MySQli($this->_host,$this->_user,$this->_pwd,$this->_dbname,$this->_port);
        $this->_mySQLi->set_charset($this->_charset);
        
        
    }
    
    //获取单例对象方法
    public static function getSingleton(array $option){
        if(!self::$_instance instanceof self){
            self::$_instance = new self($option);
        }
        return self::$_instance;
        
    }
    
    public function query($sql){
        $ret = $this->_mySQLi->query($sql);
        if($this->_mySQLi->errno){
            return '查询失败:'.$this->_mySQLi->error;
        }else{
            $ret_arr = array();
            while($row = $ret->fetch_assoc()){
                $ret_arr[] = $row;
            }
            return $ret_arr;
        }
        }
        
    public function update($sql){
        $ret = $this->_mySQLi->query($sql);
        if($ret){
            return '操作执行成功!';
        }else{
            return '操作执行失败!'.$this->_mySQLi->error;
        }
    }
        
    public function getLastId(){
        return $this->_mySQLi->insert_id;
    }
            
        
    public function fetchone($sql){
        $ret = $this->_mySQLi->query($sql);
        if($this->_mySQLi->errno){
            return '查询失败:'.$this->_mySQLi->error;
        }else{
                return $ret->fetch_assoc();
        }
        }
    
    
    
    
    
    
    
    
    
    
}





?>
DaoMySQLi.class.php

 

 

1.4 mysqli扩展增强-事务控制

代码演示:

 

1.5mysqli扩展-批量执行sql语句

 

(1).先看一个需求

先看一个需求:有时,我们需要一次性执行多条sql语句,比如批量增加用户,这时如果单条单条的向mysql数据库发送sql指令,效率不高,这时可以考虑使用批量执行sql语句的方式. 

传统的执行sql语句的方式是:

 

 

(2).批量执行sql语句的基本语法

$sqls = "$sq1;$sql2;$sql3..............";

$mySQLi->multi_query($sql3);

说明: 在拼接$sqls语句是,最后那个sql语句不要给;.

 

(3).关于批量的执行dml语句的细节说明

1-> 批量执行sql语句分成两大类(dml[insert,update,delte], dql[select]), 两大类之间不要混用.

2-> 批量执行sql语句,返回的结果是以一条sql执行的结果为准, 当某条dml错误了,后面的代码就不执行, 但是错误之前的sql还是执行成功的.

 

批量执行select 语句代码演示:

 

1.6 mysqli扩展的-预处理技术

(1).看一个需求

现在需要向mysql数据库添加100个用户,请问如何实现?

 

(2).分析sql语句执行的原理

传统的sql语句执行的流程

 

使用了预处理技术sql语句执行的流程

 

 (3).代码演示:

使用预处理插入数据->

<?php

$conn = new MySQLi('localhost','root','q123456','testdb');

$sql = "insert into news values (null,?,?,?)";

$pre_sql = $conn->prepare($sql);
$title = '孙哥激光笔';
$content = '孙笑川用激光笔射蔡徐坤';
$ctime = time();


$pre_sql->bind_param('ssi',$title,$content,$ctime);  #注意除了第一个表示参数类型的参数以字符串形式传入,其他参数必须以变量名传入(引用传递)!

$pre_sql->execute();



?>

使用预处理查询->

<?php


$conn = new MySQLi('localhost','root','q123456','testdb');

$sql = "select * from news";

$pre_sql = $conn->prepare($sql);


$pre_sql->execute();

$pre_sql->bind_result($id,$title,$content,$ctime);  #用以接收字段

while($pre_sql->fetch()){
    echo $id.'-'.$title.'-'.$content.'-'.$ctime;
    echo '<br>';
}

 

 (4).预处理的防止sql注入

 

看一个sql注入的实际案例

 

解决注入的方式有

(1) 使用PDO

(2) 使用一些好的工具类,工具类有自身的过滤sql语句的功能, 框架/函数

addslashes , mysqli_real_escape_string()

(3)  预处理方法

 

 

二、PDO扩展

2.1 PDO的基本介绍-示意图

说明

PDO为我们访问数据库提供了轻量级、一致性的接口,也就是说通过PDO不仅可以访问mysql数据库,还能访问其他类型的数据库:oraclemssql便于数据库的移植迁移

示意图:

说明

由于PDO是封装性的技术是用来提升开发效率将重复性的代码提取封装了所以并没有对执行效率有多大的提升不如mysqli扩展

 

2.2 PDO的基本使用

PDO扩展给我们提供了3个类,分别是:PDOPDOStatementPDOException

PDO类连接数据库,并对数据库进行增删改查操作

 

 

说明

通过PDO连接、操作数据库,分为2种格式:

1->执行增删改的操作,通过pdo对象的exec()方法实现:通常返回受影响的记录数

 

2->执行查询操作通过pdo对象的query方法实现,返回的是PDOStatement类的对象,该对象代表一个预处理的语句对象,将sql语句的结构部分缓存了

PDOStatement对象提供了3个方法查询数据:

①fetch(),获取一条数据

②fetchAll(),获取所有数据

③fetchColumn(index),获取一列数据(一个字段的数据)

 

通过常量约束返回的数据格式:

PDO::FETCH_ASSOC,表示关联类型的数据

PDO::FETCH_NUM,表示索引数据

PDO::FETCH_BOTH,表示关联索引数据

 

 

2.3 PDO对象错误信息

说明:

通过PDO对象的errorInfoerrorCode方法分别获得sql语句的错误信息、错误的代码号

 

方法:

errorInfoerroCode

 

2.4 PDO对象-引号转移并包裹

l 说明:

引号转义并包裹,先将字符串中的引号转义(不再具有原来的意义),然后在外面再包裹一层引号

 

l 方法、演示:

 

2.5 PDO对象-事务处理

l 说明:

什么是事务

一组DML语句的集合,事务有4个特点,原子性、一致性、隔离性、持久性

事务就是逻辑上的一组操作,这组操作的各个单元要么全部成功、那么全部失败,使用事务的时候,数据表的存储引擎必须是INNODB类型的

 

事务的使用步骤

开启事务beginTransaction()

如果各个单元全部成功:commit()

如果任何一个单元失败:rollback()

 

2.6 PDO对象-预处理

l 说明:

预处理,提前、预先处理sql,预处理执行的结果:先把sql语句的结构部分固定住,后期结构不会再变化,只能结果变化

使用预处理的优势

(1) 对数据库的操作更加安全,将外部用户传递的数据使用占位符代替,不影响sql语句的结构

(2) 预处理会将sql语句的结构部分固定住如果后期在执行类似的操作时,就直接使用上次编译好的(预处理)的语句,从而提升效率

 

2.7 PDO对象-lastInsertId

l 说明:

该方法是用来获得上次执行插入操作时产生的主键的值:$PDO_obj->lastInsertId()

 

2.8 PDOStatement对象

l 说明:

获得PDOStatement对象的方法:query()prepare()

l PDOStatement对象提供的方法:

fetch()查询1条记录

fetchAll()  查询所有记录

fetchColumn() 查询一个字段的值

bindValue()  绑定参数(替换占位符)

execute()    执行预编译的sql语句

closeCursor()  关闭游标指针(查询数据之后,将游标初始化,便于下次查询)

errorCode() 获得预编译sql语句中的错误代码

errorInfo() 获得预编译的sql语句中的错误信息

rowCount() 获得执行增删改受影响的记录数

 

2.9 封装PDO

 

<?php
interface I_DAO
{
    //查询一条记录的方法 
    public function fetchRow($sql);
    //查询所有记录的方法
    public function fetchAll($sql);
    //查询一个字段的值
    public function fetchColumn($sql);
    //执行增删改的操作
    public function exec($sql);
    //引号转义包裹的方法
    public function quote($data);
    //查询刚刚插入的这条数据的主键
    public function lastInsertId();
}
I_DAO.interface.php

 

 

<?php
require_once 'I_DAO.interface.php';
//首先,类要实现、完成接口规定的内容
class DAOPDO implements I_DAO
{
    //私有的属性,将将来实例化的对象保存到该属性上
    private static $instance;   //DAOPDO类的单利对象
    private $pdo;               //PDO对象
    //私有的构造方法,参数就是数据库的链接信息
    private function __construct($option)
    {
        //在构造方法中,初始化操作(连接数据库)
        $host = isset($option['host'])?$option['host']:'';
        $user = isset($option['user'])?$option['user']:'';
        $pass = isset($option['pass'])?$option['pass']:'';        
        $dbname = isset($option['dbname'])?$option['dbname']:'';
        $port = isset($option['port'])?$option['port']:'';
        $charset = isset($option['charset'])?$option['charset']:'';
        
        $dsn = "mysql:host=$host;dbname=$dbname;port=$port;charset=$charset";
        try {
            $this->pdo = new PDO($dsn,$user,$pass);
        }catch (PDOException $e){
            echo $e->getMessage();
        }
    }
    //私有的克隆方法
    private function __clone()
    {        
    }
    //提供一个公共的静态方法生成对象
    public static function getSingleton($option)
    {
        //如何生成单利的对象(只生成一个对象),先判断$pdo属性是否是当前类的实例
        if(!self::$instance instanceof self){
            self::$instance = new self($option);
        }
        return self::$instance;
    }
    
    //查询一条记录的方法
    public function fetchRow($sql){
        $pdo_statement = $this->pdo->query($sql);
        if($pdo_statement == false){
            //说明sql语句有误,输出错误信息
            $error = $this -> pdo -> errorInfo();
            $err_str = "SQL语句有误,详细信息如下:<br>".$error[2];
            echo $err_str;
            return false;
        }
        //执行到这里,说明sql语句没有问题
        $result = $pdo_statement->fetch(PDO::FETCH_ASSOC);
        $pdo_statement -> closeCursor();    //关闭游标指针,便于下次查询
        return $result;
    }
    //查询所有记录的方法
    public function fetchAll($sql){
        $pdo_statement = $this->pdo->query($sql);
        if($pdo_statement == false){
            //说明sql语句有误,输出错误信息
            $error = $this -> pdo -> errorInfo();
            $err_str = "SQL语句有误,详细信息如下:<br>".$error[2];
            echo $err_str;
            return false;
        }
        //执行到这里,说明sql语句没有问题
        $result = $pdo_statement->fetchAll(PDO::FETCH_ASSOC);
        $pdo_statement -> closeCursor();
        return $result;
    }
    //查询一个字段的值
    public function fetchColumn($sql){
        $pdo_statement = $this->pdo->query($sql);
        if($pdo_statement == false){
            //说明sql语句有误,输出错误信息
            $error = $this -> pdo -> errorInfo();
            $err_str = "SQL语句有误,详细信息如下:<br>".$error[2];
            echo $err_str;
            return false;
        }
        //执行到这里,说明sql语句没有问题
        //因为将来查询的时候 sql语句如下:SELECT goods_name FROM goods WHERE goods_id = 1;
        //已经告诉数据库查询的是goods_name这个字段,所以fetchColumn的时候就不用再传递字段的索引
        $result = $pdo_statement->fetchColumn();
        $pdo_statement -> closeCursor();
        return $result;
    }
    //执行增删改的操作,返回的是执行增删改受影响的记录数
    public function exec($sql){
        $result = $this->pdo->exec($sql);
        //如果sql语句出错了,输出错误信息,避免返回值是0的情况
        if($result === false){
            $error = $this->pdo->errorInfo();
            $err_str = 'SQL语句有误,详细信息如下:<br>'.$error[2];
            echo $err_str;
            return false;
        }
        //如果执行到这里说明,没有出错返回受影响的行数
        return $result;
    }
    //引号转义包裹的方法,返回转义包裹之后的数据
    public function quote($data){
        return $this->pdo->quote($data);
    }
    //查询刚刚插入的这条数据的主键
    public function lastInsertId(){
        return $this->pdo->lastInsertId();
    }
}
DaoPDO.class.php