Maison  >  Article  >  développement back-end  >  Comment CodeIgniter implémente la séparation lecture-écriture

Comment CodeIgniter implémente la séparation lecture-écriture

不言
不言original
2018-06-19 16:59:101292parcourir

Cet article présente principalement la méthode de mise en œuvre de la séparation lecture-écriture CodeIgniter et analyse en détail les compétences de configuration et de mise en œuvre des fonctions associées de la séparation lecture-écriture CodeIgniter sous forme d'exemples. Les amis dans le besoin peuvent se référer aux exemples de ceci. article

Décrit la méthode d'implémentation de la séparation en lecture et en écriture de CodeIgniter. Partagez-le avec tout le monde pour votre référence, les détails sont les suivants :

Le serveur actuel est uniquement maître-esclave et la séparation lecture-écriture n'est pas configurée. La fonction de séparation lecture-écriture ne peut être implémentée que par. Le programme. Ici, nous parlons principalement de la manière dont Codeigniter le met en œuvre. La séparation de la lecture et de l'écriture doit être respectée :

1. développement.

Il existe des solutions sur Internet pour réaliser une séparation lecture-écriture en chargeant manuellement plusieurs bases de données. Une telle séparation est trop étroitement liée au métier, augmente la difficulté de développement et n'est pas propice à la maintenance. ce que nous devons faire est de choisir par défaut la bibliothèque à lecture lourde, d'écrire dans la bibliothèque principale, et la séparation de la lecture et de l'écriture est transparente pour les développeurs

2. Configuration simple.

Conservez la méthode de configuration existante et configurez la séparation lecture-écriture en ajoutant un tableau, sans affecter la méthode d'utilisation d'origine.

Idée

1. L'idée la plus simple pour réaliser la séparation de la lecture et de l'écriture est de déterminer s'il faut insérer dans la bibliothèque principale ou lire à partir de la bibliothèque esclave en fonction du instruction de requête où la requête est finalement exécutée, cette fonction doit donc être trouvée.

2. La base de données ne doit être connectée qu'une seule fois et le lien doit être réutilisable la prochaine fois. C'est-à-dire que toutes les opérations de lecture sont disponibles même après une nouvelle base de données, et il n'est pas nécessaire de se reconnecter. Il en va de même pour la base de données principale. Nous pouvons donc mettre le lien dans le super objet CI.

3. Le jugement maître-esclave est basé sur l'instruction SQL finale exécutée, donc le paramètre d'auto-initialisation du lien automatique dans la configuration de la base de données n'a pas besoin d'être défini sur true s'il est connecté par défaut et qu'il y en a. pas besoin de faire fonctionner la bibliothèque. C'est un gaspillage de ressources.

4. Vous pouvez utiliser $this->db dans le modèle pour exécuter directement la requête sans aucun autre ajustement.

5. Ne modifiez pas les fichiers sous le système directement

Réalisez la séparation en lecture et en écriture

La classe DB de CI est fixée pour lire les fichiers sous le système. peut y parvenir avec une réécriture appropriée. Le premier est Loader.php, dans lequel la méthode de base de données est utilisée pour charger des objets de base de données. Il fait référence au fichier system/database/DB.php. Nous déterminons s'il existe un fichier DB.php personnalisé et l'importons s'il existe.

Réécrire Loader.php

public function database($params = '', $return = FALSE, $active_record = NULL)
{
  $CI =& get_instance();
  if (class_exists('CI_DB') AND $return == FALSE AND $active_record == NULL AND isset($CI->db) AND is_object($CI->db)) {
    return FALSE;
  }
  if(file_exists(APPPATH.'core/database/DB.php')) {
    require_once(APPPATH.'core/database/DB.php');
  } else {
    require_once(BASEPATH.'database/DB.php');
  }
  if ($return === TRUE) {
    return DB($params, $active_record);
  }
  $CI->db = '';
  $CI->db =& DB($params, $active_record);
}
/* End of file MY_Loader.php */
/* Location: ./application/core/MY_Loader.php */

Ensuite, nous créons une base de données/DB sous application/core php, ce fichier n'a qu'une seule méthode DB, qui est utilisée pour lire le fichier de configuration et effectuer le travail d'initialisation. Il y a aussi deux endroits qui doivent être réécrits :

Réécrire DB.php

//DB_driver.php为所有驱动方式的父类,最终执行查询的方法在该文件中
//第一处修改为判断自定义的DB_driver.php是否存在,存在则引入
if(file_exists(APPPATH.'core/database/DB_driver.php')) {
  require_once(APPPATH.'core/database/DB_driver.php');
} else {
  require_once(BASEPATH.'database/DB_driver.php');
}
//第二处 $params['dbdriver'].'_driver.php' 该文件可不调整,实际未修改该文件,为了方便调试也加了
//mysql驱动对应system/database/drivers/mysql/mysql_driver.php,mysql的最后执行方法在这里,
//包括数据库打开和关闭、查询等,可以该文件增加相应日志查看读写分离是否有效
if(file_exists(APPPATH.'core/database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php')) {
  require_once(APPPATH.'core/database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php');
} else {
  require_once(BASEPATH.'database/drivers/'.$params['dbdriver'].'/'.$params['dbdriver'].'_driver.php');
}
//将当前group name赋值给param,方便判断
$params['group_name'] = $active_group;
 
/* End of file DB.php */
/* Location: ./application/core/database/DB.php */

L'intégralité DB L'ajustement de .php consiste essentiellement à introduire des fichiers. L'introduction du nom de groupe vise à faciliter le jugement ultérieur. S'il n'est pas introduit, il peut être configuré via les noms d'hôte et de base de données. Si vous souhaitez forcer la désactivation de l'autoint, vous pouvez supprimer le paragraphe suivant dans DB.php :

if ($DB->autoinit == TRUE)
{
  $DB->initialize();
}

L'étape suivante est la partie principale . La séparation de la lecture et de l'écriture est obtenue sur la base d'instructions de requête.
La méthode simple_query dans DB_driver.php peut être comprise comme la méthode finale d'exécution de l'instruction SQL. Nous pouvons juger ici du lien vers la base de données.

Réécrire DB_driver.php

//增加属性,表示当前组
var $active_group;
//增加属性,使用强制使用主库
var $db_force_master;
//该方法为执行查询的必经之地,我们可以在这里根据类型判断使用哪个链接。
function simple_query($sql)
{
  //load_db_proxy_setting方法这里写在helper中,也可以直接写在该类中,写在helper中则需要在自动加载中加载该helper
  //该方法的作用是根据当前链接group name 和sql读写类型,以及是否强制使用主库判断使用哪个链接。使用主库 OR 重库?
  //主重库的负载均衡,单点故障都可以在这里考虑。也就是根据3个参数返回一个可用的配置数组。
  $proxy_setting = load_db_proxy_setting($this->group_name, $this->is_write_type($sql), $this->db_force_master);
  if(is_array($proxy_setting) && ! empty($proxy_setting)) {
    $proxy_setting_key = key($proxy_setting);
    $this->group_name = $proxy_setting_key;
    //将当前配置重新赋值给类的属性,如果database.php配置的是DSN字符串,则需要在load_db_proxy_setting中做处理
    foreach($proxy_setting[$proxy_setting_key] as $key => $val) {
      $this->$key = $val;
    }
    //定义链接ID为conn_前缀
    $proxy_conn_id = 'conn_'.$proxy_setting_key;
    $CI = & get_instance();
    //赋值给CI超级对象或者直接从CI超级对象中读取
    if(isset($CI->$proxy_conn_id) && is_resource($CI->$proxy_conn_id)) {
      $this->conn_id = $CI->$proxy_conn_id;
    } else {
      $this->conn_id = false;
      $this->initialize();
      $CI->$proxy_conn_id = $this->conn_id;
    }
    //强制只一次有效,下次查询失效,防止一直强制主库
    $this->reset_force_master();
  }
  if ( ! $this->conn_id)
  {
    $this->initialize();
  }
  return $this->_execute($sql);
}
//某些情况会强制使用主库,先执行该方法即可
public function force_master()
{
  $this->db_force_master = TRUE;
}
public function reset_force_master()
{
  $this->db_force_master = FALSE;
}
/* End of file DB_driver.php */
/* Location: ./application/core/database/DB_driver.php */

À ce stade, la séparation de la lecture et de l'écriture est fondamentalement réalisée , mais faites-le. Pour que les choses fonctionnent, l'objet de base de données lié doit être fermé et la connexion peut être fermée après exécution dans le contrôleur public.

Il existe également une méthode close dans DB_driver.php. Pouvez-vous déterminer si elle peut être fermée dans cette méthode ? Je pense que ce n'est pas possible ici.

Fermer le lien de la base de données

class MY_Controller extends CI_Controller 
{
  public function __construct() 
  {
    parent::__construct();
    $this->load->service('common/helper_service', NULL, 'helper');
    //下面这段为关闭CI超级对象中的数据库对象和数据库链接,db的对象Codeigniter.php中会关闭
    register_shutdown_function(function(){
      foreach(get_object_vars($this) as $key => $val) {
        if(substr($key, 0, 3) == 'db_' && is_object($this->{$key}) && method_exists($this->{$key}, 'close')) {
          $this->{$key}->close();
        }
        if(substr($key, 0, 5) == 'conn_' && is_resource($this->{$key})) {
          $this->db->_close($val);
          unset($this->{$key});
        }
      }
    });
  }
}
/* End of file MY_Controller.php */
/* Location: ./application/core/MY_Controller.php */

Utiliser dans le modèle, afin de le rendre disponible dans chaque model $this->db, et pour ne pas se connecter plusieurs fois à la base de données, le lien est également placé dans le super objet CI. Cela peut être fait même s'il n'y a pas de séparation entre la lecture et l'écriture. Il peut facilement connecter plusieurs bases de données. Si vous souhaitez utiliser d'autres bibliothèques pour un modèle spécifique, il vous suffit de transmettre le nom du groupe dans le constructeur.

Ajustement du modèle

public function __construct($group_name = '')
{
  parent::__construct();
  $this->initDb($group_name);
}
private function initDb($group_name = '')
{
  $db_conn_name = $this->getDbName($group_name);
  $CI = & get_instance();
  if(isset($CI->{$db_conn_name}) && is_object($CI->{$db_conn_name})) {
    $this->db = $CI->{$db_conn_name};
  } else {
    $CI->{$db_conn_name} = $this->db = $this->load->database($group_name, TRUE);
  }
}
private function getDbName($group_name = '')
{
  if($group_name == '') {
    $db_conn_name = 'db';
  } else {
    $db_conn_name = 'db_'.$group_name;
  }
  return $db_conn_name;
}
/* End of file MY_Model.php */
/* Location: ./application/core/MY_Model.php */

La méthode de configuration finale de la base de données n'a besoin que d'en configurer une en fonction de celle d'origine Juste un tableau. L'utilisation de deux maîtres ou d'un maître et de plusieurs esclaves dépend de la configuration ici. Au début, j'ai pensé à ajouter des noms de clés directement à la configuration d'origine, mais la relation correspondante entre maître et esclave n'est toujours pas aussi claire. La définition ici détermine l'implémentation de load_db_proxy_setting.

configuration database.php

$_master_slave_relation = array(
  'default_master' => array('default_slave1', 'default_slave2', 'default_slave3'),
);
/* End of file database.php */
/* Location: ./application/config/database.php */

Le lien initial de la base de données n'est pas placé dans le super objet CI, on constate que le lien sera ouvert à chaque fois lors du chargement de plusieurs modèles, vous devez donc tester après avoir terminé la séparation lecture-écriture. Vous pouvez vérifier si le lien de base de données est ouvert et fermé pour voir s'il est exécuté comme prévu (la méthode). correspond à application/core/database/drivers/mysql/db_connect et _close dans mysql_driver.php). Les deux points les plus importants de tout le processus d'ajustement sont la méthode simple_query et la fermeture de la connexion à la base de données dans le constructeur. L'ajustement du modèle vise à faciliter la liaison de plusieurs bibliothèques. Il est également ajusté de cette manière lorsque la séparation de la lecture et de l'écriture n'est pas implémentée. Les méthodes couramment utilisées sont séparées dans un fichier et MY_Model en hérite.

Il existe de nombreux middlewares qui implémentent la séparation de lecture et d'écriture MYSQL. Lorsqu'ils ne sont pas utilisés, la séparation de lecture et d'écriture peut être obtenue via le contrôle du programme. Bien entendu, cela n’implémente que la séparation de la lecture et de l’écriture, et vous pouvez forcer l’utilisation de la bibliothèque principale. Si vous souhaitez une meilleure méthode d'allocation, vous pouvez penser à la méthode d'allocation dans load_db_proxy_setting.

Ce qui précède représente l'intégralité du contenu de cet article. J'espère qu'il sera utile à l'étude de chacun. Pour plus de contenu connexe, veuillez faire attention au site Web PHP chinois !

Recommandations associées :

Analyse des classes d'opérations couramment utilisées dans le framework CI

À propos de la classification infinie et de la récursivité du framework CI Mettre en œuvre

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn