Laravel 5 配置数据库主从读写分离和源码分析
来源:互联网 发布:软件测试方案范例 编辑:程序博客网 时间:2024/06/06 00:41
原文地址:Laravel5配置读写分离和源码分析
一,配置过程:
Laravel5读写分离配置比较简单,只需修改config/database.php,下面以MySQL数据库为例 内容如下 'mysql' => [
'read' => [ 'host' => '192.168.1.1'],'write' => [ 'host' => '196.168.1.2'],'driver' => 'mysql','database' => 'database','username' => 'root','password' => '','charset' => 'utf8','collation' => 'utf8_unicode_ci','prefix' => '',
]
设置完毕之后,Laravel5默认将select的语句让read指定的数据库执行,insert/update/delete则交给write指定的数据库,达到读写分离的作用。 这些设置对原始查询raw queries,查询生成器query builder,以及对象映射 Eloquent 都生效。 官网解释如下: Sometimes you may wish to use one database connection for SELECT statements, and another for INSERT, UPDATE, and DELETE statements. Laravel makes this a breeze, and the proper connections will always be used whether you are using raw queries, the query builder, or the Eloquent ORM
二,实现原理
Laravel5读写分离主要有两个过程: 第一步,根据database.php配置,创建写库和读库的链接connection 第二步,调用select时先判断使用读库还是写库,而insert/update/delete统一使用写库
三,源码分析:根据database.php配置,创建写库和读库的链接connection
主要文件:Illuminate/Database/Connectors/ConnectionFactory.php 来看看几个重要的函数:
1,判断database.php是否配置了读写分离数据库
/** * Establish a PDO connection based on the configuration. * * @param array $config * @param string $name * @return \Illuminate\Database\Connection */public function make(array $config, $name = null){ $config = $this->parseConfig($config, $name); // 如果配置了读写分离,则同时创建读库和写库的链接 if (isset($config['read'])) { return $this->createReadWriteConnection($config); } // 如果没有配置,默认创建单个数据库链接 return $this->createSingleConnection($config);}
2,看看如何创建读库和写库的链接
/** * Create a single database connection instance. * * @param array $config * @return \Illuminate\Database\Connection */protected function createReadWriteConnection(array $config){ // 获取写库的配置信息,并创建链接 $connection = $this->createSingleConnection($this->getWriteConfig($config)); // 创建读库的链接 return $connection->setReadPdo($this->createReadPdo($config));}
3,多个读库会选择哪个呢
/** * Get the read configuration for a read / write connection. * * @param array $config * @return array */protected function getReadConfig(array $config){ $readConfig = $this->getReadWriteConfig($config, 'read'); // 如果数组即多个读库,那么通过随机函数array_rand()挑一个,默认取第一个 if (isset($readConfig['host']) && is_array($readConfig['host'])) { $readConfig['host'] = count($readConfig['host']) > 1 ? $readConfig['host'][array_rand($readConfig['host'])] : $readConfig['host'][0]; } return $this->mergeReadWriteConfig($config, $readConfig);}
4,写库也是随机选择的
/** * Get a read / write level configuration. * * @param array $config * @param string $type * @return array */protected function getReadWriteConfig(array $config, $type){ // 如果多个,那么通过随机函数array_rand()挑一个 if (isset($config[$type][0])) { return $config[$type][array_rand($config[$type])]; } return $config[$type];}
总结:
1,可以设置多个读库和多个写库,或者不同组合,比如一个写库两个读库
2,每次只创建一个读库链接和一个写库链接,从多个库中随机选择一个;
四,源码分析:调用select时先判断使用读库还是写库,而insert/update/delete统一使用写库
主要文件:Illuminate/Database/Connection.php 看看几个重要的函数
1,select函数根据第三个输入参数判断使用读库还是写库
/** * Run a select statement against the database. * * @param string $query * @param array $bindings * @param bool $useReadPdo * @return array */public function select($query, $bindings = [], $useReadPdo = true){ return $this->run($query, $bindings, function ($me, $query, $bindings) use ($useReadPdo) { if ($me->pretending()) { return []; } // For select statements, we'll simply execute the query and return an array // of the database result set. Each element in the array will be a single // row from the database table, and will either be an array or objects. // 根据$useReadPdo参数,判断使用读库还是写库; // true使用读库,false使用写库;默认使用读库 $statement = $this->getPdoForSelect($useReadPdo)->prepare($query); $statement->execute($me->prepareBindings($bindings)); $fetchArgument = $me->getFetchArgument(); return isset($fetchArgument) ? $statement->fetchAll($me->getFetchMode(), $fetchArgument, $me->getFetchConstructorArgument()) : $statement->fetchAll($me->getFetchMode()); });}/** * Get the PDO connection to use for a select query. * * @param bool $useReadPdo * @return \PDO */protected function getPdoForSelect($useReadPdo = true){ // 根据$useReadPdo参数,选择PDO即判断使用读库还是写库; // true使用读库getReadPdo,false使用写库getPdo; return $useReadPdo ? $this->getReadPdo() : $this->getPdo();}
2, insert/update/delete统一使用写库
/** * Run an insert statement against the database. * * @param string $query * @param array $bindings * @return bool */public function insert($query, $bindings = []){ return $this->statement($query, $bindings);}/** * Run an update statement against the database. * * @param string $query * @param array $bindings * @return int */public function update($query, $bindings = []){ return $this->affectingStatement($query, $bindings);}/** * Run a delete statement against the database. * * @param string $query * @param array $bindings * @return int */public function delete($query, $bindings = []){ return $this->affectingStatement($query, $bindings);}/** * Execute an SQL statement and return the boolean result. * * @param string $query * @param array $bindings * @return bool */public function statement($query, $bindings = []){ return $this->run($query, $bindings, function ($me, $query, $bindings) { if ($me->pretending()) { return true; } $bindings = $me->prepareBindings($bindings); // 直接调用写库 return $me->getPdo()->prepare($query)->execute($bindings); });}/** * Run an SQL statement and get the number of rows affected. * * @param string $query * @param array $bindings * @return int */public function affectingStatement($query, $bindings = []){ return $this->run($query, $bindings, function ($me, $query, $bindings) { if ($me->pretending()) { return 0; } // For update or delete statements, we want to get the number of rows affected // by the statement and return that back to the developer. We'll first need // to execute the statement and then we'll use PDO to fetch the affected. // 直接调用写库 $statement = $me->getPdo()->prepare($query); $statement->execute($me->prepareBindings($bindings)); return $statement->rowCount(); });}
总结:
1,getReadPdo()获得读库链接,getPdo()获得写库链接;
2,select()函数根据第三个参数判断使用读库还是写库;
五,强制使用写库
有时候,我们需要读写实时一致,写完数据库后,想马上读出来,那么读写都指定一个数据库即可。 虽然Laravel5配置了读写分离,但也提供了另外的方法强制读写使用同一个数据库。
实现原理:上面$this->select()时指定使用写库的链接,即第三个参数useReadPdo设置为false即可
有几个方法可实现 1,调用方法 DB::table('posts')->selectFromWriteConnection('*')->where('id', $id);
源码解释:通过selectFromWriteConnection()函数 主要文件:Illuminate/Database/Connection.php
/** * Run a select statement against the database. * * @param string $query * @param array $bindings * @return array */public function selectFromWriteConnection($query, $bindings = []){ , // 上面有解释$this->select()函数的第三个参数useReadPdod的意义 // 第三个参数是 false,所以 select 时会使用写库,而不是读库 return $this->select($query, $bindings, false);}
2,调用方法
User::onWriteConnection()->find($id);
源码解释:通过onWriteConnection()函数 主要文件:Illuminate/Database/Eloquent/Model
/** * Begin querying the model on the write connection. * * @return \Illuminate\Database\Query\Builder */public static function onWriteConnection(){ $instance = new static; // query builder 指定使用写库 return $instance->newQuery()->useWritePdo();}
看看query builder如何指定使用写库 主要文件:Illuminate/Database/Query/Builder
/** * Use the write pdo for query. * * @return $this */public function useWritePdo(){ // 指定使用写库,useWritePdo 为true $this->useWritePdo = true; return $this;}/** * Run the query as a "select" statement against the connection. * * @return array */protected function runSelect(){ // 执行select时,useWritePdo原值为true,这里取反,被改成false; // 即$this->select()函数第三个参数为false,所以使用写库; return $this->connection->select($this->toSql(), $this->getBindings(), ! $this->useWritePdo);}
- Laravel 5 配置数据库主从读写分离和源码分析
- Laravel数据库读写分离配置
- laravel数据库读写分离配置
- CentOS7,MySQL主从配置和读写分离(MySQL主从、MySQL读写分离、MySQL分布式、数据库读写分离、主从配置)
- 数据库主从和读写分离的配置和使用方法
- Mysql数据库读写分离、主从配置信息
- Hibernate主从数据库读写分离配置
- mysql数据库的主从配置读写分离
- 数据库主从、读写分离
- mysql数据库主从复制和读写分离
- mysql数据库主从复制和读写分离
- (三十四)数据库主从复制和读写分离
- Mysql主从同步和读写分离配置
- CentOS7,MySQL主从配置和读写分离
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- Spring+Hibernate框架下MySql读写分离,主从数据库配置
- JS方法实现div容器y轴滚动
- 淘宝头部讲课
- 使IE浏览器运行最新的渲染模式
- [leetcode]--413. Arithmetic Slices
- javascript基础--对象(Object)继承
- Laravel 5 配置数据库主从读写分离和源码分析
- CCF201503-4 网络延时(100分)
- OpenGL的渲染流程梳理
- 六度分离(HDU-1869)
- mybatis 面试题
- 获取应用专属缓存目录
- 宿主机访问VMware中XP系统的Oracle数据库
- 解读Poisson图像融合
- DBGridEh用法总结一