|
### MySQL连接字符集丢失问题分析与解决方案
从你描述的问题来看,这是一个典型的MySQL连接字符集在长时间运行后失效的问题。当连接长时间保持时,MySQL服务器可能会重置某些会话级参数,导致字符集设置丢失。
### 问题原因分析
1. **会话超时或空闲连接重置**:
- MySQL服务器有一个`wait_timeout`参数(默认8小时)
- 当连接空闲超过这个时间,服务器会自动断开或重置会话状态
2. **字符集设置未持久化**:
- `SET NAMES 'GBK'`是会话级设置,只对当前连接有效
- 连接重置后,这个设置不会自动恢复
3. **连接池或长连接管理问题**:
- 如果使用连接池,连接可能被复用但字符集未重新设置
- 长时间运行后,连接状态可能不一致
### 解决方案
#### 1. 修改MySQL服务器配置
增加或修改my.cnf文件:
```ini
[mysqld]
character-set-server = gbk
collation-server = gbk_chinese_ci
[client]
default-character-set = gbk
[mysql]
default-character-set = gbk
```
修改后重启MySQL服务器,这样新连接会自动使用GBK字符集。
#### 2. 优化连接初始化逻辑
在每次获取连接时都设置字符集,而不仅仅是在程序启动时:
```易语言
.版本 2
.支持库 mysql
.子程序 获取数据库连接, 整数型
.局部变量 连接, 整数型
// 从连接池获取连接或创建新连接
连接 = 取可用数据库连接 ()
// 每次获取连接后都设置字符集
线程_进入许可区 (数据库操作许可证)
执行SQL语句 (连接, "SET NAMES 'GBK'")
线程_退出许可区 (数据库操作许可证)
返回 (连接)
.子程序尾
.子程序 执行数据库cha询, 整数型
.参数 sql语句, 文本型
.局部变量 连接, 整数型
.局部变量 结果集, 整数型
连接 = 获取数据库连接 ()
结果集 = 执行SQL语句 (连接, sql语句)
返回 (结果集)
.子程序尾
```
#### 3. 实现连接健康检查
在执行SQL前检查连接状态,发现问题时重新连接:
```易语言
.版本 2
.支持库 mysql
.子程序 检查并修复连接, 逻辑型
.参数 连接句柄, 整数型
.局部变量 测试结果, 整数型
// 执行简单的测试cha询
线程_进入许可区 (数据库操作许可证)
测试结果 = 执行SQL语句 (连接句柄, "SELECT 1")
线程_退出许可区 (数据库操作许可证)
// 如果cha询失败,尝试重新连接
如果 (测试结果 = 0)
// 关闭旧连接
关闭MySql (连接句柄)
// 创建新连接
连接句柄 = 连接MySql (读配置项 (取运行目录 () + "\config.ini", "config", "mysql", ), "user", "pwd", "main", )
// 设置字符集
线程_进入许可区 (数据库操作许可证)
执行SQL语句 (连接句柄, "SET NAMES 'GBK'")
线程_退出许可区 (数据库操作许可证)
返回 (连接句柄 != 0)
否则
返回 (真)
结束
.子程序尾
.子程序 执行数据库操作, 整数型
.参数 sql语句, 文本型
.局部变量 连接, 整数型
.局部变量 结果, 整数型
连接 = 取当前数据库连接 ()
// 检查连接状态
如果 (检查并修复连接 (连接) = 假)
返回 (0) // 连接失败
结束
// 执行SQL
结果 = 执行SQL语句 (连接, sql语句)
返回 (结果)
.子程序尾
```
#### 4. 设置适当的超时参数
在MySQL服务器端增加`wait_timeout`值:
```sql
-- 设置连接超时为24小时
SET GLOBAL wait_timeout = 86400;
```
或者在易语言代码中定期执行一个空cha询来保持连接活跃:
```易语言
.版本 2
.支持库 mysql
.子程序 保持连接活跃
.局部变量 连接, 整数型
连接 = 取当前数据库连接 ()
// 每小时执行一次空cha询
线程_进入许可区 (数据库操作许可证)
执行SQL语句 (连接, "SELECT 1")
线程_退出许可区 (数据库操作许可证)
.子程序尾
// 启动一个定时器,每小时调用一次保持连接活跃
启动定时器 (1, 3600000) // 3600000毫秒 = 1小时
.子程序 _定时器1_周期事件
保持连接活跃 ()
.子程序尾
```
### 推荐方案
综合考虑,推荐以下组合方案:
1. 在MySQL服务器配置中设置默认字符集为GBK
2. 每次获取连接时都执行`SET NAMES 'GBK'`
3. 实现连接健康检查机制,发现问题时自动重连
4. 设置合理的`wait_timeout`值或定期执行空cha询
这些措施结合起来可以有效解决长时间运行后字符集丢失的问题,确保你的API后端能够稳定运行。 |
|