PHP单例模式封装PDO,简化数据库增删改查

简化PDO方式操作数据库,封装成read和write两个常用方法,以及batchWrite批量数据操作(预处理+事物)、exec批量数据(事物),减少工作量

一、数据库相关信息

数据库名为:dian

数据表名:dian_users 有user和pass字段

二、实现代码

1.封装类文件名 db.class.php

<?php
class PDOTool
{
   protected static $_instance = null;
   protected static $dbConfig;
   protected $dsn;
   protected $dbh;

   private static $dbHost;
   private static $dbName;
   private static $dbUser;
   private static $dbPasswd;

   /**
    * 配置数据库信息
    */
   private static function setDBConfig()
   {
       $DB = array(
           "host" => self::$dbHost,        //数据库地址
           "user" => self::$dbUser,           //数据库名
           "password" => self::$dbPasswd,    //数据库帐号
           "dbname" => self::$dbName        //数据库密码
       );

       self::$dbConfig = $DB;
   }

   /**
    * 构造方法
    */
   public function __construct($dbHost, $dbUser, $dbPasswd, $dbName)
   {
       try {
           self::$dbHost = $dbHost;
           self::$dbName = $dbName;
           self::$dbUser = $dbUser;
           self::$dbPasswd = $dbPasswd;
           $this->dsn = 'mysql:host=' . $dbHost . ';dbname=' . $dbName;
           $this->dbh = new PDO($this->dsn, $dbUser, $dbPasswd, array(PDO::MYSQL_ATTR_INIT_COMMAND => "set names utf8"));
           $this->dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
           $this->dbConfig = self::setDBConfig();
       } catch (PDOException $e) {
           die(json_encode(self::result(false, $e->getMessage(), $e)));
       }
   }

   /**
    * 单例模式创建PDOTool类
    * @return PDOTool
    */
   private static function getInstance()
   {
       if (self::$_instance === null) {
           //加载数据库配置信息
           self::setDBConfig();
           self::$_instance = new self(self::$dbConfig['host'], self::$dbConfig['user'], self::$dbConfig['password'], self::$dbConfig['dbname']);
       }
       return self::$_instance;
   }

   /**
    * 开放数据库名信息,写sql语句有时候需要数据库名,具体看个人需求
    * @return  string  返回数据库名
    */
   public static function getDBName()
   {
       return self::getInstance()->dbConfig['dbname'];
   }

   /**
    * 数据读取方法
    * @param $sqlStr   string\sql查询语句
    * @param $dataArray    array\查询的参数列表
    * @param $method    boolean\查询方式是数组还是单条
    * @return  array
    */
   public static function read($sqlStr, $dataArray, $method = true)
   {
       try {
           $pdo = self::getInstance()->dbh;

           //执行预处理语句
           $stmt = $pdo->prepare($sqlStr);

           if ($dataArray != null && count($dataArray) > 0) {
               $stmt->execute($dataArray);
           } else {
               $stmt->execute();
           }

           //以数组|单条形式返回
           $arr = $method
               ? $stmt->fetchAll(PDO::FETCH_ASSOC) //默认数组
               : $stmt->fetch(PDO::FETCH_ASSOC); //false为单条

           //判读数组是否为空
           $isEmpty = !empty($arr);

           return self::result($isEmpty, $isEmpty ? "查询成功!" : "查询结果为空", $arr);
       } catch (PDOException $e) {
           die(json_encode(self::result(false, $e->getMessage(), $e)));
       }
   }

   /**
    * 数据插入、更新、删除方法
    * @param   $sqlStr  string\sql操作语句
    * @param   $dataArray array\数据参数列表
    * @return   array
    */
   public static function write($sqlStr, $dataArray)
   {
       try {
           $pdo = self::getInstance()->dbh;

           //执行预处理语句
           $stmt = $pdo->prepare($sqlStr);

           if ($dataArray != null && count($dataArray) > 0) {
               $stmt->execute($dataArray);
           } else {
               $stmt->execute();
           }

           //获取影响行数
           $affectRow = $stmt->rowCount();

           $isSuccess = $affectRow > 0;

           return self::result($isSuccess, $isSuccess ? "操作成功!" : "操作失败", array("affectedRows" => $affectRow));
       } catch (PDOException $e) {
           die(json_encode(self::result(false, $e->getMessage(), $e)));
       }
   }

   /**
    * 批量数据操作-事物操作
    * @param $sql string\需要执行的sql语句
    * @param $bathDataArray array\与sql语句相对应的参数列
    * @return array
    */
   public static function batchWrite($sql, $bathDataArray)
   {
       try {
           $pdo = self::getInstance()->dbh;
           //开启事物
           $pdo->beginTransaction();

           //预处理语句
           $stmt = $pdo->prepare($sql);

           $dataArrayLenth = count($bathDataArray);

           //影响行数
           $affectRow = 0;

           for ($i = 0; $i < $dataArrayLenth; $i++) {
               //执行预处理语句
               if ($stmt->execute($bathDataArray[$i])) {
                   $affectRow++;
               };
           }

           //执行事物的提交操作
           $pdo->commit();

           $isSuccess = $affectRow > 0;

           return self::result($isSuccess, $isSuccess ? "操作成功!" : "操作失败", array("affectedRows" => $affectRow));
       } catch (PDOException $e) {
           $pdo->rollBack();
           die(json_encode(self::result(false, $e->getMessage(), $e)));
       }
   }

   /**
    * 可用于执行一个完整导出的sql文件,通常用于安装导入数据库信息。
    * @param $sqlArray array\Sql语句
    * @return array
    */
   public static function exec($sqlArray)
   {
       try {
           $pdo = self::getInstance()->dbh;

           //开启事物
           $pdo->beginTransaction();

           //计算数组长度
           $sqlLength = count($sqlArray);

           //执行状态
           $statusData = array();

           //失败条数
           $errorCount = 0;

           //失败信息数组
           $errorData = array();

           //sql语句是否全部执行通过
           $isPass = true;
           for ($i = 0; $i < $sqlLength; $i++) {
               if ($sql = trim($sqlArray[$i])) {
                   $pdo->exec($sql);
                   $code = $pdo->errorCode();
                   if ($code != 00000) {
                       $errorData[$errorCount]["errorCode"] = $code;
                       $errorData[$errorCount]['errorSql'] = $sql;
                       $errorCount++;
                       $isPass = false;
                   }
               }
           }

           if (!$isPass) {
               $pdo->rollBack();
               $resultArray = array("errorRows" => $errorCount, "errorData" => $errorData);
               return self::result(false, "执行失败,事物回滚!", $resultArray);
           }

           //提交事务
           $pdo->commit();

           return self::result(true, "操作成功!", array("affectedRows" => $i));
       } catch (PDOException $e) {
           //执行事物的回滚操作
           $pdo->rollBack();
           die(json_encode(self::result(false, $e->getMessage(), $e)));
       }
   }

   /**
    * 返回执行结果
    * @param $isSuccess boolean\true成功、false失败
    * @param $msg  string\信息描述
    * @param $object   object\数据对象
    * @return array    array\操作结果
    */
   private static function result($isSuccess, $msg, $object)
   {
       return array('success' => $isSuccess, 'msg' => $msg, 'data' => $object);
   }
}
?>

2.测试文件名 sql.php

<?php
header("Content-type: text/html; charset=utf-8");
include("db.class.php");   //引入封装的数据库操作类

//初始化连接
$DB = new PDOTool("localhost", "username", "password", "dbname");

//查询数据库信息-----------------------------
//查询方法1 :不带数据的数组
//$sql = "SELECT * FROM `".$dbName."`.`dian_users` "; //1.不带参数的查询
//$mData = array();             //1.不带参数查询的数组,数组传空值
$arrResult = $DB->read($sql, $mData, true); //php全版本可用
$arrResult = $DB::read($sql, $mData, true); //php5.2及以下不支持
//第三个参数默认true,表示查询全部;可使用false,表示只查询一条数据
$data = $arrResult['data']; //取出data
foreach ($data as $key => $value) {
   var_dump($value); //显示出来
}

//查询方法2 :带数据的数组
$sql = "SELECT * FROM `" . $dbName . "`.`dian_users` where `user` = ? and pass = ? "; //2.带参数的查询
$mData = array("111", "aaa");    //2.带参数查询的数组,数组值与需要查询的字段名字对应,111代表user的值  ,aaa表示pass的值

//用多维数组存储查询结果-注意如果没有查询到数据,返回的数组为空,但长度是1,不是0
$arrResult = $DB::read($sql, $mData);//调用查询方法,传入sql语句、数组参数

//输出结果
var_dump($arrResult);

//插入一个用户信息-----------------------
$sql = "INSERT INTO `" . $dbName . "`.`dian_users`(`user`, `pass`) VALUES (?, ?)";

//创建数组,存放需要传入的值,注意:数据的位置必须和数据字段的位置对应,不能错乱,有几个问号就有几个数据
$mData = array("555", "fff"); //插入一个用户名为555,密码为fff的帐号

//调用方法写入数据
$ret = $DB::write($sql, $mData);     //传入sql语句和数据参数,返回值是bool类型

if ($ret['success'] == true) {
   echo "写入成功";
} else {
   echo "写入失败";
}
?>

3.返回结果类型-数组

read返回值:success:成功true、失败false

{
    "success": true,
    "msg": "查询成功!",
    "data": [查询出来的数据]
}

write返回值:success:成功true、失败false

{
    "success": true,
    "msg": "操作成功!",
    "data": {
        "affectedRows": 17
    }
}

exec执行成功结果和write一致

exec执行失败返回值:

{
    "success": false,
    "msg": "执行失败,事物回滚!",
    "data": {
        "errorRows": 执行出错语句条数,
        "errorData": [
            {
                "errorCode": "出错响应码",
                "errorSql": "出错sql语句1"
            },
            {
                "errorCode": "出错响应码",
                "errorSql": "出错sql语句2"
            }
        ]
    }
}