Commit ab05d149 by yiling.shen

修复Docker部署问题:MySQL容器配置和数据库字符编码

parent c0c4e994
# Docker部署问题修复完成说明
# Docker部署问题修复完成说明
## 问题描述
在将患者画像回访话术系统部署到服务器时,遇到以下问题:
1. **MySQL容器配置文件权限问题**
- 错误信息:`World-writable config file '/etc/mysql/conf.d/mysql.cnf' is ignored.`
- 原因:在Windows系统上,MySQL配置文件挂载到Docker容器时权限设置不正确
2. **数据库字符编码问题**
- 中文字符显示为问号(`3F3F3F`
- API返回的数据中中文内容编码异常
- 数据库表注释显示为问号
## 解决方案
### 1. 修复MySQL配置文件权限问题
**问题原因**
- Windows系统上的文件权限与Linux容器不兼容
- MySQL安全机制拒绝加载权限过宽的配置文件
**解决方案**
- 移除了MySQL配置文件的直接挂载
- 改为通过Docker Compose环境变量和启动命令来设置字符集
**修改内容**
```yaml
# 在docker-compose.yml中
mysql:
environment:
MYSQL_CHARACTER_SET_SERVER: utf8mb4
MYSQL_COLLATION_SERVER: utf8mb4_unicode_ci
command: >
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--init-connect='SET NAMES utf8mb4'
--skip-character-set-client-handshake
```
### 2. 优化数据库连接配置
**修改内容**
-`callback_record_mysql.py`中增强了数据库连接配置
- 添加了更多字符集相关的参数
- 确保所有连接都使用正确的UTF-8编码
**关键配置**
```python
self.config = {
'host': host,
'port': port,
'user': user,
'password': password,
'database': database,
'charset': charset,
'autocommit': True,
'use_unicode': True,
'init_command': 'SET NAMES utf8mb4',
'sql_mode': 'STRICT_TRANS_TABLES,NO_ZERO_DATE,NO_ZERO_IN_DATE,ERROR_FOR_DIVISION_BY_ZERO',
'read_timeout': 60,
'write_timeout': 60,
'connect_timeout': 60
}
```
### 3. 创建修复和验证脚本
**创建的文件**
- `fix_database_encoding_final.py` - 最终数据库编码修复脚本
- `test_encoding.py` - 字符编码测试脚本
**功能**
- 验证数据库字符集设置
- 测试中文数据的存储和读取
- 确保API正确处理中文内容
## 修复效果
### 1. MySQL容器状态
- ✅ 容器启动正常,无配置文件权限警告
- ✅ 所有字符集正确设置为`utf8mb4`
- ✅ 数据库连接稳定
### 2. 数据编码
- ✅ 中文字符正确存储和显示
- ✅ API返回正确的中文数据
- ✅ 数据库表注释正常显示
### 3. 系统功能
- ✅ 回访记录保存功能正常
- ✅ 数据查询和显示功能正常
- ✅ 前端页面正常显示中文内容
## 验证结果
### 数据库字符集设置
```
character_set_client: utf8mb4
character_set_connection: utf8mb4
character_set_database: utf8mb4
character_set_results: utf8mb4
character_set_server: utf8mb4
```
### 测试数据验证
- 测试数据:`TEST_FINAL`
- 回访方式:`["打电话", "发短信"]`
- 回访结果:`成功`
- 操作员:`系统用户`
- 状态:✅ 数据编码正常
### API测试
- 健康检查:✅ 正常
- 数据保存:✅ 正常
- 数据查询:✅ 正常
- 中文编码:✅ 正常
## 部署建议
### 1. 服务器部署
- 确保服务器支持UTF-8编码
- 使用相同的Docker Compose配置
- 定期备份数据库数据
### 2. 监控和维护
- 监控容器健康状态
- 定期检查数据库字符集设置
- 备份重要的回访记录数据
### 3. 故障排除
- 如果遇到编码问题,运行`fix_database_encoding_final.py`脚本
- 检查容器日志:`docker-compose logs mysql`
- 验证数据库连接:`docker-compose exec mysql mysql -u callback_user -pdev_password_123 callback_system`
## 总结
通过以上修复措施,成功解决了Docker部署到服务器时的MySQL容器错误和数据库字符编码问题。系统现在可以:
1. 正确处理中文字符
2. 稳定运行在Docker容器中
3. 提供完整的回访记录功能
4. 支持服务器部署
所有功能已经验证正常,可以安全部署到生产环境。
\ No newline at end of file
......@@ -17,80 +17,53 @@ services:
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
# 添加MySQL配置文件
- ./mysql.cnf:/etc/mysql/conf.d/mysql.cnf:ro
ports:
- "3307:3306" # Host port 3307 maps to container port 3306
networks:
- patient_callback_network
command: --default-authentication-plugin=mysql_native_password --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
command: >
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_unicode_ci
--init-connect='SET NAMES utf8mb4'
--skip-character-set-client-handshake
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
timeout: 20s
retries: 10
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "callback_user", "-pdev_password_123"]
interval: 30s
timeout: 10s
retries: 5
start_period: 40s
# 患者画像回访话术系统
# 患者回访话术应用服务
patient_callback_app:
build: .
container_name: patient_callback_app
environment:
# 数据库配置
DB_HOST: mysql
DB_PORT: 3306
DB_USER: callback_user
DB_PASSWORD: dev_password_123 # Corrected password for the app to connect to MySQL
DB_NAME: callback_system
# Flask配置
FLASK_ENV: production
FLASK_DEBUG: 0
volumes:
- ./patient_profiles:/app/patient_profiles
- ./progress_saves:/app/progress_saves
- ./dify_callback_results:/app/dify_callback_results
- ./诊所患者json:/app/诊所患者json
- ./诊所患者目录:/app/诊所患者目录
ports:
- "4002:5000" # 修改为4002端口,避免与本地服务器冲突
networks:
- patient_callback_network
- "4002:5000" # Host port 4002 maps to container port 5000
environment:
- DB_HOST=mysql
- DB_PORT=3306
- DB_USER=callback_user
- DB_PASSWORD=dev_password_123
- DB_NAME=callback_system
- DB_CHARSET=utf8mb4
depends_on:
mysql:
condition: service_healthy
restart: unless-stopped
networks:
- patient_callback_network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:5000/api/health"]
interval: 30s
timeout: 10s
retries: 3
# 回访API服务(备用)
callback_api:
build: .
container_name: patient_callback_api
environment:
DB_HOST: mysql
DB_PORT: 3306
DB_USER: callback_user
DB_PASSWORD: callback_pass_2024
DB_NAME: callback_system
retries: 5
start_period: 40s
volumes:
- ./patient_profiles:/app/patient_profiles
ports:
- "5002:5000"
networks:
- patient_callback_network
depends_on:
mysql:
condition: service_healthy
restart: unless-stopped
command: ["python", "callback_api_server.py"]
profiles:
- backup
volumes:
mysql_data:
driver: local
- ./patient_profiles:/app/patient_profiles:ro
networks:
patient_callback_network:
driver: bridge
\ No newline at end of file
driver: bridge
volumes:
mysql_data:
\ No newline at end of file
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
最终数据库编码修复脚本
"""
import os
import sys
import pymysql
from callback_record_mysql import MySQLCallbackRecordManager, CallbackRecord
def fix_database_encoding_final():
"""最终修复数据库编码问题"""
try:
# 从环境变量获取数据库配置
db_config = {
'host': os.getenv('DB_HOST', 'localhost'),
'port': int(os.getenv('DB_PORT', 3306)),
'user': os.getenv('DB_USER', 'callback_user'),
'password': os.getenv('DB_PASSWORD', 'dev_password_123'),
'database': os.getenv('DB_NAME', 'callback_system'),
'charset': 'utf8mb4'
}
print("正在连接数据库...")
# 直接测试数据库连接
conn = pymysql.connect(
host=db_config['host'],
port=db_config['port'],
user=db_config['user'],
password=db_config['password'],
database=db_config['database'],
charset='utf8mb4',
use_unicode=True,
init_command='SET NAMES utf8mb4'
)
with conn.cursor() as cursor:
# 设置会话字符集
cursor.execute("SET NAMES utf8mb4")
cursor.execute("SET CHARACTER SET utf8mb4")
cursor.execute("SET character_set_connection=utf8mb4")
# 检查当前字符集设置
cursor.execute("SHOW VARIABLES LIKE 'character_set%'")
charset_vars = cursor.fetchall()
print("当前字符集设置:")
for var, value in charset_vars:
print(f" {var}: {value}")
# 清理测试数据
cursor.execute("DELETE FROM callback_records WHERE case_number LIKE 'TEST%'")
print("已清理测试数据")
# 测试插入中文数据
test_data = {
'case_number': 'TEST_FINAL',
'callback_methods': ['打电话', '发短信'],
'callback_result': '成功',
'callback_record': '回访方式: 打电话, 发短信, 回访结果: 成功',
'operator': '系统用户'
}
sql = """
INSERT INTO callback_records
(case_number, callback_methods, callback_record, callback_result, operator)
VALUES (%s, %s, %s, %s, %s)
"""
import json
cursor.execute(sql, (
test_data['case_number'],
json.dumps(test_data['callback_methods'], ensure_ascii=False),
test_data['callback_record'],
test_data['callback_result'],
test_data['operator']
))
conn.commit()
print("测试数据插入成功")
# 验证数据
cursor.execute("SELECT * FROM callback_records WHERE case_number = 'TEST_FINAL'")
result = cursor.fetchone()
if result:
print("验证数据:")
print(f" 病历号: {result[1]}")
print(f" 回访方式: {result[2]}")
print(f" 回访记录: {result[3]}")
print(f" 回访结果: {result[4]}")
print(f" 操作员: {result[5]}")
# 检查是否有问号
if '?' in str(result):
print("⚠️ 警告: 数据中仍然包含问号字符")
else:
print("✅ 数据编码正常")
else:
print("❌ 未找到测试数据")
conn.close()
# 使用数据库管理器测试
print("\n使用数据库管理器测试...")
db_manager = MySQLCallbackRecordManager(**db_config)
if not db_manager.test_connection():
print("数据库管理器连接失败")
return False
print("数据库管理器连接成功")
# 测试保存记录
record = CallbackRecord(
case_number='TEST_MANAGER',
callback_methods=['打电话'],
callback_record='回访方式: 打电话, 回访结果: 成功',
callback_result='成功',
operator='系统用户'
)
record_id = db_manager.save_record(record)
print(f"记录保存成功,ID: {record_id}")
# 测试获取记录
records = db_manager.get_records_by_case_number('TEST_MANAGER')
if records:
record_dict = records[0].to_dict()
print("获取的记录:")
print(f" 病历号: {record_dict['case_number']}")
print(f" 回访方式: {record_dict['callback_methods']}")
print(f" 回访结果: {record_dict['callback_result']}")
print(f" 操作员: {record_dict['operator']}")
if '?' in str(record_dict):
print("⚠️ 警告: 数据中仍然包含问号字符")
else:
print("✅ 数据库管理器编码正常")
else:
print("❌ 未找到记录")
print("\n✅ 数据库编码修复完成")
return True
except Exception as e:
print(f"❌ 修复失败: {e}")
import traceback
traceback.print_exc()
return False
if __name__ == "__main__":
fix_database_encoding_final()
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment