首页
4K壁纸
直播
统计分析
友情链接
搜索
1
#1031 – TABLE STORAGE ENGINE FOR ” DOESN’T HAVE THIS OPTION解决方法
1,239 阅读
2
让浏览器不显示 https 页面中 http 请求警报 http-equiv=”Content-Security-Policy” content=”upgrade-insecure-requests”
948 阅读
3
报错代码:ERROR 1227 (42000)-解决办法
738 阅读
4
微信个人商户号养号建议
584 阅读
5
解决移动端position:fixed随软键盘移动的问题
554 阅读
Php
Mysql
Linux
Reids
Java
Python
常用笔记
学习
乱七八糟
Search
标签搜索
php
Mysql
千卡云支付
Linux
redis
千卡云
千卡易支付
Nginx
function
JS
shell
JSON
跨域
支付宝
CentOS
Apache
支付
composer
Array
database
蓝科迪梦
累计撰写
102
篇文章
累计收到
0
条评论
首页
栏目
Php
Mysql
Linux
Reids
Java
Python
常用笔记
学习
乱七八糟
页面
4K壁纸
直播
统计分析
友情链接
搜索到
9
篇与
的结果
2025-10-19
数据库连接池与性能优化
PHP开发中的复杂问题及解决方案:数据库连接池与性能优化在高并发的PHP应用中,数据库连接管理是一个关键性能瓶颈。频繁创建和销毁数据库连接会消耗大量系统资源,影响应用响应速度和吞吐量。常见的数据库连接问题1. 连接泄漏// 忘记关闭数据库连接导致连接泄漏 $pdo = new PDO($dsn, $username, $password); $result = $pdo->query("SELECT * FROM users"); // 连接未正确关闭2. 连接数超限// 每次请求都创建新连接,快速耗尽数据库连接数 for ($i = 0; $i < 100; $i++) { $pdo = new PDO($dsn, $username, $password); // 处理业务逻辑 }解决方案方案一:基础连接池实现<?php /** * 数据库连接池管理器 */ class DatabaseConnectionPool { private static ?self $instance = null; private array $connections = []; private array $usedConnections = []; private int $maxConnections; private int $currentConnections = 0; private array $config; private function __construct(array $config, int $maxConnections = 20) { $this->config = $config; $this->maxConnections = $maxConnections; // 注册关闭回调 register_shutdown_function([$this, 'closeAllConnections']); } /** * 获取连接池单例实例 */ public static function getInstance(array $config = [], int $maxConnections = 20): self { if (self::$instance === null) { self::$instance = new self($config, $maxConnections); } return self::$instance; } /** * 获取数据库连接 */ public function getConnection(): PDO { // 检查是否有可用的空闲连接 if (!empty($this->connections)) { $connection = array_pop($this->connections); $this->usedConnections[spl_object_hash($connection)] = $connection; return $connection; } // 检查是否可以创建新连接 if ($this->currentConnections < $this->maxConnections) { $connection = $this->createConnection(); $this->usedConnections[spl_object_hash($connection)] = $connection; $this->currentConnections++; return $connection; } // 等待可用连接(简化实现) throw new Exception("No available database connections"); } /** * 释放连接回连接池 */ public function releaseConnection(PDO $connection): void { $hash = spl_object_hash($connection); if (isset($this->usedConnections[$hash])) { unset($this->usedConnections[$hash]); $this->connections[] = $connection; } } /** * 创建新的数据库连接 */ private function createConnection(): PDO { $dsn = $this->config['dsn'] ?? ''; $username = $this->config['username'] ?? ''; $password = $this->config['password'] ?? ''; $options = $this->config['options'] ?? [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ]; return new PDO($dsn, $username, $password, $options); } /** * 关闭所有连接 */ public function closeAllConnections(): void { foreach ($this->connections as $connection) { $connection = null; } foreach ($this->usedConnections as $connection) { $connection = null; } $this->connections = []; $this->usedConnections = []; $this->currentConnections = 0; } /** * 获取连接池状态 */ public function getPoolStatus(): array { return [ 'total_connections' => $this->currentConnections, 'available_connections' => count($this->connections), 'used_connections' => count($this->usedConnections), 'max_connections' => $this->maxConnections ]; } }方案二:高级连接池with健康检查<?php /** * 带健康检查的高级连接池 */ class AdvancedConnectionPool { private array $connections = []; private array $usedConnections = []; private int $maxConnections; private int $minConnections; private array $config; private int $connectionTimeout; private int $idleTimeout; public function __construct( array $config, int $maxConnections = 50, int $minConnections = 5, int $connectionTimeout = 30, int $idleTimeout = 300 ) { $this->config = $config; $this->maxConnections = $maxConnections; $this->minConnections = $minConnections; $this->connectionTimeout = $connectionTimeout; $this->idleTimeout = $idleTimeout; // 初始化最小连接数 $this->initializeMinConnections(); // 注册定时清理任务 $this->registerCleanupTask(); } /** * 初始化最小连接数 */ private function initializeMinConnections(): void { for ($i = 0; $i < $this->minConnections; $i++) { try { $connection = $this->createConnection(); $this->connections[] = [ 'connection' => $connection, 'last_used' => time(), 'created_at' => time() ]; } catch (Exception $e) { error_log("Failed to initialize connection: " . $e->getMessage()); } } } /** * 获取数据库连接 */ public function getConnection(): PDO { // 清理过期连接 $this->cleanupIdleConnections(); // 查找可用连接 $connection = $this->findAvailableConnection(); if ($connection !== null) { return $connection; } // 创建新连接 if (count($this->usedConnections) + count($this->connections) < $this->maxConnections) { return $this->createNewConnection(); } // 等待可用连接 return $this->waitForAvailableConnection(); } /** * 查找可用连接 */ private function findAvailableConnection(): ?PDO { while (!empty($this->connections)) { $connInfo = array_pop($this->connections); // 检查连接是否仍然有效 if ($this->isConnectionValid($connInfo['connection'])) { $connInfo['last_used'] = time(); $this->usedConnections[spl_object_hash($connInfo['connection'])] = $connInfo; return $connInfo['connection']; } else { // 连接无效,丢弃 $connInfo['connection'] = null; } } return null; } /** * 创建新连接 */ private function createNewConnection(): PDO { $connection = $this->createConnection(); $connInfo = [ 'connection' => $connection, 'last_used' => time(), 'created_at' => time() ]; $this->usedConnections[spl_object_hash($connection)] = $connInfo; return $connection; } /** * 等待可用连接 */ private function waitForAvailableConnection(): PDO { $startTime = time(); while (time() - $startTime < $this->connectionTimeout) { usleep(100000); // 等待100ms $connection = $this->findAvailableConnection(); if ($connection !== null) { return $connection; } } throw new Exception("Timeout waiting for database connection"); } /** * 检查连接是否有效 */ private function isConnectionValid(PDO $connection): bool { try { $connection->query("SELECT 1"); return true; } catch (Exception $e) { return false; } } /** * 释放连接 */ public function releaseConnection(PDO $connection): void { $hash = spl_object_hash($connection); if (isset($this->usedConnections[$hash])) { $connInfo = $this->usedConnections[$hash]; $connInfo['last_used'] = time(); $this->connections[] = $connInfo; unset($this->usedConnections[$hash]); } } /** * 清理空闲连接 */ private function cleanupIdleConnections(): void { $currentTime = time(); $remainingConnections = []; foreach ($this->connections as $connInfo) { // 保留最近使用的连接和最小连接数要求的连接 if (($currentTime - $connInfo['last_used']) < $this->idleTimeout || (count($remainingConnections) + count($this->usedConnections)) < $this->minConnections) { $remainingConnections[] = $connInfo; } else { // 关闭超时连接 $connInfo['connection'] = null; } } $this->connections = $remainingConnections; } /** * 注册清理任务 */ private function registerCleanupTask(): void { // 在应用关闭时清理连接 register_shutdown_function([$this, 'shutdown']); } /** * 应用关闭时的清理工作 */ public function shutdown(): void { foreach ($this->connections as $connInfo) { $connInfo['connection'] = null; } foreach ($this->usedConnections as $connInfo) { $connInfo['connection'] = null; } } /** * 创建数据库连接 */ private function createConnection(): PDO { $options = $this->config['options'] ?? [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, PDO::ATTR_PERSISTENT => false // 不使用持久连接,由连接池管理 ]; return new PDO( $this->config['dsn'], $this->config['username'], $this->config['password'], $options ); } }方案三:连接池使用封装<?php /** * 数据库操作封装类 */ class DatabaseManager { private AdvancedConnectionPool $connectionPool; private static ?self $instance = null; private function __construct() { $config = [ 'dsn' => $_ENV['DATABASE_DSN'] ?? 'mysql:host=localhost;dbname=test', 'username' => $_ENV['DATABASE_USER'] ?? 'root', 'password' => $_ENV['DATABASE_PASS'] ?? '', 'options' => [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_EMULATE_PREPARES => false, ] ]; $this->connectionPool = new AdvancedConnectionPool( $config, maxConnections: (int)($_ENV['DB_MAX_CONNECTIONS'] ?? 50), minConnections: (int)($_ENV['DB_MIN_CONNECTIONS'] ?? 5) ); } /** * 获取单例实例 */ public static function getInstance(): self { if (self::$instance === null) { self::$instance = new self(); } return self::$instance; } /** * 执行查询操作 */ public function query(string $sql, array $params = []): array { $connection = $this->connectionPool->getConnection(); try { $stmt = $connection->prepare($sql); $stmt->execute($params); $result = $stmt->fetchAll(); return $result; } finally { $this->connectionPool->releaseConnection($connection); } } /** * 执行更新操作 */ public function execute(string $sql, array $params = []): int { $connection = $this->connectionPool->getConnection(); try { $stmt = $connection->prepare($sql); $stmt->execute($params); return $stmt->rowCount(); } finally { $this->connectionPool->releaseConnection($connection); } } /** * 执行事务操作 */ public function transaction(callable $callback) { $connection = $this->connectionPool->getConnection(); try { $connection->beginTransaction(); $result = $callback($connection); $connection->commit(); return $result; } catch (Exception $e) { $connection->rollBack(); throw $e; } finally { $this->connectionPool->releaseConnection($connection); } } /** * 获取连接池状态 */ public function getPoolStatus(): array { // 这里需要在AdvancedConnectionPool中添加获取状态的方法 return []; } } // 使用示例 class UserService { private DatabaseManager $dbManager; public function __construct() { $this->dbManager = DatabaseManager::getInstance(); } /** * 获取用户信息 */ public function getUserById(int $id): ?array { $users = $this->dbManager->query( "SELECT * FROM users WHERE id = ?", [$id] ); return $users[0] ?? null; } /** * 创建新用户 */ public function createUser(array $userData): int { $this->dbManager->execute( "INSERT INTO users (name, email, created_at) VALUES (?, ?, ?)", [ $userData['name'], $userData['email'], date('Y-m-d H:i:s') ] ); return $this->dbManager->query("SELECT LAST_INSERT_ID() as id")[0]['id']; } /** * 批量更新用户状态 */ public function batchUpdateUserStatus(array $userIds, string $status): int { return $this->dbManager->transaction(function($connection) use ($userIds, $status) { $placeholders = str_repeat('?,', count($userIds) - 1) . '?'; $sql = "UPDATE users SET status = ? WHERE id IN ($placeholders)"; $params = array_merge([$status], $userIds); $stmt = $connection->prepare($sql); $stmt->execute($params); return $stmt->rowCount(); }); } }最佳实践建议1. 配置优化// 环境变量配置示例 /* DB_HOST=localhost DB_PORT=3306 DB_NAME=myapp DB_USER=myuser DB_PASS=mypass DB_MAX_CONNECTIONS=100 DB_MIN_CONNECTIONS=10 DB_IDLE_TIMEOUT=300 */2. 监控和日志/** * 连接池监控工具 */ class ConnectionPoolMonitor { public static function logConnectionEvent( string $eventType, array $poolStats ): void { $logData = [ 'timestamp' => date('Y-m-d H:i:s'), 'event_type' => $eventType, 'pool_stats' => $poolStats ]; error_log(json_encode($logData)); // 发送到监控系统 if (function_exists('statsd_timing')) { statsd_gauge('db.connections.total', $poolStats['total_connections']); statsd_gauge('db.connections.available', $poolStats['available_connections']); } } }3. 性能调优参数// 数据库连接池推荐配置 $poolConfig = [ 'max_connections' => 50, // 最大连接数 'min_connections' => 5, // 最小连接数 'connection_timeout' => 30, // 连接超时时间 'idle_timeout' => 300, // 空闲连接超时时间 'wait_timeout' => 10 // 等待连接超时时间 ];总结数据库连接池优化的关键要点:连接复用:避免频繁创建和销毁连接资源控制:限制最大连接数防止资源耗尽健康检查:定期检查连接有效性自动清理:及时清理空闲和无效连接监控告警:实时监控连接池状态和性能指标通过实现高效的数据库连接池,可以显著提升PHP应用的数据库访问性能和系统稳定性。
2025年10月19日
0 阅读
0 评论
0 点赞
2025-06-25
which is not functionally dependent on columns in GROUP BY clause
报错信息:which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 在对连接表进行select查找时出现以上报错信息。 打开【my.ini】文件 添加如下代码在【mysqld】中 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION 保存,重启mysql即可
2025年06月25日
109 阅读
0 评论
0 点赞
2025-03-29
mysql中 for update 使用方法
for update是在数据库中上锁用的,可以为数据库中的行上一个排它锁。当一个事务的操作未完成时候,其他事务可以读取但是不能写入或更新。 例子: 比如一张表三个字段 , id(商品id), name(商品名字) , count(数量) 当商品抢购时候会显示剩余商品件数,如果并发量大的时候,商品自减的值可能不准确。所以当我们在一个事务中对count字段进行修改的时候,其他事务应该只能读取指定id的count,而不能进行update等操作。这个时候就需要用到for update. sql语句: start transaction ; select * from table_name where id =1 for update ; update table_name set count = count - 1 where id= 1; 此时如果另一个事务也想执行类似的操作: start transaction ; select * from table_name where id =1 for update ; //下面的这行sql会等待,直到上面的事务回滚或者commit才得到执行。 update table_name set count = count - 1 where id= 1; *注:当选中某一个行的时候,如果是通过主键id选中的。那么这个时候是行级锁。 其他的行还是可以直接insert 或者update的。如果是通过其他的方式选中行,或者选中的条件不明确包含主键。这个时候会锁表。其他的事务对该表的任意一行记录都无法进行插入或者更新操作。只能读取。* 那是一种行级锁,一旦用户对某个行施加了行级加锁,则该用户可以查询也可以更新被加锁的数据行,其它用户只能查询但不能更新被加锁的数据行.如果其它用户想更新该表中的数据行,则也必须对该表施加行级锁.即使多个用户对一个表均使用了共享更新,但也不允许两个事务同时对一个表进行更新,真正对表进行更新时,是以独占方式锁表,一直到提交或复原该事务为止。行锁永远是独占方式锁。 只有当出现如下之一的条件,便释放共享更新锁: (1)、执行提交(COMMIT)语句; (2)、退出数据库(LOG OFF) (3)、程序停止运行。 那么,什么时候需要使用for update?就是那些需要业务层面数据独占时,可以考虑使用for update。场景上,比如火车票订票,在屏幕上显示邮票,而真正进行出票时,需要重新确定一下这个数据没有被其他客户端修改。所以,在这个确认过程中,可以使用for update。这是统一的解决方案方案问题,需要前期有所准备
2025年03月29日
31 阅读
0 评论
0 点赞
2025-03-18
/usr/sbin/mysqld: Can't open file: '**.frm'(errno: 24 - Too many open files)
kangle主机开的主机多了mysql就容易挂,每次都要重启mysql才能解决,今天抽空查了下日志,看到大量这个报错: /usr/sbin/mysqld: Can't open file: '**.frm'(errno: 24 - Too many open files) 主要原因: lock tables时候文件打开句柄太多导致,可以适当调大文件打开数句柄。 解决方法: 在 /etc/mysql/my.conf 中,你需要增加MySQLs内部 open_files_limit。 所以暂时将这个添加到配置并重启 MySQL。 [mysqld] open_files_limit = 100000 /bin/systemctl restart mysqld.service ============================ 因为kangle主机有很多的小白用户,发现存在很多死进程,为了保证稳定性和长期免维护,又在定时任务中加了定期重启mysql 配置crond服务启动计划需要编辑etc目录下的crontab文件内容,直接用Vim编辑它: vim /etc/crontab vim编辑命令不熟的可以搜索一下,不难,添加一行,比如我要每天凌晨2:30自动重启一次mysql就添加下面这样一行: 30 2 * * * root /bin/systemctl restart mysqld.service 保存重启下crontabs就可以了. /bin/systemctl restart crond.service
2025年03月18日
89 阅读
0 评论
0 点赞
2025-03-18
mysql查询json字段
一张openvpn表里存了一个stop字段是json类型的 表名:openvpn 字段:id int(11) , stop json(255) 假如stop的数据: { "surplus": 119, "opentime": 0 } 1.查询该stop里status这个字段数据: SELECT id,JSON_EXTRACT(stop,'$.status') as status FROM `openvpn` 2.查询该stop里status这个字段为0的数据: SELECT id,JSON_EXTRACT(stop,'$.status') as status FROM `openvpn` WHERE JSON_EXTRACT(stop,'$.status') = 0 3.查询该stop里status这个字段不为1且id大于10000的数据: SELECT id,JSON_EXTRACT(stop,'$.status') as status FROM `openvpn` WHERE JSON_EXTRACT(stop,'$.status') != 1 AND `id` > 10000 备注:通过json_extract函数,获取到了json对象的特定key的值
2025年03月18日
53 阅读
0 评论
0 点赞
2025-03-18
which is not functionally dependent on columns in GROUP BY clause
报错信息:which is not functionally dependent on columns in GROUP BY clause; this is incompatible with sql_mode=only_full_group_by 在对连接表进行select查找时出现以上报错信息。 打开【my.ini】文件 添加如下代码在【mysqld】中 sql_mode=STRICT_TRANS_TABLES,NO_ZERO_IN_DATE,NO_ZERO_DATE,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION 保存,重启mysql即可
2025年03月18日
63 阅读
0 评论
0 点赞
2022-12-07
Mysql和Redis的本质区别
1.mysql和redis的数据库类型 mysql是关系型数据库,主要用于存放持久化数据,将数据存储在硬盘中,读取速度较慢。 redis是NOSQL,即非关系型数据库,也是缓存数据库,即将数据存储在缓存中,缓存的读取速度快,能够大大的提高运行效率,但是保存时间有限 2.mysql的运行机制 mysql作为持久化存储的关系型数据库,相对薄弱的地方在于每次请求访问数据库时,都存在着I/O操作,如果反复频繁的访问数据库。第一:会在反复链接数据库上花费大量时间,从而导致运行效率过慢;第二:反复的访问数据库也会导致数据库的负载过高,那么此时缓存的概念就衍生了出来。 3.缓存 缓存就是数据交换的缓冲区(cache),当浏览器执行请求时,首先会对在缓存中进行查找,如果存在,就获取;否则就访问数据库。 缓存的好处就是读取速度快 4.redis数据库 redis数据库就是一款缓存数据库,用于存储使用频繁的数据,这样减少访问数据库的次数,提高运行效率。 5.redis和mysql的区别总结 (1)类型上 从类型上来说,mysql是关系型数据库,redis是缓存数据库 (2)作用上 mysql用于持久化的存储数据到硬盘,功能强大,但是速度较慢 redis用于存储使用较为频繁的数据到缓存中,读取速度快 (3)需求上 mysql和redis因为需求的不同,一般都是配合使用。
2022年12月07日
342 阅读
0 评论
0 点赞
2022-12-07
报错代码:ERROR 1227 (42000)-解决办法
考虑到数据库 MySQL 的稳定性和安全性,数据库 MySQL 限制了 super、shutdown、file 权限,有时在数据库 MySQL 上执行 set 语句时,会出现如下的报错: #1227-Access denied;you need(at least one of)the SUPER privilege (s) for this operation 解决方案: 删除SQL文件中的SET语句,然后重新导入就可以了 SET @MYSQLDUMP_TEMP_LOG_BIN = @@SESSION.SQL_LOG_BIN; SET @@SESSION.SQL_LOG_BIN= 0; -- -- GTID state at the beginning of the backup -- SET @@GLOBAL.GTID_PURGED='341db1af-a492-11e9-a8b6-6c92bf48c732:1-216839'; SET @@SESSION.SQL_LOG_BIN = @MYSQLDUMP_TEMP_LOG_BIN;
2022年12月07日
738 阅读
0 评论
0 点赞
2022-12-02
#1031 – TABLE STORAGE ENGINE FOR ” DOESN’T HAVE THIS OPTION解决方法
有一个数据库是从mysql5.6要导进5.7。 出现了:1031 – Table storage engine for ‘这里是具体表名’ doesn’t have this option的错误 5.6是:MyISAM,5.7是:InnoDB。 原来5.6的默认为:ROW_FORMAT=FIXED 但是5.7不支持,我没有具体去看资料,可能是我这个版本吧。 然后把:ROW_FORMAT=FIXED改成: ROW_FORMAT=COMPACT 就可以正常导入执行sql了。
2022年12月02日
1,239 阅读
0 评论
0 点赞