Heim >Backend-Entwicklung >PHP-Tutorial >Wie CodeIgniter die Lese-Schreib-Trennung implementiert

Wie CodeIgniter die Lese-Schreib-Trennung implementiert

不言
不言Original
2018-06-19 16:59:101327Durchsuche

In diesem Artikel wird hauptsächlich die Implementierungsmethode der CodeIgniter-Lese-Schreib-Trennung vorgestellt und die zugehörigen Konfigurations- und Funktionsimplementierungsfähigkeiten der CodeIgniter-Lese-Schreib-Trennung anhand von Beispielen detailliert analysiert Artikel

Beschreibt die Implementierungsmethode der Lese- und Schreibtrennung in CodeIgniter. Teilen Sie es als Referenz mit allen. Die Details lauten wie folgt:

Der aktuelle Server ist nur Master-Slave und die Lese-/Schreibtrennung ist nicht konfiguriert. Die Funktion der Lese-/Schreibtrennung kann nur von implementiert werden Das Programm. Hier sprechen wir hauptsächlich darüber, wie Codeigniter es implementiert. Die folgenden zwei Punkte müssen erfüllt sein:

1 Die Trennung von Lesen und Schreiben sollte transparent sein Entwicklung.

Es gibt Lösungen im Internet, um eine Lese-/Schreibtrennung durch manuelles Laden mehrerer DBs zu erreichen. Diese Trennung ist zu eng mit dem Geschäft verbunden, was die Entwicklung erschwert und der Wartung nicht förderlich ist Was wir tun müssen, ist, standardmäßig auf die leselastige Bibliothek umzustellen, Schreibvorgänge in die Hauptbibliothek zu schreiben und die Trennung von Lesen und Schreiben für Entwickler transparent zu machen

2. Einfache Konfiguration.

Behalten Sie die vorhandene Konfigurationsmethode bei und konfigurieren Sie die Lese-/Schreibtrennung durch Hinzufügen eines Arrays, ohne die ursprüngliche Verwendungsmethode zu beeinträchtigen.

Ideen

1. Die einfachste Idee, eine Lese-Schreib-Trennung zu erreichen, besteht darin, basierend auf der Abfrage zu bestimmen, ob in die Hauptbibliothek eingefügt oder aus der Slave-Bibliothek gelesen werden soll Anweisung, in der die Abfrage schließlich ausgeführt wird, daher muss diese Funktion gefunden werden.

2. Die Datenbank sollte nur einmal verbunden werden und der Link sollte beim nächsten Mal wiederverwendbar sein. Das heißt, alle Lesevorgänge sind auch nach einer erneuten Datenbankerstellung verfügbar und es besteht keine Notwendigkeit, erneut eine Verbindung herzustellen. Das Gleiche gilt für die Hauptdatenbank. So können wir den Link in das CI-Superobjekt einfügen.

3. Die Master-Slave-Beurteilung basiert auf der endgültig ausgeführten SQL-Anweisung, daher muss der automatische Link-Autoinit-Parameter in der Datenbankkonfiguration nicht auf true gesetzt werden, wenn er standardmäßig verbunden ist Die Bibliothek muss nicht betrieben werden. Das ist eine Verschwendung von Ressourcen.

4. Sie können $this->db im Modell verwenden, um die Abfrage ohne weitere Anpassungen direkt auszuführen.

5. Ändern Sie Dateien nicht direkt im System.

Erzielen Sie eine Lese- und Schreibtrennung.

Die DB-Klasse von CI ist auf das Lesen von Dateien im System We festgelegt kann dies durch entsprechendes Umschreiben erreichen. Die erste ist Loader.php, in der die Datenbankmethode zum Laden von Datenbankobjekten verwendet wird. Sie bezieht sich auf die Datei system/database/DB.php. Wir ermitteln, ob eine benutzerdefinierte DB.php-Datei vorhanden ist, und importieren sie.

Loader.php neu schreiben

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 */

Dann erstellen wir Datenbank/DB.php unter Anwendung/Kern, diese Datei Es gibt nur eine DB-Methode, mit der die Konfigurationsdatei gelesen und Initialisierungsarbeiten durchgeführt werden. Es gibt auch zwei Stellen, die neu geschrieben werden müssen:

DB.php neu schreiben

//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 */

Die gesamte DB. Die Anpassung von php dient im Wesentlichen der Einführung von Gruppennamen, um die spätere Beurteilung zu erleichtern. Wenn sie nicht eingeführt werden, können sie über den Host- und Datenbanknamen konfiguriert werden. Wenn Sie das Ausschalten von Autoint erzwingen möchten, können Sie den folgenden Absatz in DB.php löschen:

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

Der nächste Schritt ist der Kernteil. Die Trennung von Lesen und Schreiben wird anhand von Abfrageanweisungen erreicht.
Die simple_query-Methode in DB_driver.php kann als letzte Methode zum Ausführen der SQL-Anweisung verstanden werden. Hier können wir die Datenbankverknüpfung beurteilen.

DB_driver.php neu schreiben

//增加属性,表示当前组
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 */

Die Trennung von Lesen und Schreiben ist hier grundsätzlich realisiert, aber schwierig Dinge tun Von Anfang bis Ende muss das verknüpfte Datenbankobjekt geschlossen werden, und die Verbindung kann nach der Ausführung im öffentlichen Controller geschlossen werden.

Es gibt auch eine Close-Methode in DB_driver.php. Können Sie überlegen, ob sie in dieser Methode geschlossen werden kann? Ich denke, das ist hier nicht möglich.

Datenbankverknüpfung schließen

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 */

Im Modell verwenden, um $this in jedem Modell verfügbar zu machen ->db, und nicht mehrmals eine Verbindung zur Datenbank herstellen, hier wird der Link auch im CI-Superobjekt platziert. Dies ist auch dann möglich, wenn es keine Trennung von Lesen und Schreiben gibt. Es können problemlos mehrere DBs verbunden werden. Wenn Sie andere Bibliotheken für ein bestimmtes Modell verwenden möchten, müssen Sie nur den Gruppennamen im Konstruktor übergeben.

Modellanpassung

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 */

Die endgültige Datenbankkonfigurationsmethode besteht darin, ein Array basierend auf dem ursprünglichen Can zu konfigurieren . Ob Dual-Master oder ein Master und mehrere Slaves verwendet werden, hängt hier von der Konfiguration ab. Zuerst habe ich darüber nachgedacht, Schlüsselnamen direkt zur ursprünglichen Konfiguration hinzuzufügen, aber die entsprechende Beziehung zwischen Master und Slave ist immer noch nicht so klar. Die Definition hier bestimmt die Implementierung von load_db_proxy_setting.

database.php-Konfiguration

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

Der ursprüngliche Datenbanklink wurde nicht im CI-Superobjekt platziert, das ich gefunden habe dass beim Laden mehrerer Modelle der Link jedes Mal geöffnet wird, sodass Sie nach Abschluss der Lese-/Schreibtrennung testen müssen, ob der Datenbanklink geöffnet und geschlossen ist, um festzustellen, ob er wie erwartet ausgeführt wird (die Methode entspricht). application/core/database/drivers/mysql/mysql_driver. Die beiden wichtigsten Punkte im gesamten Anpassungsprozess sind die Methode simple_query und das Schließen der Datenbankverbindung im Konstruktor. Die Anpassung im Modell soll die Verknüpfung mehrerer Bibliotheken erleichtern. Sie wird auch dann angepasst, wenn die Trennung von Lesen und Schreiben nicht in einer Datei erfolgt und MY_Model sie erbt.

Es gibt viele Middlewares, die die Lese- und Schreibtrennung von MYSQL implementieren. Wenn diese nicht verwendet werden, kann die Lese- und Schreibtrennung durch Programmsteuerung erreicht werden. Dies implementiert natürlich nur die Trennung von Lesen und Schreiben, und Sie können die Verwendung der Hauptbibliothek erzwingen. Wenn Sie eine bessere Zuweisungsmethode wünschen, können Sie über die Zuweisungsmethode in Load_db_proxy_setting nachdenken.

Das Obige ist der gesamte Inhalt dieses Artikels. Ich hoffe, er wird für das Studium aller hilfreich sein. Weitere verwandte Inhalte finden Sie auf der chinesischen PHP-Website.

Verwandte Empfehlungen:

Analyse häufig verwendeter Operationsklassen im CI-Framework

Informationen zur unendlichen Klassifizierung und Rekursion des CI-Frameworks Implementieren Sie

Das obige ist der detaillierte Inhalt vonWie CodeIgniter die Lese-Schreib-Trennung implementiert. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn