基于TP5的断网重连封装PHP函数

为应对办公时良(la)好(ji)的网络连接,防止数据库操作在连接中超时丢失,本人封装了断网重连的函数,如果需要的小伙伴欢迎使用~
本PHP函数基于TP5进行开发,如有其他需求,也可根据逻辑自行封装处理

如对断网重连要求不高,可参考《ThinkPHP5.x完全开发手册》中“连接数据库”章节的参数break_reconnect’ => true

断网重连方法相关参数api文档

breaklineReconnection($queryCb, $config = [])
$queryCb参数类型 应用参考 备注
string ‘select * from tableName’ 直接使用字符串,方法内部封装了db类进行处理
callable function($dbObj){return $dbObj->name(‘tableName’)->count();} 回调函数返回数据集,使用内置的$dbObj防止断网后dB静态的旧连接失效
$config参数 必填 类型 参考值 默认值 备注
simpleReturn int 1 0 1为简单格式,0为详细格式。返回的数据格式为简单格式,不返回具体错误信息,直接获取sql会返回的数据集
dbConnect string/array ‘db_local’ [] DB所要连接的数据库参数配置,默认为空,跟dB::connnect()所要填充的第一项内容一致,可参考tp5相关写法
forceDbConnFresh boolean false false 是否强制重新连接DB数据库。默认为false,在断网重连后,必定会处理为true进行重连。非必要是不调整为true
ignoreNotify boolean false true 是否echo重连数据库信息相关提示
<?php

namespace expand;

use think\Exception;
use think\exception\PDOException;

/*
 * @title 断网重连继续sql操作
 * @author millionmile<[email protected]>
 */

class BreaklineReconnection
{
    static $sleepTime = 5;    //每次睡眠暂停的时间
    static $dbObj = [];   //存放最新的dB连接
    static $intervalNum = 1;    //每隔一段时间重新执行
    private static $currentDbConnect = [];
    private static $defualtConfig = [
        'simpleReturn' => 0,
        'dbConnect' => [],
        'forceDbConnFresh' => false,
        'ignoreNotify' => true,
        'customOperate' => false //
    ];


    /**
     * 初始化默认的断线重连参数
     * @param array $config
     */
    public static function setConfig($config = [])
    {
        self::$defualtConfig['simpleReturn'] = $config['simpleReturn'] ?? self::$defualtConfig['simpleReturn'];
        self::$defualtConfig['dbConnect'] = $config['dbConnect'] ?? self::$defualtConfig['dbConnect'];
        self::$defualtConfig['forceDbConnFresh'] = $config['forceDbConnFresh'] ?? self::$defualtConfig['forceDbConnFresh']; //强制重连刷新
        self::$defualtConfig['ignoreNotify'] = $config['ignoreNotify'] ?? self::$defualtConfig['ignoreNotify']; //是否忽略重连通知
        self::$defualtConfig['customOperate'] = $config['customOperate'] ?? self::$defualtConfig['customOperate']; //是否使用自定义的sql查询操作
    }

    /**
     * @title 切换连接的数据库,保证该连接是可用的
     * @param null $dbObj
     */
    public static function getDbObj($dbConnect = [], $forceFresh = false)
    {
        return self::reconnCb(
            function () use ($dbConnect, $forceFresh) {
                //切换为新的数据库连接
                return db('', $dbConnect, $forceFresh);
            },
            function () use ($dbConnect) {
                return self::getDbObj($dbConnect, true);
            }, [
                'resetIntervalNumFlag' => false    //避免影响到定时间隔
            ]
        );
    }

    /**
     * @title 服务器断开的话的断线重连
     * @param $queryCb callable|string 回调函数形式的话,最终也要返回字符串的sql
     * @param array $config 配置项,可不填写
     *               simpleReturn       返回的数据格式为简单格式,不返回具体错误信息,直接获取sql会返回的数据集
     *               dbConnect          连接数据库的配置项,可以用来选择要连接的库
     *               forceDbConnFresh   强制重连,默认一开始进入不需要重连,无需人工配置
     *               ignoreNotify       是否查看连接数据库信息
     * @return array|bool|mixed
     */
    public static function breaklineReconnection($queryCb, $config = [])
    {
        //如果直接返回值,simpleReturn为1
        $simpleReturn = $config['simpleReturn'] ?? self::$defualtConfig['simpleReturn'];
        $dbConnect = $config['dbConnect'] ?? self::$defualtConfig['dbConnect'];
        $forceDbConnFresh = $config['forceDbConnFresh'] ?? self::$defualtConfig['forceDbConnFresh']; //强制重连刷新
        $ignoreNotify = $config['ignoreNotify'] ?? self::$defualtConfig['ignoreNotify']; //是否忽略重连通知

        if (is_array($dbConnect)) {
            $dbConnectStr = md5(json_encode($dbConnect));
        } else {
            $dbConnectStr = $dbConnect;
        }
        //如果不是当前的,需要重新初始化db

        //重新获取dbObj
        if (self::$dbObj[$dbConnectStr] === null || $forceDbConnFresh) {
            if ((!$ignoreNotify) && $forceDbConnFresh) {
                echo '重连数据库' . PHP_EOL;
            }
            self::$dbObj[$dbConnectStr] = self::getDbObj($dbConnect, $forceDbConnFresh);
        }

        return self::reconnCb(
            function () use ($queryCb, &$config, $simpleReturn, $forceDbConnFresh, $ignoreNotify, $dbConnectStr) {
                //如果不是使用自定义操作,则传sql
                switch (true) {
                    //如果是回调函数,就是使用直接执行方法
                    case is_callable($queryCb) === true:
                        $data = $queryCb(self::$dbObj[$dbConnectStr]); //如有特殊需要,如切换数据库,建议使用内置getDbObj方法获取
                        break;
                    //如果是sql语句
                    case is_string($queryCb) === true:
                        $data = self::$dbObj[$dbConnectStr]->query($queryCb);
                        break;
                    default:
                        if ($simpleReturn) {
                            return false;
                        } else {
                            return [
                                'code' => 0,
                                'msg' => '暂不支持的sql执行方式,请使用字符串或回调函数',
                                'data' => []
                            ];
                        }
                        break;
                }
                unset($config['forceDbConnFresh']); //取消强制重连
                if ($simpleReturn) {
                    return $data;
                } else {
                    return [
                        'code' => 0,
                        'msg' => '执行成功,返回结果',
                        'data' => $data
                    ];
                }
            },
            function () use ($queryCb, &$config) {
                $config['forceDbConnFresh'] = true; //重连连接数据库
                return self::breaklineReconnection($queryCb, $config);
            },
            [
                'simpleReturn' => $simpleReturn,
                'dbConnect' => $dbConnect,
                'forceDbConnFresh' => $forceDbConnFresh,
                'ignoreNotify' => $ignoreNotify,
            ]
        );
    }


    /**
     * @title 重连回调函数执行
     * @param callable $execCb
     * @param callable $errCb
     * @param array $config
     * @return mixed
     */
    private static function reconnCb(callable $execCb, callable $errCb, array $config = [])
    {
        $ignoreNotify = $config['ignoreNotify'] ?? self::$defualtConfig['ignoreNotify'];
        $resetIntervalNumFlag = $config['resetIntervalNumFlag'] ?? true;    //重置间隔数字

        $errSelfCb = function () use ($errCb, $ignoreNotify) {
            $currentSleepTime = intval(self::$sleepTime * self::$intervalNum);
            //每次重连的间隔延长
            self::$intervalNum++;
            if (!$ignoreNotify) {
                echo '连接数据库失败,' . $currentSleepTime . '秒后重新执行' . PHP_EOL;
            }
            sleep($currentSleepTime);
            return $errCb();
        };

        try {
            $res = $execCb();
            //上面执行成功,重新调整失败重连间隔时间
            if ($resetIntervalNumFlag) {
                self::$intervalNum = 1;
            }
            return $res;
        } catch (\Exception $e) {
            //如果是mysql连接失败,重新执行方法
            $errMsg = $e->getMessage();
            if (strpos($errMsg, 'SQLSTATE[HY000]') !== false && (strpos($errMsg, '2002') !== false or strpos($errMsg, '2006') !== false)) {
                return $errSelfCb();
            }
//            echo $errMsg;
//            exit;
        }
    }
}

技术有限,如有更好的方式方法处理,还请不吝指教!

猜你喜欢

转载自blog.csdn.net/weixin_38125045/article/details/105948261