分析的版本是TP3.2.3
此版本已经支持mysql数据库读写分离,配置比较简单,具体可看分布式数据库支持
我们尝试分析下源码实现:
不妨先yy一下,在写操作和读操作时区分开数据库连接分别连接master和slave。
我们可以看见Model.class.php的db初始化
public function db($linkNum = , $config = , $force = false) { if ( === $linkNum && $this->db) { return $this->db; } if (! isset ( $this->_db [$linkNum] ) || $force) { if (! empty ( $config ) && is_string ( $config ) && false === strpos ( $config, / )) { $config = C ( $config ); } $this->_db [$linkNum] = Db::getInstance ( $config ); } elseif (NULL === $config) { $this->_db [$linkNum]->close (); unset ( $this->_db [$linkNum] ); return; } $this->db = $this->_db [$linkNum]; $this->_after_db (); if (! empty ( $this->name ) && $this->autoCheckFields) $this->_checkTableInfo (); return $this; }
|
接着看DB单例,
static public function getInstance($config = array()) { $md5 = md5 ( serialize ( $config ) ); if (! isset ( self::$instance [$md5] )) { $options = self::parseConfig ( $config ); if (mysqli == $options [type]) $options [type] = mysql; $class = $options [lite] ? ThinkDbLite : Think\Db\Driver\ . ucwords ( strtolower ( $options [type] ) ); if (class_exists ( $class )) { self::$instance [$md5] = new $class ( $options ); } else { E ( L ( _NO_DB_DRIVER_ ) . : . $class ); } } self::$_instance = self::$instance [$md5]; return self::$_instance; }
|
接着看见mysql驱动继承了抽象类Driver。
不妨找两个Model操作读(find)和写(add):
public function find($options = array()) { ... $resultSet = $this->db->select ( $options ); ... }
public function add($data = , $options = array(), $replace = false) { ... $result = $this->db->insert ( $data, $options, $replace ); ... }
|
我们只聚焦关键代码select 和insert 。
然后去查看数据库驱动类代码:
public function select($options = array()) { ... $result = $this->query ( $sql, ! empty ( $options [fetch_sql] ) ? true : false ); ... }
public function insert($data, $options = array(), $replace = false) { ... return $this->execute ( $sql, ! empty ( $options [fetch_sql] ) ? true : false ); }
|
继续寻根,我们看见
public function query($str, $fetchSql = false) { $this->initConnect ( false ); ... }
public function execute($str, $fetchSql = false) { $this->initConnect ( true ); ... }
|
我们终于找到了根本,
protected function initConnect($master = true) { if (! empty ( $this->config [deploy] )) $this->_linkID = $this->multiConnect ( $master ); else if (! $this->_linkID) $this->_linkID = $this->connect (); }
protected function multiConnect($master = false) { $_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] ); $m = floor ( mt_rand ( 0, $this->config [master_num] - 1 ) ); if ($this->config [rw_separate]) { if ($master) $r = $m; else { if (is_numeric ( $this->config [slave_no] )) { $r = $this->config [slave_no]; } else { $r = floor ( mt_rand ( $this->config [master_num], count ( $_config [hostname] ) - 1 ) ); } } } else { $r = floor ( mt_rand ( 0, count ( $_config [hostname] ) - 1 ) ); } 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 ); }
|
其实就是通过传入initConnect来区分读写操作,并根据配置去连接操作。
今天分析就到这里了,其实与我们yy的基本一致。