3

通过PHP单例模式与长连接减少MySql连接数

 1 year ago
source link: https://blog.p2hp.com/archives/6131
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

通过PHP单例模式与长连接减少MySql连接数 | Lenix Blog

此单例代码有问题,请参考下面的

在Mysql驱动的PHP网站中,MySql连接的一般都是利用脚本的结束来进行释放,在一些分层写的php网站中,若一个页面含有多个数据访问类,由于每个数据访问类都会有数据库的连接,导致这一个页面在脚本结束前会有多个数据库连接,在一些大型的页面连接可能多至数十上百,为此需要进行必要的控制,对于解释性的PHP语言,脚本是顺序执行的,也就是说数据库连接的利用同时只有一个,根据这个特点,可以用单例模式来进行改造。

<?php
class ConnecToDB
private static $instance;
private function _constuct()
} //私有构造函数,防止外界构造新对象,
public static function GetConnec()
if (!self::$instance instanceof self) {
self::$instance =new self;//若当前对象实例不存在
$temp=self::$instance; //获取当前单例
return $temp::Con() ; //调用对象私有方法连接 数据库
//连接到数据库
private static function Con()
$connec=mysqli_connect("127.0.0.1", "root", "root"); //数据库地址和密码等
mysqli_select_db($connec, "dbname");//选择数据库
} catch (Exception $e) {
echo $e->getMessage().'<br/>';
return $connec;
$db=new ConnecToDB();
$db->GetConnec();
<?php
  class ConnecToDB
  {
      private static $instance;
      private function _constuct()
      {
      } //私有构造函数,防止外界构造新对象,
      public static function GetConnec()
      {
          if (!self::$instance instanceof self) {
              self::$instance =new self;//若当前对象实例不存在
          }
          $temp=self::$instance; //获取当前单例
            return $temp::Con() ;  //调用对象私有方法连接 数据库
      }
      //连接到数据库
      private static function Con()
      {
          try {
              $connec=mysqli_connect("127.0.0.1", "root", "root");   //数据库地址和密码等
            mysqli_select_db($connec, "dbname");//选择数据库
          } catch (Exception $e) {
              echo $e->getMessage().'<br/>';
          }
          return $connec;
      }
  }
$db=new ConnecToDB();
$db->GetConnec();

这是正确的单例代码

<?php
class Config1 {}
class Config
* 必须先声明一个静态私有属性:用来保存当前类的实例
* 1. 为什么必须是静态的?因为静态成员属于类,并被类所有实例所共享
* 2. 为什么必须是私有的?不允许外部直接访问,仅允许通过类方法控制方法
* 3. 为什么要有初始值null,因为类内部访问接口需要检测实例的状态,判断是否需要实例化
private static $instance = null;
//保存用户的自定义配置参数
private $setting = [];
//构造器私有化:禁止从类外部实例化
private function __construct(){}
//克隆方法私有化:禁止从外部克隆对象
private function __clone(){}
//因为用静态属性返回类实例,而只能在静态方法使用静态属性
//所以必须创建一个静态方法来生成当前类的唯一实例
public static function getInstance()
//检测当前类属性$instance是否已经保存了当前类的实例
if (self::$instance == null) {
//如果没有,则创建当前类的实例
//self::$instance = new self();
self::$instance= new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
self::$instance->set_charset('utf8');
//如果已经有了当前类实例,就直接返回,不要重复创建类实例
return self::$instance;
//设置配置项
public function set($index, $value)
$this->setting[$index] = $value;
//读取配置项
public function get($index)
return $this->setting[$index];
//实例化Config类
$obj1 = Config::getInstance();
$obj2 = Config::getInstance();
var_dump($obj1,$obj2);
$obj1->set('host','localhost');
echo $obj1->get('host');
<?php
  class Config1 {}
  class Config
  {
    /*
  * 必须先声明一个静态私有属性:用来保存当前类的实例
  * 1. 为什么必须是静态的?因为静态成员属于类,并被类所有实例所共享
  * 2. 为什么必须是私有的?不允许外部直接访问,仅允许通过类方法控制方法
  * 3. 为什么要有初始值null,因为类内部访问接口需要检测实例的状态,判断是否需要实例化
  */
  private static $instance = null;
  //保存用户的自定义配置参数
  private $setting = [];
  //构造器私有化:禁止从类外部实例化
  private function __construct(){}
  //克隆方法私有化:禁止从外部克隆对象
  private function __clone(){}
          //因为用静态属性返回类实例,而只能在静态方法使用静态属性
          //所以必须创建一个静态方法来生成当前类的唯一实例
  public static function getInstance()
  {
              //检测当前类属性$instance是否已经保存了当前类的实例
              if (self::$instance == null) {
                  //如果没有,则创建当前类的实例
                  //self::$instance = new self();
                  self::$instance= new mysqli(DB_SERVER, DB_USERNAME, DB_PASSWORD, DB_NAME);
                  self::$instance->set_charset('utf8');
              }
              //如果已经有了当前类实例,就直接返回,不要重复创建类实例
              return self::$instance;
  }
  //设置配置项
  public function set($index, $value)
  {
  $this->setting[$index] = $value;
  }
  //读取配置项
  public function get($index)
  {
  return $this->setting[$index];
  }
  }
   
  //实例化Config类
  $obj1 = Config::getInstance();
  $obj2 = Config::getInstance();
  var_dump($obj1,$obj2);
  $obj1->set('host','localhost');
  echo $obj1->get('host');

当然这个代码中,数据库的账号、密码等连接信息都是硬编码,可以通过改造GetConnec()函数注入相应的信息。

通过这段脚本,就可以控制一个页面只有一次数据库连接。这就会减少mysql的连接数。但是虽然减少了单次请求的连接数,但是如果这个页面进行多次刷新的话,还是会生产大量mysql连接,降低性能,如图,页面进行多次刷新后,mysql连接数,出现很多:

TIM%E5%9B%BE%E7%89%8720190413111348.png

如何解决多次刷新情况下的大量连接呢,答案是用mysql长连接;

我们把上面的代码的

$connec=mysqli_connect("127.0.0.1", "root", "root"); //数据库地址和密码等

$connec=mysqli_connect("p:127.0.0.1", "root", "root"); //数据库地址和密码等

注意:上面的代码在IP地址前加了一个“p:”前缀,代表使用的是mysql长连接,修改完成后,我们再来多次刷新页面。

TIM%E5%9B%BE%E7%89%8720190413111856.png

如上图,只有2个连接了。解决成功。

当然,除了用mysql的长连接外,还可以修改linux 内核参数的连接重用参数,也可以达到目的。

用mysql长连接能大大提升性能,所以请务必使用mysql长连接。

原创文章,转载请注明:来自Lenix的博客,地址http://blog.p2hp.com/archives/6131 

最后更新于 2022年11月4日


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK