swoole 连接mysql_swoole教程:用swoole4操作mysql连接池之读写分离

为什么要读写分离?

一般的系统都是读多写少,利用读写分离,可以提升mysql的效率

读写分离后,从库可以水平扩展

下面我们开始代码之旅吧

配置先改造:

$config = [ 'host'=> '127.0.0.1', //数据库ip'port'=> 3306, //数据库端口'user'=> 'root', //数据库用户名'password'=> '123456', //数据库密码'database'=> 'test', //默认数据库名'timeout'=> 0.5, //数据库连接超时时间'charset'=> 'utf8mb4', //默认字符集'strict_type'=> true, //ture,会自动表数字转为int类型'pool_size'=> '3', //连接池大小'pool_get_timeout'=> 0.5, //当在此时间内未获得到一个连接,会立即返回。(表示所以的连接都已在使用中)];

改成:

$config = [ 'pool_size'=> '3', //连接池大小'pool_get_timeout'=> 0.5, //当在此时间内未获得到一个连接,会立即返回。(表示所以的连接都已在使用中)'master'=> [ 'host'=> '127.0.0.1', //数据库ip'port'=> 3306, //数据库端口'user'=> 'root', //数据库用户名'password'=> '123456', //数据库密码'database'=> 'test', //默认数据库名'timeout'=> 0.5, //数据库连接超时时间'charset'=> 'utf8mb4', //默认字符集'strict_type'=> true, //ture,会自动表数字转为int类型], 'slave'=> [

[ 'host'=> '127.0.0.1', //从数据库1ip'port'=> 3306, //从数据库1端口'user'=> 'root', //从数据库1用户名'password'=> '123456', //从数据库1密码'database'=> 'test', //默认数据库名'timeout'=> 0.5, //数据库连接超时时间'charset'=> 'utf8mb4', //默认字符集'strict_type'=> true, //ture,会自动表数字转为int类型],

[ 'host'=> '127.0.0.1', //从数据库2ip'port'=> 3306, //从数据库2端口'user'=> 'root', //从数据库2用户名'password'=> '123456', //数据库密码'database'=> 'test', //默认数据库名'timeout'=> 0.5, //数据库连接超时时间'charset'=> 'utf8mb4', //默认字符集'strict_type'=> true, //ture,会自动表数字转为int类型]

],

];

上面模拟的一主两从,由于我本机没有搭建mysql的主从,所以这里主从配置一样

由于我们要做到对上层业务无感知,所以我们只需要改动mydb.php这一层就行了

{ //创建主数据连接$master = newMySQL();

$res = $master->connect($config['master']); if($res === false) { //连接失败,抛弃常throw newRuntimeException($master->connect_error, $master->errno);

} else{ //存入master资源$this->master= $master;

} //创建从数据库连接foreach($config['slave'] as$conf) {

$slave = newMySQL();

$res = $slave->connect($conf); if($res === false) { //连接失败,抛弃常throw newRuntimeException($slave->connect_error, $slave->errno);

} else{ //存入slave资源$this->slave[] = $slave;

}

}

$this->config= $config; return$res;

} /***@param$type*@param$index*@returnMySQL*@desc单个数据库重连*/public functionreconnect($type, $index)

{ //通过type判断是主还是从if('master'== $type) { //创建主数据连接$master = newMySQL();

$res = $master->connect($this->config['master']); if($res === false) { //连接失败,抛弃常throw newRuntimeException($master->connect_error, $master->errno);

} else{ //更新主库连接$this->master= $master;

} return$this->master;

} //创建从数据连接$slave = newMySQL();

$res = $slave->connect($this->config['slave'][$index]); if($res === false) { //连接失败,抛弃常throw newRuntimeException($slave->connect_error, $slave->errno);

} else{ //更新对应的重库连接$this->slave[$index] = $slave;

} return$slave;

} /***@param$name*@param$arguments*@returnmixed*@desc利用__call,实现操作mysql,并能做断线重连等相关检测*/public function__call($name, $arguments)

{

$sql = $arguments[0];

$res = $this->chooseDb($sql); print_r($res);

$db = $res['db'];

$result = call_user_func_array([$db, $name], $arguments); if(false=== $result) { if(!$db->connected) { //断线重连echo"mysql reconnect". PHP_EOL;

$db = $this->reconnect($res['type'], $res['index']);

$result = call_user_func_array([$db, $name], $arguments); return$this->parseResult($result, $db);

} if(!empty($db->errno)) { //有错误码,则抛出弃常throw newRuntimeException($db->error, $db->errno);

}

} return$this->parseResult($result, $db);

} /***@param$result*@param$db MySQL*@returnarray*@desc格式化返回结果:查询:返回结果集,插入:返回新增id, 更新删除等操作:返回影响行数*/public functionparseResult($result, $db)

{ if($result === true) { return[ 'affected_rows'=> $db->affected_rows, 'insert_id'=> $db->insert_id,

];

} return$result;

} /***@param$sql*@desc根据sql语句,选择主还是从* @ 判断有select 则选择从库, insert, update, delete等选择主库*@returnarray*/protected functionchooseDb($sql)

{ //查询语句,随机选择一个从库if('select'== strtolower(substr($sql, 0, 6))) { if(1== count($this->slave)) {

$index = 0;

} else{

$index = array_rand($this->slave);

} return[ 'type'=> 'slave', 'index'=> $index, 'db'=> $this->slave[$index],

];

} return[ 'type'=> 'master', 'index'=> 0, 'db'=> $this->master];

}

}

connect的时候,我们自动把主,从所有的连接都建立好

执行sql的时候,我们跟据sql语句是否有select关键词,来判断选择主库还是从库

重连操作,只重连有问题的连接,不重连所有的连接

一个支持读写分离的mysql数据库接连池就OK了,是不是很简单的,大家完全可以在此基础上封装自己的CRUD等相关操作

我们在http server里增加 Insert的逻辑:

if($request->server['path_info'] == '/add') {

go(function() use($request, $response) { //从池子中获取一个实例try{

$pool = MysqlPool::getInstance(); echo"当前可用连接数:". $pool->getLength() . PHP_EOL;

$mysql = $pool->get(); echo"当前可用连接数:". $pool->getLength() . PHP_EOL;

defer(function() use($mysql) { //协程执行完成,归还$mysql到连接池MysqlPool::getInstance()->put($mysql); echo"当前可用连接数:". MysqlPool::getInstance()->getLength() . PHP_EOL;

});

$ct = time();

$title = $request->get['title'];

$result = $mysql->query("insert into test values(NULL, '{$title}', '{$ct}')");

$response->end(json_encode($result));

} catch(\Exception $e) {

$response->end($e->getMessage());

}

}); return;

}

访问:http://127.0.0.1:9501/add?title=测试

再访问: http://127.0.0.1:9501/list, 看看是否有最新的

抛个问题:

主从分离后,如果写入之后马上读,大概率会读不到?为什么?有什么方案解决?

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值