ThinkPHP framework distributed database connection method details, thinkphp database connection
This article analyzes the distributed database connection method of the ThinkPHP framework. We will share this with you for your reference. The details are as follows:
Thinkphp, as a popular framework in China, is believed to be widely used. In this article, we will analyze the connection of distributed databases, an important part of Thinkphp.
Of course, we are not here to add, delete, modify, and query databases using models. We analyze the underlying connection code to help you better understand thinkphp's database operations. It is convenient for future use.
1. Single Database Connection
In use, the connection configuration of a single database is very simple. You only need to configure the information in the configuration file.
'DB_TYPE' => 'mysql','DB_HOST' => '192.168.5.102','DB_NAME' => 'databasename','DB_USER' => 'user','DB_PWD' => 'password','DB_PORT' => '3306','DB_PREFIX' => 'onmpw_',
After the settings are complete, you can use them. By default, a single database connection is used.
2. Connection to distributed databases
The connection to a single database is very simple. Let's analyze the connection to a distributed database.
'Db _ type' => 'mysql', 'db _ host' => '2017. 168.5.191, 192.168.5.88, 192.168.5.103 ', 'db _ name' => 'test, test, test', 'db _ user' => 'masteruser, slaveuser, slaveuser ', 'db _ pwd' => 'masterpass, slavepass, slavepass ', 'db _ port' => '123', 'db _ prefix' => '', 'db _ DEPLOY_TYPE '=> 1, // database deployment method: 0 centralized (Single Server), 1 distributed (master-slave server) 'db _ RW_SEPARATE' => true, // whether the read/write operations of the database are separated from the master-slave type valid 'db _ MASTER_NUM '=> 1, // The number of Master servers after the read/write splitting 'db _ slave_no' => '', // specify the serial number of the slave server
You can connect to the distributed database according to the above configuration.
Next, let's look at the following options:
'Db _ host'
For a distributed database, several server addresses are required for several servers. Each address is separated by a comma. For master-slave distribution, the preceding address is the address of the master database.
For the user name and password below, there are also listening ports and so on, of course, there are a few to write. If the user name and password of each database are the same, you can write only one.
The parsing code for these options is as follows:
$_config['username'] = explode(',',$this->config['username']);$_config['password'] = explode(',',$this->config['password']);$_config['hostname'] = explode(',',$this->config['hostname']);$_config['hostport'] = explode(',',$this->config['hostport']);$_config['database'] = explode(',',$this->config['database']);$_config['dsn'] = explode(',',$this->config['dsn']);$_config['charset'] = explode(',',$this->config['charset']);
'Db _ DEPLOY_TYPE '=> 1
1 indicates distributed, 0 indicates centralized (that is, a single server ).
This option is implemented in the Think \ Db \ Dirver class.
Protected function initConnect ($ master = true) {if (! Empty ($ this-> config ['ploy']) // use a distributed database $ this-> _ linkID = $ this-> multiConnect ($ master ); else // default single database if (! $ This-> _ linkID) $ this-> _ linkID = $ this-> connect ();}
$this->config['deploy']
IndicatesIs 'db _ DEPLOY_TYPE'
This configuration option, the above configuration has been resolved before use, the configuration items are in$this->config
Array. As for how to parse the configuration file, we will not introduce it here. If you are interested, refer to the Think \ Db class.
$this->multiConnect()
The function is used for Distributed connections. If'DB_DEPLOY_TYPE'
If this parameter is set to 1, the function is executed. Otherwise, execute the command directly.$this->connect()
Function.
'Db _ RW_SEPARATE '=> true
True indicates read/write splitting; false indicates read/write splitting.
Note that read/write splitting is based on the master-slave database system. If this option is set to true, the master database writes data and reads data from the database.
If ($ this-> config ['rw _ separate ']) {// use read/write splitting in the master/Slave Mode if ($ master) // write data to the master server $ r = $ m; else {if (is_numeric ($ this-> config ['slave _ no']) {// specify the server read $ r = $ this-> config ['slave _ no'];} else {// read operation connection slave server $ r = floor (mt_rand ($ this-> config ['master _ num'], count ($ _ config ['hostname']) -1); // the database to be randomly connected each time} else {// read/write operations do not distinguish servers $ r = floor (mt_rand (0, count ($ _ config ['hostname'])-1); // the database to be connected randomly}
$this->config['rw_separate']
If the value is true, read/write splitting is used. If the value is false, read/write splitting is not performed. Why must read/write splitting be In the master-slave mode? The slave server cannot write but read data. If data is written to the slave server, data cannot be synchronized. This will cause data inconsistency. Therefore, if our system is master-slave, we must adopt read/write splitting. That is to say, the DB_RW_SEPARATE option must be set to true.
'Db _ MASTER_NUM '=> 1
The number next to this option indicates the number of master servers after read/write splitting. Therefore, this option is also used for master-slave database systems.
The following code selects the master server.
$m = floor(mt_rand(0,$this->config['master_num']-1));
Select the core code to be read from the server when reading the master-slave database.
Copy codeThe Code is as follows: $ r = floor (mt_rand ($ this-> config ['master _ num'], count ($ _ config ['hostname'])-1 )); // The database to be randomly connected each time
Where$this->config['master_num']
The number of Master servers.
'Db _ SLAVE_NO '=>''
Specify the serial number of the slave server to read data. If this parameter is not set, the number of books on the server is calculated based on the number of master servers, and then one of them is randomly selected for reading.
If (is_numeric ($ this-> config ['slave _ no']) {// specify the server read $ r = $ this-> config ['slave _ no'];} else {// read operation connection slave server $ r = floor (mt_rand ($ this-> config ['master _ num'], count ($ _ config ['hostname']) -1); // the database to be connected randomly}
The above is a simple description of the implementation code for the role of each option.
Next let's look at the connection section.
if($m != $r ){ $db_master = array( 'username' => isset($_config['username'][$m])?$_config['username'][$m]:$_config['username'][0], 'password' => isset($_config['password'][$m])?$_config['password'][$m]:$_config['password'][0], 'hostname' => isset($_config['hostname'][$m])?$_config['hostname'][$m]:$_config['hostname'][0], 'hostport' => isset($_config['hostport'][$m])?$_config['hostport'][$m]:$_config['hostport'][0], 'database' => isset($_config['database'][$m])?$_config['database'][$m]:$_config['database'][0], 'dsn' => isset($_config['dsn'][$m])?$_config['dsn'][$m]:$_config['dsn'][0], 'charset' => isset($_config['charset'][$m])?$_config['charset'][$m]:$_config['charset'][0], );}$db_config = array( 'username' => isset($_config['username'][$r])?$_config['username'][$r]:$_config['username'][0], 'password' => isset($_config['password'][$r])?$_config['password'][$r]:$_config['password'][0], 'hostname' => isset($_config['hostname'][$r])?$_config['hostname'][$r]:$_config['hostname'][0], 'hostport' => isset($_config['hostport'][$r])?$_config['hostport'][$r]:$_config['hostport'][0], 'database' => isset($_config['database'][$r])?$_config['database'][$r]:$_config['database'][0], 'dsn' => isset($_config['dsn'][$r])?$_config['dsn'][$r]:$_config['dsn'][0], 'charset' => isset($_config['charset'][$r])?$_config['charset'][$r]:$_config['charset'][0],);return $this->connect($db_config,$r,$r == $m ? false : $db_master);
Seeing this, I think we should look at the functions of $ r and $ m in the code described above.
Now let's look at $ r = $ m? False: $ db_master. If the read/write status of the database is not separated, the value transmitted to the connect function when the read/write status is a server is false. Or, if it is a master-slave separated write, the value passed to connect is also false. The code above shows that if $ r and $ m are not equal, $ db_master is set. In fact, it is equivalent to a backup server. If the selected $ r server fails and cannot be connected, it will connect to $ db_master.
The third parameter of the connect () function indicates whether to select a backup connection when $ db_config is faulty. False indicates no reconnection, and other values indicate reconnection.
The core code is as follows:
Try {if (empty ($ config ['dsn ']) {$ config ['dsn'] = $ this-> parseDsn ($ config );} if (version_compare (PHP_VERSION, '5. 3.6 ',' <= ') {// disable the simulated preprocessing statement $ this-> options [PDO: ATTR_EMULATE_PREPARES] = false ;} $ this-> linkID [$ linkNum] = new PDO ($ config ['dsn '], $ config ['username'], $ config ['Password'], $ this-> options);} catch (\ PDOException $ e) {if ($ autoConnection) {// $ autoConnection is not false, instead, the default master server trace ($ e-> getMessage (), '', 'err'); return $ this-> connect ($ autoConnection, $ linkNum ); // if an exception occurs, use the recursive function to reconnect} elseif ($ config ['debug']) {E ($ e-> getMessage ());}}
In this way, for the master-slave mode, $ r and $ m are certainly not the same. Therefore, if the slave server selected fails during data reading, the master server is the slave server and will finally read the data from the master server. This ensures the timeliness of data reading.
However, it is still not perfect. If there are multiple slave servers, and the slave server and master server selected when reading the data are faulty, then the data cannot be read. At this time, it should be more secure to read other slave servers. Of course, the current thinkphp function has been quite complete, enough for us to use. However, we still hope thinkphp will be improved in the future.