db封装

2023-05-16

db封装

以下Connection类封装支持以下几个特性

  • 1.参数绑定防止sql注入
  • 2.读写分离
  • 3.多主多从,多节点负载均衡
  • 4.故障自动摘除及自动恢复

代码实现

<?php
class Connection
{
    /**
     * @var array
     * @datetime 2020/7/5 10:20 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public $masters = [];

    /**
     * @var array
     * @datetime 2020/7/5 10:20 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public $slaves = [];

    /**
     * @var \PDO
     * @datetime 2020/7/5 10:21 AM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_master;

    /**
     * @var \PDO
     * @datetime 2020/7/5 10:21 AM
     * @author roach
     * @email jhq0113@163.com
     */
    protected $_slave;

    /**
     * @var string
     * @datetime 2020/7/6 1:32 下午
     * @author   roach
     * @email    jhq0113@163.com
     */
    protected $_driver;

    /**
     * @return string
     * @datetime 2020/7/6 1:49 下午
     * @author   roach
     * @email    jhq0113@163.com
     */
    public function getDriver()
    {
        if(is_null($this->_driver)) {
            $this->_driver = ucfirst(substr($this->masters[0]['dsn'], 0, strpos($this->masters[0]['dsn'], ':')));
        }
        return $this->_driver;
    }

    /**
     * @param array $configs
     * @return \PDO
     * @datetime 2020/7/5 12:19 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected function _select($configs = [])
    {
        shuffle($configs);

        foreach ($configs as $config) {
            try {
                if(!isset($config['options'])) {
                    $config['options'] = [];
                }
                $config['options'][ \PDO::ATTR_ERRMODE ] = \PDO::ERRMODE_EXCEPTION;

                $pdo = new \PDO($config['dsn'], $config['username'], $config['password'], $config['options']);
                return $pdo;
            }catch (\Throwable $throwable) {
                continue;
            }
        }
    }

    /**
     * @return \PDO
     * @throws Exception
     * @datetime 2020/7/5 10:30 AM
     * @author roach
     * @email jhq0113@163.com
     */
    protected function _master()
    {
        if(is_null($this->_master)) {
            $this->_master = $this->_select($this->masters);
            if(is_null($this->_master)) {
                throw new Exception('没有可用的master数据库了');
            }
        }

        return $this->_master;
    }

    /**
     * @return \PDO
     * @throws Exception
     * @datetime 2020/7/5 10:31 AM
     * @author roach
     * @email jhq0113@163.com
     */
    protected function _slave()
    {
        if(is_null($this->_slave)) {
            if(empty($this->slaves)) {
                $this->slaves = $this->masters;
            }

            $this->_slave = $this->_select($this->slaves);
            if(is_null($this->_slave)) {
                throw new Exception('没有可用的slave数据库了');
            }
        }

        return $this->_slave;
    }

    /**
     * @param bool   $useMaster
     * @param string $sql
     * @return bool|\PDOStatement
     * @throws Exception
     * @datetime 2020/7/5 12:12 PM
     * @author roach
     * @email jhq0113@163.com
     */
    protected function _createCommand($useMaster, $sql)
    {
        try {
            if($useMaster) {
                $pdo = $this->_master();
                return $pdo->prepare($sql);
            } else {
                $pdo = $this->_slave();
                return $pdo->prepare($sql);
            }
        }catch (\Throwable $throwable) {
            //连接断了,原因可能是超时、mysql宕机等,会重新选择一个数据库,仅重新选择一次
            if($useMaster) {
                $this->_master = null;
                $pdo = $this->_master();
                return $pdo->prepare($sql);
            } else {
                $this->_slave = null;
                $pdo = $this->_slave();
                return $pdo->prepare($sql);
            }
        }
    }

    /**
     * @return string
     * @datetime 2020/7/5 10:42 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public function lastInsertId()
    {
        return $this->_master->lastInsertId();
    }

    /**
     * @param string $sql
     * @param array  $params
     * @param bool   $useMaster
     * @return array
     * @throws Exception
     * @datetime 2020/7/5 12:13 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function queryAll($sql, $params = [], $useMaster = false)
    {
        $stmt = $this->_createCommand($useMaster, $sql);
        $stmt->execute($params);
        $rows = $stmt->fetchAll(\PDO::FETCH_ASSOC);
        $stmt->closeCursor();

        return $rows;
    }

    /**
     * @param $sql
     * @param array $params
     * @return int
     * @throws Exception
     * @throws \ReflectionException
     * @datetime 2020/7/5 12:13 PM
     * @author roach
     * @email jhq0113@163.com
     */
    public function execute($sql, $params = [])
    {
        $stmt = $this->_createCommand(true, $sql);
        $stmt->execute($params);

        return $stmt->rowCount();
    }

    /**
     * @return bool
     * @throws Exception
     * @datetime 2020/7/5 10:44 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public function begin()
    {
        return $this->_master()->beginTransaction();
    }

    /**
     * @return bool
     * @throws Exception
     * @datetime 2020/7/5 10:45 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public function rollback()
    {
        return $this->_master()->rollBack();
    }

    /**
     * @return bool
     * @throws Exception
     * @datetime 2020/7/5 10:48 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public function commit()
    {
        return $this->_master()->commit();
    }

    /**
     * @param callable $handler
     * @return bool
     * @throws Exception
     * @datetime 2020/7/5 10:50 AM
     * @author roach
     * @email jhq0113@163.com
     */
    public function transaction(callable $handler)
    {
        $result = $this->begin();
        if(!$result) {
            return false;
        }

        $result = call_user_func($handler, $this);
        if($result) {
           return $this->commit();
        }

        $this->rollback();
        return false;
    }
}

使用

<?php
$connection = new Connection([
    'masters' => [
        [
            'dsn'      => 'mysql:host=10.16.49.113;port=3306;dbname=doctor_v6;charset=utf8',
            'username' => 'browser',
            'password' => 'browser.360'
        ]
    ],
    'slaves' => [
        [
            'dsn'      => 'mysql:host=10.16.49.113;port=3306;dbname=doctor_v6;charset=utf8',
            'username' => 'browser',
            'password' => 'browser.360'
        ],
        [
            'dsn'      => 'mysql:host=10.16.49.113;port=3306;dbname=doctor_v6;charset=utf8',
            'username' => 'browser',
            'password' => 'browser.360'
        ],
    ]
]);

$rows = $connection->execute('INSERT INTO `t_user`(`user_name`,`true_name`,`add_time`) VALUES(?, ?, ?)', [
    uniqid('u'), uniqid('t'), time()
]);

$userId = $connection->lastInsertId();

echo '插入的用户id为:'.$userId.';受影响行数为:'.$rows.PHP_EOL;

$rows = $connection->execute('UPDATE `t_user` SET add_time=? WHERE id=?', [
    time()+1, $userId
]);

echo '修改的受影响行数为:'.$rows.PHP_EOL;

$users = $connection->queryAll('SELECT * FROM `t_user` WHERE id=?', [
    $userId
]);

echo '插入和修改的用户信息为:'.json_encode($users[0], JSON_UNESCAPED_UNICODE).PHP_EOL;

//强制读主库
$users = $connection->queryAll('SELECT * FROM `t_user` LIMIT 5', [], true);
echo '主库读取到的数据:'.json_encode($users, JSON_UNESCAPED_UNICODE).PHP_EOL;

//使用事务
try {
    $connection->begin();
    $rows = $connection->execute('INSERT INTO `t_user`(`user_name`,`true_name`,`add_time`) VALUES(?, ?, ?)', [
        uniqid('u'), uniqid('t'), time()
    ]);
    if($rows < 1) {
        throw new \Exception('插入失败');
    }

    $userId = $connection->lastInsertId();
    if($userId % 2 !== 0) {
        throw new \Exception('用户id只能为偶数');
    }

    $connection->commit();
    echo '提交事务成功'.PHP_EOL;
}catch (\Exception $exception) {
    $connection->rollback();
    echo $exception->getMessage().PHP_EOL;
}

如果您需要一个orm封装,可以通过以下指令安装

composer require jhq0113/roach-orm

jhq0113/roach-orm源码及文档地址

  • https://github.com/jhq0113/roach-orm

学习更多内容: https://404.360tryst.com

我的视频课程: https://edu.csdn.net/course/detail/9933

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

db封装 的相关文章

  • Iterator主要有三个方法:hasNext()、next()、remove()详解

    一 Iterator的API 关于Iterator主要有三个方法 xff1a hasNext next remove hasNext 没有指针下移操作 xff0c 只是判断是否存在下一个元素 next xff1a 指针下移 xff0c 返回
  • @ModelAttribute用法详解

    转载于 xff1a https blog csdn net harry zh wang article details 57329613 之前项目中并自己并没有怎么使用到过 64 ModelAttribute这个注解 xff0c 接手一个老
  • mysql除法运算保留小数的用法

    参照 xff1a https www cnblogs com owenma p 7097602 html 在工作中会遇到计算小数而且需要显现出小数末尾的0 xff0c 我们会用到DECIMAL这个函数 xff0c 这是一个函数非常强悍 xf
  • IDEA—点击文件代码与目录自动同步对应

    关注微信公众号 xff1a CodingTechWork xff0c 一起学习进步 引言 在使用IDEA的时候 xff0c 我们Ctrl 43 Shift 43 F搜索文件后 xff0c 总是要慢慢找文件在哪个包路径下 如查看路径顶端 xf
  • springboot打包完成之后无法读取到resources下的资源文件

    File privateKeyFile 61 ResourceUtils getFile classpath wx pfx PrivateKey privateKey 61 getPrivateKey privateKeyFile priv
  • 接口签名实现拦截的两种方式

    1 采用spring的aop思想进行拦截 需要自定义注解 xff0c 然后定义切面 xff08 五大类 xff09 然后在定义 xff0c 可以获取所有的参数 2 拦截器的实现方式 自定义拦截器 xff0c 然后对拦截器进行配置即可 配置
  • Java程序员利器,lombok神搭档:delombok插件

    Lombok是一款非常实用Java工具 xff0c 它可以帮助开发人员减少样板代码 xff0c 使开发人员专注业务逻辑 xff0c 在Java界几乎无人不知 但也有一些明显的缺点 xff0c 例如 xff1a 对插件强依赖 xff0c 在团
  • C++bind函数

    1 基本概念 bind函数定义在头文件 functional 中 可以将 bind 函数看作一个通用的函数适配器 xff0c 它接受一个可调用对象 xff0c 生成一个新的可调用对象来 适应 原对象的参数列表 C 43 43 Primer
  • C++值的分类 —— 摘自维基百科

    在C 43 43 11 xff0c 对于值的分类 xff0c 要考虑标识 xff08 identity xff09 与可移动性 xff08 movability xff09 xff0c 二者的组合产生了五种分类 xff1a 基础值类型 左值
  • pytorch 深度学习入门代码 (一)线性回归代码实现

    34 34 34 一维线性回归代码实现 34 34 34 import torch from torch autograd import Variable import matplotlib pyplot as plt import tor
  • pytorch 深度学习入门代码 (三)Logistic 回归代码实现

    span class hljs string 34 34 34 Logistic 回归的代码实现 34 34 34 span span class hljs keyword import span matplotlib pyplot spa
  • pytorch 深度学习入门代码 (四)多层全连接神经网络实现 MNIST 手写数字分类

    net py span class hljs keyword import span torch nn span class hljs keyword as span nn span class hljs class span class
  • CentOs云服务器部署项目全流程

    目录 序工具准备putty安装及使用pscp安装及使用 环境安装及配置serverjre 或jdk 安装及配置mysql安装及配置Tomcat 安装及配置 项目部署上传war包至服务器tomcat无法启动常见问题去除端口号和目录名访问项目项
  • 快速上手MybatisPlus

    首先附上mybatis plus官方文档 本篇参考官方文档记录spring mvc项目接入mybatis plus的全流程及一些问题的解决方案 xff0c 建议优先参考官方文档 开始之前 xff0c 假设数据库已建好并已能正常访问 依赖配置
  • FTP工具类一

    public class FTPClientUtils public static String FTPCONFIG 61 34 config ftpConfig properties 34 private static String LO
  • 在 SourceTree 中使用 git rebase (变基)

    原始状态 假如我们要在 master 分支上进行开发 xff0c 在远端的 master 分支上右键 xff0c 检出 一个自己的开发分支 dev 1 做一些开发 xff0c 提交到本地 xff0c 不要推送 xff08 push xff0
  • 云服务器搭建部署全流程

    本篇记录在centos7 3上部署web项目的全流程及一些问题的解决方案 工具准备 putty安装及使用 PuTTY可用来在windows上连接linux服务器 xff0c 可去PuTTY官网下载安装如果不想每次登录都输入密码 xff0c
  • 三种获取字节码对象的方式及区别

    方式一 xff1a 对象 getClass 方法是 根对象Object的方法 是其他类继承Object的getClass方法 方式二 xff1a 类名 class xff0c 你可以理解为字节码本身就是静态的 xff0c 类加载的时字节码就
  • 关于接口与Object 类的关系

    看到这个标题 xff0c 你或许就会想好自己的那份答案 但事实上这个确实没有答案 xff0c 至少没官方证明它们之间的基友关系 看法一 xff1a 因为老师说 xff0c 你可以把接口看作是特殊的类 xff0c 所以不假思索的就认为接口也
  • 单词博弈Java实现(借鉴“miss若尘”博客中写的解题思路)

    单词博弈Java实现 xff0c 已经通过庞果网的用例测试 代码如下 import java util HashMap public class WordGameFinalTest public static int who String

随机推荐

  • mysql安装时的粗心错误:last error unable to update security settings. access denied for user 'root' @ 'localh

    来自 梦想家haima 39 s blog gt http blog dreamwe cn 这个报错出现在mysql最后 当你看到mysql的最后一步需要设置密码可能你开心得很 Mysql就快安装好了 赶快输入三行密码都是root 结果报下
  • @SuppressWarnings

    简介 xff1a java lang SuppressWarnings是J2SE 5 0中标准的Annotation之一 可以标注在类 字段 方法 参数 构造方法 xff0c 以及局部变量上 作用 xff1a 告诉编译器忽略指定的警告 xf
  • 欢迎使用CSDN-markdown编辑器

    欢迎使用Markdown编辑器写博客 本Markdown编辑器使用StackEdit修改而来 xff0c 用它写博客 xff0c 将会带来全新的体验哦 xff1a Markdown和扩展Markdown简洁的语法代码块高亮图片链接和图片上传
  • Linux之强大的awk

    来自 梦想家 Haima s blog gt http blog dreamwe cn awk简介 awk是Linux中的一个命令 xff0c 用来做文本处理与分析 xff0c 功能简单强悍 xff0c 同时它也是一门编程语言 awk处理文
  • 手机抓包charles使用

    使用的是charles window 之前使过fiddler但是感觉并没有charles好用以及一目了然 链接 https pan baidu com s 1NMNXa8M4niLObQKIsCNL3A 提取码 2wsa 安装包可以通过连接
  • 安卓Tinker热更新接入踩坑(minSdkVersion 21)

    哎哟 xff0c 这个坑啊 我项目采用的是ARouter 43 Tinker 我接入的是tinkerpathchttp www tinkerpatch com Docs intro按照文档对接 xff0c 我采用的是reflectAppli
  • Android 解压和重新打包system.img

    开始我们的工作前 xff0c 请记住 xff0c Linux一定要学会用file命令分析文件类型 xff0c 这样才好入手 xff0c 否则错了都不知道怎么回事 xff01 xff01 xff01 1 解压system img 先用file
  • Jetpack系列学习笔记整理一 之LifeCycles

    学习最好的途径就是官网和github Demo xff0c 先放链接 xff0c 想看自行跳转 xff1a 官网 xff1a https developer android com topic libraries architecture
  • 获取安卓位置信息

    别忘了添加权限 xff1a lt uses permission android name 61 34 android permission INTERNET 34 gt lt uses permission android name 61
  • 安卓与html混合开发之原生与js相互调用

    原生和html的优缺点就不多说了 xff0c 有些特定条件下用html页面可以很方便 xff0c 也很容易更新和维护 xff0c 那么这就涉及到html与安卓原生的交互和通信 接下来我要分享的是html调用原生的弹窗和位置信息 xff0c
  • 应用保活--杀死进程也能收到推送消息

    我选取的是极光推送 xff0c 当把进程杀死时候就接受不到推送过来的消息 这是因为我使用的是小米手机 xff0c 小米和华为手机属于那种深度定制安卓系统 xff0c 需要用户的操作才能够实现应用 保活 的目的 小米 MIUI 自启动管理 x
  • 安卓原生与vue前段相互调用

    之前写过一个博客是安卓原生与JS交互的博客 xff1a http blog csdn net jhl122 article details 53406623 那是正常情况下的交互 xff0c 但是如果前段人员使用vue开发就会产生一个问题
  • CMake 编译时报错 ninja: error: ......missing and no known rule to make it

    Build command failed Error while executing process F Android sdk cmake 3 6 4111459 bin cmake exe with arguments build E
  • 数据类型和Json格式

    1 前几天 xff0c 我才知道有一种简化的数据交换格式 xff0c 叫做yaml 我翻了一遍它的文档 xff0c 看懂的地方不多 xff0c 但是有一句话令我茅塞顿开 它说 xff0c 从结构上看 xff0c 所有的数据最终都可以分成三种
  • golang语言rsa加解密及签名验签

    golang语言rsa加解密及签名验签 96 rsa 96 算法概述 96 Rsa 96 结构体封装封装的优点使用案例 rsa算法 概述 rsa是一种非对称的可逆的加密算法 xff0c 对加密数据长度有限制 xff0c 同时rsa也提供了数
  • 异常与错误处理

    异常与错误处理 PHP的异常与错误是分开的 xff0c 当程序出现异常时会throw一个 Exception 或子类 对象 xff0c 但是当出现错误时会触发一个错误 1 异常处理 1 1 通过try catch主动处理异常 span cl
  • 设计模式

    1 什么是模式 设计模式是对某些典型易变问题的特定解决方案 xff0c 这些问题和解决方案经过分类总结 xff0c 并且为了方便交流给每个解决方案都起了特定的名字 模式是为了解决变化的问题 xff0c 将变化的问题进行封装 xff0c 让变
  • 最新完美解决Python第三方库安装出现Microsoft Visual C++ 14.0 is required的问题

    安装库出现报错 xff1a Microsoft Visual 14 0 or greater is required 怎么办 xff1f 使用Python下载第三方库 xff0c pip也更新了 xff0c 镜像也使用了 xff0c 网络也
  • pdo-mysql

    pdo mysql PHP连接数据库推荐使用PDO xff0c PDO扩展为PHP访问数据库定义了一个轻量级接口 我们可以通过实现PDO接口的每个数据库驱动来访问数据库服务 访问mysql数据库服务 xff0c 我们使用PDO MYSQL驱
  • db封装

    db封装 以下Connection类封装支持以下几个特性 1 参数绑定防止sql注入2 读写分离3 多主多从 xff0c 多节点负载均衡4 故障自动摘除及自动恢复 代码实现 span class token delimiter import