连接池使用说明
所有连接池的实现均基于 ConnectionPool 原始连接池;
连接池的底层原理是基于 Channel 的自动调度;
开发者需要自己保证归还的连接是可重用的;
若连接不可重用,需要调用 $pool->put(null); 归还一个空连接;
归还空连接后,原始连接池会重新创建连接以保证连接池的数量一致。
PDO 连接池
declare(strict_types=1);
use Swoole\Coroutine;
use Swoole\Database\PDOConfig;
use Swoole\Database\PDOPool;
use Swoole\Runtime;
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
$s = microtime(true);
const N = 1024;
Coroutine\run(function () {
$config = (new PDOConfig)
->withHost('127.0.0.1')
->withPort(3306)
// ->withUnixSocket('/tmp/mysql.sock')
->withDbName('test')
->withCharset('utf8mb4')
->withUsername('root')
->withPassword('root');
// 创建连接池对象,默认创建64个连接
$pool = new PDOPool($config);
for ($n = N; $n--;) {
Coroutine::create(function () use ($pool) {
// 获取连接
$pdo = $pool->get();
$statement = $pdo->prepare('SELECT ? + ?');
if (!$statement) {
throw new RuntimeException('Prepare failed');
}
$a = mt_rand(1, 100);
$b = mt_rand(1, 100);
$result = $statement->execute([$a, $b]);
if (!$result) {
throw new RuntimeException('Execute failed');
}
$result = $statement->fetchAll();
if ($a + $b !== (int)$result[0][0]) {
throw new RuntimeException('Bad result');
}
// 回收连接
$pool->put($pdo);
});
}
});
$s = microtime(true) - $s;
echo 'Use ' . $s . 's for ' . N . ' queries' . PHP_EOL;
Redis 连接池
declare(strict_types=1);
use Swoole\Coroutine;
use Swoole\Database\RedisConfig;
use Swoole\Database\RedisPool;
use Swoole\Runtime;
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
$s = microtime(true);
const N = 1024;
Coroutine\run(function () {
$config = (new RedisConfig)
->withHost('127.0.0.1')
->withPort(6379)
->withAuth('')
->withDbIndex(0)
->withTimeout(1);
// 创建连接池对象,默认创建64个连接
$pool = new RedisPool($config);
for ($n = N; $n--;) {
Coroutine::create(function () use ($pool) {
// 获取连接
$redis = $pool->get();
$result = $redis->set('foo', 'bar');
if (!$result) {
throw new RuntimeException('Set failed');
}
$result = $redis->get('foo');
if ($result !== 'bar') {
throw new RuntimeException('Get failed');
}
// 回收连接
$pool->put($redis);
});
}
});
$s = microtime(true) - $s;
echo 'Use ' . $s . 's for ' . (N * 2) . ' queries' . PHP_EOL;
Mysqli 连接池
declare(strict_types=1);
use Swoole\Coroutine;
use Swoole\Database\MysqliConfig;
use Swoole\Database\MysqliPool;
use Swoole\Runtime;
Co::set(['hook_flags'=> SWOOLE_HOOK_ALL]);
$s = microtime(true);
const N = 1024;
Coroutine\run(function () {
$config = (new MysqliConfig)
->withHost('127.0.0.1')
->withPort(3306)
// ->withUnixSocket('/tmp/mysql.sock')
->withDbName('test')
->withCharset('utf8mb4')
->withUsername('root')
->withPassword('root');
// 创建连接池对象,默认创建64个连接
$pool = new MysqliPool($config);
for ($n = N; $n--;) {
Coroutine::create(function () use ($pool) {
// 获取连接
$mysqli = $pool->get();
$statement = $mysqli->prepare('SELECT ? + ?');
if (!$statement) {
throw new RuntimeException('Prepare failed');
}
$a = mt_rand(1, 100);
$b = mt_rand(1, 100);
if (!$statement->bind_param('dd', $a, $b)) {
throw new RuntimeException('Bind param failed');
}
if (!$statement->execute()) {
throw new RuntimeException('Execute failed');
}
if (!$statement->bind_result($result)) {
throw new RuntimeException('Bind result failed');
}
if (!$statement->fetch()) {
throw new RuntimeException('Fetch failed');
}
if ($a + $b !== (int)$result) {
throw new RuntimeException('Bad result');
}
while ($statement->fetch()) {
continue;
}
// 回收连接
$pool->put($mysqli);
});
}
});
$s = microtime(true) - $s;
echo 'Use ' . $s . 's for ' . N . ' queries' . PHP_EOL;