数据库模块模块 小扳手

来源:互联网 发布:拆分源码 编辑:程序博客网 时间:2024/04/29 13:50

    • 背景
    • 独立方式
      • 方法抽取
    • 整体方式
      • 字符串切割
      • 匹配模式
      • 完整 小扳手
    • 总结

背景

放假在家的日子过得真是飞快,一晃这么多天了没碰代码,想来还真是有点汗颜。为了扩充我的代码小仓库,就写了个简单的轮子,这样以后就省事了。

这次的轮子,借鉴了Apache的db-utils框架(然而我这个简易的不能更简易了吧)。大致的功能就是CRUD的操作。实现的时候分别以独立和整体的方式表现。

接下来我将一点点的写出来

独立方式

独立方式就是指简单的对于select, update, delete, insert等语句进行专门处理,一种SQL语句对应一种处理方式。其实底层原理都是一样的。

方法抽取

在进行独立语句处理之前,我们还需要明白的就是在PDO模块中的prepare语句,既可以在一定的程度上提升程序的运行效率,还能提高程序的安全性。(类似于Java中JDBC常用的PreparedStatement)。

在PHP中实现类似的处理有两种方式,这里介绍一下使用?的吧。因为我觉得使用:variable的方式虽然对于程序的可读性上来讲比较好,但是在灵活度以及程序的维护层面上就不是那么的美妙了。所以我这里使用了第一种。至于怎么实现,还是先来看个小例子吧。

$arr = array(    "name", 1);for($index=0; $index<count($arr); $index++) {    echo "<mark>{$arr[$index]}</mark><br />";}

运行的效果为:
预处理原理简易演示

通过这种方式,就可以取得数组中我们预置好的变量值了,配合PHP中的bindParam方法,就可以啦。

接下来/**     * 补全SQL语句,并处理附加参数。     * @param $sql     * @param $params     * @return PDOStatement     */    public function prepareAndExecute($sql = "", $params = array())    {        try{            $sqlRunner = $this->conn->prepare($sql);            for ($index = 0; $index < count($params); $index++) {                $sqlRunner->bindParam($index + 1, $params[$index]);            }            $sqlRunner->execute();            return $sqlRunner;        }catch (Exception $e){            throw new RuntimeException($e->getMessage());        }    }

下面针对向数据库中插入数据实现特定方法。

/**     * 数据插入,返回值表示是否成功执行。     * @param $sql     * @param $params     * @return bool     */    public function insert($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlRunner)            return true;        else            return false;    }

/**     * 支持单条记录删除以及批量删除操作。     * @param $sql     * @param $params     * @return bool     */    public function delete($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlRunner)            return true;        else            return false;    }

/**     * 支持单条记录更新以及批量更新操作。     * @param $sql     * @param $params     * @return bool     */    public function update($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlRunner)            return true;        else            return false;    }

/**     * 根据SQL语句获取到查询结果,防止SQL注入并处理附加参数。     * @param $sql     * @param $params     * @return array|bool     */    public function select($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        $resultSet = $sqlRunner->fetchAll(PDO::FETCH_ASSOC);        if (count($resultSet) == 0 || $resultSet == false) {            return false;        } else {            return $resultSet;        }    }

获取到查询结果集之后进行返回,至于要怎么对数据进行处理,就不适合在这一个方法内实现了,具体的业务逻辑还是要进行具体分析。

按照约定俗成的理念,一个方法只完成一个功能就够了,一个方法实现多个功能很多时候不符合“低耦合,高内聚”的理念。

整体方式

对于整体方式,我觉得和上面的处理逻辑并没有什么很大的区别,唯一不同的就是对上面的代码进行了重构。

精简了代码处理,以及优化了代码的结构,其他的还真的没什么不同的。但是这里有一个小小的技巧。

来观看“select, update, delete, insert”这几个关键字,不知有没有发现有什么共通之处?

哈哈,都是6个字母呗。是的,就是这么个特征,而且针对于SQL语句而言,这几个关键字通常是放置在最前面的(这里没有讨论关于复杂SQL语句书写的情况),因此简单的SQL语句就可以利用这一个特点,书写的更加简洁。

字符串切割

先来看个小例子。

echo "<br />对于substr函数的测试!";$types = array('select', 'update', 'delete', 'insert');for($index=0; $index<count($types); $index++) {    $type = substr("{$types[$index]} sql statement", 0, 6);    echo "<br /><mark>{$type}</mark>";}

运行的效果就是:
substr函数使用

匹配模式

于是,独立方式的那么多的代码,接下来就可以被写成下面的这样。

/**     * 全方位实现所有SQL语句的执行。<br />     * 自动区分SQL语句CRUD类型,并实现$SQL语句的附加参数处理。     * @param $sql     * @param $params     */    public function exec($sql = "", $params = array())    {        $sqlType = substr($sql, 0, 6);        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlType == "select") {            $resultSet = $sqlRunner->fetchAll(PDO::FETCH_ASSOC);            if ($resultSet != false && count($resultSet) != 0) {                return $resultSet;            } else {                return false;            }        } else if ($sqlType == 'delete' or $sqlType == 'update' or $sqlType == 'insert') {            if ($sqlRunner) {                return true;            } else {                return false;            }        } else {            // 实际上,即使是非CURD语句,这里也是能够成功得到执行的,prepareAndExecute方法内部完成了对此的处理。但是为了业务逻辑更加清晰,此处故意以抛出异常的形式处理。            throw new RuntimeException('您输入的SQL语句不是业务语句!如必须执行,请使用prepareAndExecute()方法代替!');        }

完整 小扳手

接下来,贴上整体这个小扳手的代码,比较简单,就不做过多的注释了。

<?php/** * Created by PhpStorm. * User: ${郭璞} * Date: 2017/1/22 * Time: 22:24 * Description: DB相关 *              <br>在DbUtils中配置所需数据库连接信息。 *              <br>然后只需要实例化QueryRunner即可完成自定义的CRUD语句了。 *//** * Class DbUtils * 数据库配置信息必备。只需要修改db_config 数组中的数据即可。 */class DbUtils{    private $dbConfig;    private $conn;    public function getConn()    {        return $this->conn;    }    public function __construct($encoding = "utf8")    {        /**         * 数据库配置信息         */        $db_config = array(            "host" => "localhost",            "user" => "root",            "password" => "mysql",            "dbname" => "test",        );        $this->dbConfig = $db_config;        $this->conn = new PDO("mysql:host={$this->dbConfig['host']};dbname={$this->dbConfig['dbname']}", $this->dbConfig['user'], $this->dbConfig['password']);        if ($encoding !== "utf8") {            $this->conn->query("set names {$encoding}");        } else {            $this->conn->query("set names utf8");        }    }    public function __destruct()    {        // TODO: Implement __destruct() method.        // 关闭数据库连接对象        $this->conn = null;    }}/** * Class QueryRunner * 模拟Apache db-utils实现的数据库常用操作支持类。最简易版本。 */class QueryRunner{    private $conn;    public function __construct($encoding = 'utf8')    {        $dbutils = new DbUtils($encoding);        $this->conn = $dbutils->getConn();    }    /**     * 根据SQL语句获取到查询结果,防止SQL注入并处理附加参数。     * @param $sql     * @param $params     * @return array|bool     */    public function select($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        $resultSet = $sqlRunner->fetchAll(PDO::FETCH_ASSOC);        if (count($resultSet) == 0 || $resultSet == false) {            return false;        } else {            return $resultSet;        }    }    /**     * 数据插入,返回值表示是否成功执行。     * @param $sql     * @param $params     * @return bool     */    public function insert($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlRunner)            return true;        else            return false;    }    /**     * 支持单条记录更新以及批量更新操作。     * @param $sql     * @param $params     * @return bool     */    public function update($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlRunner)            return true;        else            return false;    }    /**     * 支持单条记录删除以及批量删除操作。     * @param $sql     * @param $params     * @return bool     */    public function delete($sql = "", $params = array())    {        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlRunner)            return true;        else            return false;    }    /**     * 补全SQL语句,并处理附加参数。     * @param $sql     * @param $params     * @return PDOStatement     */    public function prepareAndExecute($sql = "", $params = array())    {        try{            $sqlRunner = $this->conn->prepare($sql);            for ($index = 0; $index < count($params); $index++) {                $sqlRunner->bindParam($index + 1, $params[$index]);            }            $sqlRunner->execute();            return $sqlRunner;        }catch (Exception $e){            throw new RuntimeException($e->getMessage());        }    }    /**     * 全方位实现所有SQL语句的执行。<br />     * 自动区分SQL语句CRUD类型,并实现$SQL语句的附加参数处理。     * @param $sql     * @param $params     */    public function exec($sql = "", $params = array())    {        $sqlType = substr($sql, 0, 6);        $sqlRunner = $this->prepareAndExecute($sql, $params);        if ($sqlType == "select") {            $resultSet = $sqlRunner->fetchAll(PDO::FETCH_ASSOC);            if ($resultSet != false && count($resultSet) != 0) {                return $resultSet;            } else {                return false;            }        } else if ($sqlType == 'delete' or $sqlType == 'update' or $sqlType == 'insert') {            if ($sqlRunner) {                return true;            } else {                return false;            }        } else {            // 实际上,即使是非CURD语句,这里也是能够成功得到执行的,prepareAndExecute方法内部完成了对此的处理。但是为了业务逻辑更加清晰,此处故意以抛出异常的形式处理。            throw new RuntimeException('您输入的SQL语句不是业务语句!如必须执行,请使用prepareAndExecute()方法代替!');        }    }}

总结

回顾一下,本次主要学习了一下小扳手的整体的实现流程,没什么技术难度。对自己而言也是一个拿不出手的实用性小工具罢了。

还有就是,过年在家写代码的效率真的是太低了。好想安安静静的写会代码,安安静静的思考。

这个寒假,貌似,有点长,还有一个月呢。。。

1 0
原创粉丝点击