关闭

数据库模块模块 小扳手

标签: 数据库PHP小扳手
5734人阅读 评论(1) 收藏 举报
分类:

背景

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

这次的轮子,借鉴了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
查看评论

【微信小程序开发•系列文章四】模块化

微信小程序的MINA框架,其实是许多前端开发技术的组合。这篇文章中,我们来简单地讨论一下模块化。 1、模块化标准 玩前端的同学大部分都知道模块化的几个标准,CommonJs / AMD / CMD。这里花费一些篇幅简单的介绍一下,比较熟悉的同学可以跳过这一部分的介绍。 (1)CommonJs...
  • lingyb011
  • lingyb011
  • 2016-11-07 16:57
  • 3219

Verilog HDL模块的结构

一个设计是由一个个模块(module)构成的。一个模块的设计如下: 1、模块内容是嵌在module 和endmodule两个语句之间。每个模块实现特定的功能,模块可进行层次的嵌套,因此可以将大型的数字电路设计分割成大小不一的小模块来实现特定的功能,最 后通过由顶层模块调用子模块来实现整体...
  • kobesdu
  • kobesdu
  • 2013-10-09 17:52
  • 3921

ruby中的模块

什么是模块 模块(module)是Ruby特有的功能之一。类用来表现具有数据与行为(程序)的"东西", 而模块大致来说,则是只有程序部分的集合体。类与模块最大的不同在于: 1.模块不能建立实例 2.模块不能继承 模块的用法 (1)提供命名空间 命名空间(namesp...
  • Magneto7
  • Magneto7
  • 2013-06-23 09:13
  • 1502

ECMAScript6(19):Module 模块

相关文章ECMAScript6 (1):块级作用域 ECMAScript6 (2):解构赋值 ECMAScript6 (3):数值类型扩展 ECMAScript6 (4):字符串类型扩展 ECMAScript6 (5):函数的扩展 ECMAScript6 (6):数组的扩展 ECMASc...
  • Faremax
  • Faremax
  • 2017-06-21 16:19
  • 463

微信小程序(模块化)

1.模块化: 我们可以将一些公共的代码抽离成为一个单独的 js 文件,作为一个模块。模块只有通过 module.exports 或者 exports 才能对外暴露接口。需要注意的是: exports 是 module.exports 的一个引用,因此在模块里边随意更改 exports 的指向会造...
  • isoble
  • isoble
  • 2017-02-23 14:22
  • 1487

系统模块划分

系统模块划分: 1、以技术架构的纵向拆分方法; 2、以业务模块的横向拆分方法; 3、以maven作为架构进行模块划分;
  • u013456370
  • u013456370
  • 2018-01-11 11:21
  • 62

微信小程序模块化开发框架

微信小程序组件化开发框架教程
  • qq_38125123
  • qq_38125123
  • 2017-05-25 14:39
  • 372

短信模块(一)

最近在学习短信模块,写点东西
  • sjz4860402
  • sjz4860402
  • 2014-11-12 21:13
  • 1355

python 小模块 ---marshai模块

转自:http://python.01314.cn/201506112.html 下面是marshal模块中定义的一些与序列化/反序列化有关的函数: marshal.dump(value, file[, version]) 将值写入到一个打开的输出流里。参数value表示待序列...
  • zzlzzh
  • zzlzzh
  • 2016-04-08 09:04
  • 195

登录java编程

1.实现注册、登录功能。 某用户先注册,注册信息包括用户名、密码、个人格言。 然后使用注册的信息登录,如果登录成功,则显示个人信息; 否则显示“登录失败”。 代码:
  • Seulementzh1010
  • Seulementzh1010
  • 2018-01-02 20:50
  • 29
    个人资料
    • 访问:3239279次
    • 积分:34877
    • 等级:
    • 排名:第148名
    • 原创:357篇
    • 转载:35篇
    • 译文:9篇
    • 评论:734条
    友情链接
    我的偶像
    个人主页
      GitHub
    放松一下
    博客专栏
    最新评论
    版权信息
    去除本页广告
    图片炸弹装填中...

        
    [img=赞一个]http://bpic.588ku.com/element_origin_min_pic/16/12/12/0d96da96cf36505736c09d63832eaac8.jpg[/img]