提交
This commit is contained in:
1 parent
34a843e790
commit
abfc5cd746
14 files changed
+1595
-1148
No files matched your search
-102
@@ -1,102 +0,0 @@
|
||||
# 学生换班级模块
|
||||
|
||||
## 📁 文件夹说明
|
||||
|
||||
本文件夹包含学生换班级业务模块的相关设计文档和数据库脚本。
|
||||
|
||||
## 📋 文件清单
|
||||
|
||||
### 🗄️ 数据库设计
|
||||
- **[学生换班级记录表.sql](学生换班级记录表.sql)** - 学生换班级记录表的完整建表SQL脚本
|
||||
- **[学生换班级记录表设计说明.md](学生换班级记录表设计说明.md)** - 详细的表结构设计说明文档
|
||||
|
||||
### 🔧 处理脚本(新增)
|
||||
- **[process_student_class_change.sh](process_student_class_change.sh)** - 准实时处理换班级工单的主脚本
|
||||
- **[control_scripts.sh](control_scripts.sh)** - 脚本控制程序,支持启动、停止、重启等操作
|
||||
- **[health_check.sh](health_check.sh)** - 服务健康检查和监控脚本
|
||||
- **[data.conf](data.conf)** - 数据库连接和脚本运行配置
|
||||
- **[README_换班级脚本.md](README_换班级脚本.md)** - 换班级处理脚本的详细技术文档
|
||||
|
||||
## 🎯 业务概述
|
||||
|
||||
学生换班级记录表用于记录学校所有学生换班级的操作历史,包括:
|
||||
- 学生主动申请换班级
|
||||
- 学校根据教学需要调整班级
|
||||
- 学生转专业导致的班级变化
|
||||
- 其他特殊情况的换班级操作
|
||||
|
||||
## 🔑 核心功能
|
||||
|
||||
### 1. 完整的换班级记录
|
||||
- 记录学生的原班级和新班级信息
|
||||
- 保存换班级的原因和类型
|
||||
- 记录换班级的时间和生效时间
|
||||
- 状态管理:未处理/已处理
|
||||
|
||||
### 2. 前端界面支持
|
||||
- 学生信息管理页面集成换班级功能
|
||||
- 单选学生进行换班级操作
|
||||
- 三级级联选择新班级(学院→专业→班级)
|
||||
- 实时展示学生原班级信息
|
||||
|
||||
### 3. 数据追溯和审计
|
||||
- 完整的操作历史记录
|
||||
- 支持数据追溯和审计
|
||||
- 提供统计分析基础数据
|
||||
|
||||
## 📊 数据结构特点
|
||||
|
||||
### 遵循项目规范
|
||||
- ✅ 包含所有强制性基础字段
|
||||
- ✅ 使用雪花ID作为主键
|
||||
- ✅ 支持多租户数据隔离
|
||||
- ✅ 逻辑删除,避免物理删除
|
||||
- ✅ 新增状态字段:0-未处理,1-已处理
|
||||
|
||||
### 关联关系
|
||||
- 学生信息:关联 `xg_student_msg` 表
|
||||
- 班级信息:关联 `xg_class_msg` 表
|
||||
- 专业信息:关联 `xg_major_msg` 表
|
||||
- 学院信息:关联 `sys_dept` 表(dept_category区分层级)
|
||||
|
||||
### 索引优化
|
||||
- 基础索引:租户、删除标志、创建时间
|
||||
- 业务索引:学生ID、班级ID、时间等
|
||||
- 唯一约束:防止重复记录
|
||||
|
||||
## 🔄 业务流程
|
||||
|
||||
```
|
||||
学生申请 → 提交申请 → 辅导员审批 → 院系领导审批 → 教务处审批 → 执行换班级 → 生效
|
||||
```
|
||||
|
||||
## 📈 统计分析支持
|
||||
|
||||
支持多种维度的统计分析:
|
||||
- 按时间统计换班级趋势
|
||||
- 按原因分析换班级分布
|
||||
- 按班级统计换班级情况
|
||||
- 按审批状态统计处理情况
|
||||
|
||||
## 🚀 使用建议
|
||||
|
||||
### 开发注意事项
|
||||
1. **数据一致性**: 换班级操作必须确保相关数据的一致性
|
||||
2. **业务规则**: 严格遵守学校的换班级管理规定
|
||||
3. **审批流程**: 必须经过完整的审批流程
|
||||
4. **文档同步**: 代码变更及时更新相关文档
|
||||
|
||||
### 性能优化
|
||||
1. **分页查询**: 大数据量查询必须分页
|
||||
2. **索引使用**: 充分利用设计的索引
|
||||
3. **缓存策略**: 对常用数据进行适当缓存
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
如有疑问或需要技术支持,请联系项目技术团队。
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025-01-25
|
||||
**维护人员**: AI Assistant
|
||||
**版本**: v1.0.0
|
||||
@@ -1,248 +0,0 @@
|
||||
# 学生换班级处理脚本
|
||||
|
||||
## 📁 概述
|
||||
|
||||
本脚本用于准实时处理学生换班级工单,实现学生信息的自动更新和干部信息的终止处理。参考退学、休学、复学、毕业脚本的架构设计,提供完整的换班级业务处理能力。
|
||||
|
||||
## 🎯 业务需求
|
||||
|
||||
### 1. 干部信息终止
|
||||
- 参考退学等脚本思路,终止学生的干部职务
|
||||
- 设置干部状态为"换班级终止"(cadre_status = '5')
|
||||
- 记录终止原因和时间
|
||||
|
||||
### 2. 学生信息更新
|
||||
- 更新学生基本班级信息(学院、专业、班级、年级等)
|
||||
- 更新预留字段,从新班级表获取完整信息
|
||||
- 特别处理 `academic_level` 字段,对应 `xg_class_msg.class_type`
|
||||
|
||||
## 📋 文件清单
|
||||
|
||||
### 🔧 核心脚本
|
||||
- **[process_student_class_change.sh](process_student_class_change.sh)** - 主处理脚本,实现换班级业务逻辑
|
||||
- **[control_scripts.sh](control_scripts.sh)** - 脚本控制程序,支持启动、停止、重启等操作
|
||||
- **[health_check.sh](health_check.sh)** - 服务健康检查脚本
|
||||
|
||||
### ⚙️ 配置文件
|
||||
- **[data.conf](data.conf)** - 数据库连接配置
|
||||
|
||||
### 📊 数据库设计
|
||||
- **[学生换班级记录表.sql](学生换班级记录表.sql)** - 换班级记录表结构
|
||||
- **[学生换班级记录表设计说明.md](学生换班级记录表设计说明.md)** - 详细设计文档
|
||||
|
||||
## 🔄 处理流程
|
||||
|
||||
```
|
||||
换班级工单提交 → 脚本检测 → 获取新班级信息 → 终止干部职务 → 更新学生信息 → 标记处理完成
|
||||
```
|
||||
|
||||
### 详细步骤
|
||||
|
||||
1. **工单检测**: 扫描 `status = '0'` 的换班级记录
|
||||
2. **班级信息获取**: 从 `xg_class_msg` 表获取新班级完整信息
|
||||
3. **干部信息终止**:
|
||||
- 设置 `is_current = 0`
|
||||
- 设置 `cadre_status = '5'`(换班级终止)
|
||||
- 记录终止日期和原因
|
||||
4. **学生信息更新**:
|
||||
- 更新基础班级信息(college_id, major_id, class_id等)
|
||||
- 更新预留字段(school_system, academic_level, training_type等)
|
||||
- academic_level 对应 class_type
|
||||
5. **工单状态更新**: 设置 `status = '1'` 标记处理完成
|
||||
|
||||
## 🗄️ 数据映射
|
||||
|
||||
### 新班级信息获取
|
||||
```sql
|
||||
SELECT
|
||||
college_id, college_name, major_id, major_name,
|
||||
class_code, class_name, class_type, grade,
|
||||
training_type, counselor_id, counselor_name,
|
||||
class_teacher_id, class_teacher_name, school_system
|
||||
FROM xg_class_msg
|
||||
WHERE id = {new_class_id}
|
||||
```
|
||||
|
||||
### 学生信息更新字段
|
||||
```sql
|
||||
UPDATE xg_student_msg SET
|
||||
-- 基础班级信息
|
||||
college_id = '{college_id}',
|
||||
college_name = '{college_name}',
|
||||
major_id = '{major_id}',
|
||||
major_name = '{major_name}',
|
||||
class_id = '{new_class_id}',
|
||||
class_name = '{class_name}',
|
||||
grade = '{grade}',
|
||||
|
||||
-- 预留字段 (7182-7195行)
|
||||
school_system = '{school_system}',
|
||||
academic_level = '{class_type}', -- 关键映射
|
||||
training_type = '{training_type}',
|
||||
counselor_id = {counselor_id},
|
||||
counselor_name = '{counselor_name}',
|
||||
class_teacher_id = {class_teacher_id},
|
||||
class_teacher_name = '{class_teacher_name}',
|
||||
|
||||
-- 更新信息
|
||||
update_by = {operator_id},
|
||||
update_time = NOW()
|
||||
WHERE id = {student_id}
|
||||
```
|
||||
|
||||
## 🚀 部署使用
|
||||
|
||||
### 1. 配置数据库连接
|
||||
```bash
|
||||
vim data.conf
|
||||
# 修改数据库连接信息
|
||||
```
|
||||
|
||||
### 2. 启动服务
|
||||
```bash
|
||||
# 启动换班级处理服务
|
||||
./control_scripts.sh start class_change
|
||||
|
||||
# 或启动所有服务
|
||||
./control_scripts.sh startall
|
||||
```
|
||||
|
||||
### 3. 查看服务状态
|
||||
```bash
|
||||
# 查看所有服务状态
|
||||
./control_scripts.sh statusall
|
||||
|
||||
# 查看特定服务
|
||||
./control_scripts.sh status class_change
|
||||
```
|
||||
|
||||
### 4. 健康检查
|
||||
```bash
|
||||
# 执行健康检查
|
||||
./health_check.sh
|
||||
|
||||
# 生成详细报告
|
||||
./health_check.sh --report
|
||||
```
|
||||
|
||||
### 5. 停止服务
|
||||
```bash
|
||||
# 停止换班级处理服务
|
||||
./control_scripts.sh stop class_change
|
||||
|
||||
# 或停止所有服务
|
||||
./control_scripts.sh stopall
|
||||
```
|
||||
|
||||
## 📊 监控日志
|
||||
|
||||
### 日志位置
|
||||
- **主日志**: `./student_class_change/process_student_class_change_*.log`
|
||||
- **包含信息**: 处理详情、错误信息、性能统计
|
||||
|
||||
### 日志内容示例
|
||||
```
|
||||
[2025-01-25 10:00:00] [INFO] Starting student class change processing daemon
|
||||
[2025-01-25 10:00:00] [INFO] Processing student change - ID: 123, Student: 20240001 (456), New Class ID: 789
|
||||
[2025-01-25 10:00:00] [INFO] Successfully processed student class change - ID: 123, Student: 20240001
|
||||
```
|
||||
|
||||
## ⚙️ 配置参数
|
||||
|
||||
### data.conf 配置项
|
||||
```bash
|
||||
# 数据库配置
|
||||
DB_HOST="localhost"
|
||||
DB_PORT="3306"
|
||||
DB_NAME="hzdyjs_xg"
|
||||
DB_USER="root"
|
||||
DB_PASS="password"
|
||||
|
||||
# 脚本配置
|
||||
LOG_DIR="./student_class_change"
|
||||
BATCH_SIZE=100 # 每批处理数量
|
||||
MAX_RETRY=3 # 最大重试次数
|
||||
RETRY_DELAY=5 # 重试间隔(秒)
|
||||
CYCLE_INTERVAL=600 # 检查周期(秒)
|
||||
```
|
||||
|
||||
## 🔧 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
1. **数据库连接失败**
|
||||
```bash
|
||||
# 检查配置
|
||||
cat data.conf
|
||||
# 测试连接
|
||||
mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASS $DB_NAME -e "SELECT 1;"
|
||||
```
|
||||
|
||||
2. **服务无法启动**
|
||||
```bash
|
||||
# 检查脚本权限
|
||||
ls -la *.sh
|
||||
# 设置执行权限
|
||||
chmod +x *.sh
|
||||
```
|
||||
|
||||
3. **处理失败**
|
||||
```bash
|
||||
# 查看日志
|
||||
tail -f ./student_class_change/*.log
|
||||
# 检查数据
|
||||
mysql -e "SELECT * FROM xg_student_class_change WHERE status = '0';"
|
||||
```
|
||||
|
||||
### 性能优化
|
||||
|
||||
1. **索引检查**: 确保相关表的索引完整
|
||||
2. **批量处理**: 每次处理适当数量的记录
|
||||
3. **日志轮转**: 定期清理旧日志文件
|
||||
4. **监控资源**: 监控CPU、内存、磁盘使用情况
|
||||
|
||||
## 📈 统计监控
|
||||
|
||||
### 处理统计
|
||||
```sql
|
||||
-- 查看处理统计
|
||||
SELECT
|
||||
COUNT(*) as total_records,
|
||||
SUM(CASE WHEN status = '0' THEN 1 ELSE 0 END) as pending,
|
||||
SUM(CASE WHEN status = '1' THEN 1 ELSE 0 END) as processed
|
||||
FROM xg_student_class_change
|
||||
WHERE deleted = 0;
|
||||
|
||||
-- 查看最近处理情况
|
||||
SELECT
|
||||
DATE(update_time) as process_date,
|
||||
COUNT(*) as processed_count
|
||||
FROM xg_student_class_change
|
||||
WHERE status = '1'
|
||||
AND update_time >= DATE_SUB(NOW(), INTERVAL 7 DAY)
|
||||
GROUP BY DATE(update_time)
|
||||
ORDER BY process_date DESC;
|
||||
```
|
||||
|
||||
## 🔄 扩展开发
|
||||
|
||||
### 添加新的业务逻辑
|
||||
1. 在 `process_student_class_change()` 函数中添加处理步骤
|
||||
2. 更新事务SQL,确保数据一致性
|
||||
3. 添加相应的日志记录
|
||||
4. 更新健康检查逻辑
|
||||
|
||||
### 自定义配置
|
||||
1. 在 `data.conf` 中添加新配置项
|
||||
2. 在脚本中读取和使用配置
|
||||
3. 更新文档说明
|
||||
|
||||
## 📞 技术支持
|
||||
|
||||
如有疑问或需要技术支持,请联系项目技术团队。
|
||||
|
||||
---
|
||||
|
||||
**创建时间**: 2025-01-25
|
||||
**维护人员**: AI Assistant
|
||||
**版本**: v1.0.0
|
||||
@@ -1,332 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===========================================
|
||||
# 学生换班级处理脚本控制程序
|
||||
# 用于启动、停止、重启处理脚本
|
||||
# ===========================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Load configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "错误:配置文件 $CONFIG_FILE 未找到!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Script definitions
|
||||
declare -A SCRIPTS=(
|
||||
["class_change"]="process_student_class_change.sh"
|
||||
)
|
||||
|
||||
# PID files
|
||||
PID_DIR="${SCRIPT_DIR}/pids"
|
||||
mkdir -p "$PID_DIR"
|
||||
|
||||
# Functions
|
||||
log() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "[$timestamp] [$level] $message"
|
||||
}
|
||||
|
||||
get_pid_file() {
|
||||
local script_name="$1"
|
||||
echo "${PID_DIR}/${script_name}.pid"
|
||||
}
|
||||
|
||||
get_lock_file() {
|
||||
local script_name="$1"
|
||||
echo "${SCRIPT_DIR}/${script_name}.lock"
|
||||
}
|
||||
|
||||
is_running() {
|
||||
local script_name="$1"
|
||||
local pid_file=$(get_pid_file "$script_name")
|
||||
local lock_file=$(get_lock_file "$script_name")
|
||||
|
||||
# Check PID file
|
||||
if [[ -f "$pid_file" ]]; then
|
||||
local pid=$(cat "$pid_file")
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
return 0 # Running
|
||||
else
|
||||
log "WARN" "删除脚本 $script_name 的过期PID文件"
|
||||
rm -f "$pid_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check lock file
|
||||
if [[ -f "$lock_file" ]]; then
|
||||
local lock_pid=$(cat "$lock_file")
|
||||
if kill -0 "$lock_pid" 2>/dev/null; then
|
||||
return 0 # Running
|
||||
else
|
||||
log "WARN" "删除脚本 $script_name 的过期锁定文件"
|
||||
rm -f "$lock_file"
|
||||
fi
|
||||
fi
|
||||
|
||||
return 1 # Not running
|
||||
}
|
||||
|
||||
start_script() {
|
||||
local script_name="$1"
|
||||
local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}"
|
||||
local pid_file=$(get_pid_file "$script_name")
|
||||
|
||||
if [[ ! -f "$script_file" ]]; then
|
||||
log "ERROR" "脚本文件未找到: $script_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if is_running "$script_name"; then
|
||||
log "INFO" "$script_name 已在运行"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "INFO" "正在启动 $script_name..."
|
||||
chmod +x "$script_file"
|
||||
|
||||
# Start script in background
|
||||
nohup "$script_file" > /dev/null 2>&1 &
|
||||
local pid=$!
|
||||
|
||||
# Save PID
|
||||
echo $pid > "$pid_file"
|
||||
|
||||
# Wait a moment and check if it's still running
|
||||
sleep 2
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
log "INFO" "$script_name 启动成功 (PID: $pid)"
|
||||
return 0
|
||||
else
|
||||
log "ERROR" "$script_name 启动失败"
|
||||
rm -f "$pid_file"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
stop_script() {
|
||||
local script_name="$1"
|
||||
local pid_file=$(get_pid_file "$script_name")
|
||||
local lock_file=$(get_lock_file "$script_name")
|
||||
|
||||
if ! is_running "$script_name"; then
|
||||
log "INFO" "$script_name 未运行"
|
||||
return 0
|
||||
fi
|
||||
|
||||
log "INFO" "正在停止 $script_name..."
|
||||
|
||||
# Try graceful shutdown first
|
||||
local pids=()
|
||||
[[ -f "$pid_file" ]] && pids+=($(cat "$pid_file"))
|
||||
[[ -f "$lock_file" ]] && pids+=($(cat "$lock_file"))
|
||||
|
||||
for pid in "${pids[@]}"; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
|
||||
# Wait for graceful shutdown
|
||||
local count=0
|
||||
while [[ $count -lt 10 ]] && is_running "$script_name"; do
|
||||
sleep 1
|
||||
((count++))
|
||||
done
|
||||
|
||||
# Force kill if still running
|
||||
if is_running "$script_name"; then
|
||||
log "WARN" "Graceful shutdown failed, force killing $script_name..."
|
||||
for pid in "${pids[@]}"; do
|
||||
if kill -0 "$pid" 2>/dev/null; then
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
fi
|
||||
done
|
||||
sleep 1
|
||||
fi
|
||||
|
||||
# Clean up files
|
||||
rm -f "$pid_file" "$lock_file"
|
||||
|
||||
if is_running "$script_name"; then
|
||||
log "ERROR" "Failed to stop $script_name"
|
||||
return 1
|
||||
else
|
||||
log "INFO" "$script_name stopped successfully"
|
||||
return 0
|
||||
fi
|
||||
}
|
||||
|
||||
restart_script() {
|
||||
local script_name="$1"
|
||||
|
||||
log "INFO" "正在重启 $script_name..."
|
||||
if stop_script "$script_name" && start_script "$script_name"; then
|
||||
log "INFO" "$script_name 重启成功"
|
||||
return 0
|
||||
else
|
||||
log "ERROR" "$script_name 重启失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
status_script() {
|
||||
local script_name="$1"
|
||||
|
||||
if is_running "$script_name"; then
|
||||
local pid_file=$(get_pid_file "$script_name")
|
||||
local lock_file=$(get_lock_file "$script_name")
|
||||
local pid=""
|
||||
|
||||
if [[ -f "$pid_file" ]]; then
|
||||
pid=$(cat "$pid_file")
|
||||
elif [[ -f "$lock_file" ]]; then
|
||||
pid=$(cat "$lock_file")
|
||||
fi
|
||||
|
||||
echo "$script_name 正在运行 (PID: $pid)"
|
||||
return 0
|
||||
else
|
||||
echo "$script_name 未运行"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
usage() {
|
||||
echo "用法: $0 {start|stop|restart|status} {script_name}"
|
||||
echo " $0 {startall|stopall|restartall|statusall}"
|
||||
echo ""
|
||||
echo "可用脚本:"
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
echo " $script - ${SCRIPTS[$script]}"
|
||||
done
|
||||
echo ""
|
||||
echo "示例:"
|
||||
echo " $0 start class_change # 启动换班级处理"
|
||||
echo " $0 stop class_change # 停止换班级处理"
|
||||
echo " $0 restart class_change # 重启换班级处理"
|
||||
echo " $0 status class_change # 检查换班级处理状态"
|
||||
echo " $0 startall # 启动所有脚本"
|
||||
echo " $0 stopall # 停止所有脚本"
|
||||
echo " $0 statusall # 检查所有脚本状态"
|
||||
}
|
||||
|
||||
# Main logic
|
||||
case "${1:-}" in
|
||||
start)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "${SCRIPTS[$2]:-}" ]]; then
|
||||
start_script "$2"
|
||||
else
|
||||
echo "未知脚本: $2"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
stop)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "${SCRIPTS[$2]:-}" ]]; then
|
||||
stop_script "$2"
|
||||
else
|
||||
echo "未知脚本: $2"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
restart)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "${SCRIPTS[$2]:-}" ]]; then
|
||||
restart_script "$2"
|
||||
else
|
||||
echo "未知脚本: $2"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
status)
|
||||
if [[ -z "${2:-}" ]]; then
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
if [[ -n "${SCRIPTS[$2]:-}" ]]; then
|
||||
status_script "$2"
|
||||
else
|
||||
echo "未知脚本: $2"
|
||||
usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
startall)
|
||||
log "INFO" "正在启动所有脚本..."
|
||||
local failed=()
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
if ! start_script "$script"; then
|
||||
failed+=("$script")
|
||||
fi
|
||||
done
|
||||
if [[ ${#failed[@]} -eq 0 ]]; then
|
||||
log "INFO" "所有脚本启动成功"
|
||||
else
|
||||
log "ERROR" "启动脚本失败: ${failed[*]}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
stopall)
|
||||
log "INFO" "正在停止所有脚本..."
|
||||
local failed=()
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
if ! stop_script "$script"; then
|
||||
failed+=("$script")
|
||||
fi
|
||||
done
|
||||
if [[ ${#failed[@]} -eq 0 ]]; then
|
||||
log "INFO" "所有脚本停止成功"
|
||||
else
|
||||
log "ERROR" "停止脚本失败: ${failed[*]}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
restartall)
|
||||
log "INFO" "正在重启所有脚本..."
|
||||
local failed=()
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
if ! restart_script "$script"; then
|
||||
failed+=("$script")
|
||||
fi
|
||||
done
|
||||
if [[ ${#failed[@]} -eq 0 ]]; then
|
||||
log "INFO" "所有脚本重启成功"
|
||||
else
|
||||
log "ERROR" "重启脚本失败: ${failed[*]}"
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
statusall)
|
||||
log "INFO" "正在检查所有脚本的状态..."
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
echo -n "$script: "
|
||||
status_script "$script"
|
||||
done
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,17 @@
|
||||
# Database configuration
|
||||
DB_HOST="172.16.0.67"
|
||||
DB_PORT="3306"
|
||||
DB_NAME="hzdyjs_xg"
|
||||
DB_USER="root"
|
||||
DB_PASS="Hzdyjs@Root@123456"
|
||||
|
||||
# Script configuration
|
||||
LOG_DIR="${SCRIPT_DIR}/student_class_change"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCK_FILE="${SCRIPT_DIR}/script.lock"
|
||||
|
||||
# Processing configuration
|
||||
BATCH_SIZE=100
|
||||
MAX_RETRY=3
|
||||
RETRY_DELAY=5
|
||||
CYCLE_INTERVAL=600 # 循环间隔时间(秒),默认10分钟
|
||||
@@ -1,348 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===========================================
|
||||
# 学生换班级处理服务健康检查脚本
|
||||
# 用于监控服务运行状态和数据库连接
|
||||
# ===========================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
CONTROL_SCRIPT="${SCRIPT_DIR}/control_scripts.sh"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Load configuration
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo -e "${RED}错误:配置文件 $CONFIG_FILE 未找到!${NC}"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Functions
|
||||
log() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo -e "${timestamp} [$level] $message"
|
||||
}
|
||||
|
||||
success() {
|
||||
echo -e "${GREEN}✓ $1${NC}"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}✗ $1${NC}"
|
||||
}
|
||||
|
||||
warning() {
|
||||
echo -e "${YELLOW}⚠ $1${NC}"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "${BLUE}ℹ $1${NC}"
|
||||
}
|
||||
|
||||
# 检查数据库连接
|
||||
check_database() {
|
||||
info "正在检查数据库连接..."
|
||||
|
||||
local db_test
|
||||
if db_test=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1 as test;" 2>/dev/null); then
|
||||
if echo "$db_test" | grep -q "test"; then
|
||||
success "数据库连接成功"
|
||||
return 0
|
||||
else
|
||||
error "数据库查询失败"
|
||||
return 1
|
||||
fi
|
||||
else
|
||||
error "数据库连接失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查服务状态
|
||||
check_service() {
|
||||
local service_name="$1"
|
||||
local service_desc="$2"
|
||||
|
||||
info "正在检查 $service_desc..."
|
||||
|
||||
if [[ ! -x "$CONTROL_SCRIPT" ]]; then
|
||||
error "控制脚本未找到或不可执行: $CONTROL_SCRIPT"
|
||||
return 1
|
||||
fi
|
||||
|
||||
local status_output
|
||||
status_output=$("$CONTROL_SCRIPT" status "$service_name" 2>/dev/null)
|
||||
|
||||
if echo "$status_output" | grep -q "is running"; then
|
||||
success "$service_desc 正在运行"
|
||||
|
||||
# 提取PID(如果可用)
|
||||
local pid
|
||||
pid=$(echo "$status_output" | grep -o "PID: [0-9]*" | cut -d' ' -f2)
|
||||
if [[ -n "$pid" ]]; then
|
||||
info " 进程ID: $pid"
|
||||
fi
|
||||
|
||||
return 0
|
||||
else
|
||||
error "$service_desc 未运行"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查待处理记录
|
||||
check_pending_records() {
|
||||
info "正在检查待处理的换班级记录..."
|
||||
|
||||
local pending_count
|
||||
if pending_count=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "
|
||||
SELECT COUNT(*) as pending
|
||||
FROM xg_student_class_change
|
||||
WHERE status = '0' AND deleted = 0;
|
||||
" 2>/dev/null | tail -n1); then
|
||||
|
||||
if [[ "$pending_count" -eq 0 ]]; then
|
||||
success "无待处理的换班级记录"
|
||||
elif [[ "$pending_count" -lt 10 ]]; then
|
||||
warning "$pending_count 条待处理的换班级记录"
|
||||
else
|
||||
error "$pending_count 条待处理的换班级记录 (积压严重)"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
error "检查待处理记录失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查最近的处理活动
|
||||
check_recent_processing() {
|
||||
info "正在检查最近的处理活动..."
|
||||
|
||||
local recent_count
|
||||
if recent_count=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "
|
||||
SELECT COUNT(*) as recent
|
||||
FROM xg_student_class_change
|
||||
WHERE status = '1'
|
||||
AND update_time >= DATE_SUB(NOW(), INTERVAL 1 HOUR)
|
||||
AND deleted = 0;
|
||||
" 2>/dev/null | tail -n1); then
|
||||
|
||||
if [[ "$recent_count" -gt 0 ]]; then
|
||||
success "最近一小时处理了 $recent_count 条记录"
|
||||
else
|
||||
warning "最近一小时未处理任何记录"
|
||||
fi
|
||||
return 0
|
||||
else
|
||||
error "检查最近处理活动失败"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查日志文件
|
||||
check_logs() {
|
||||
info "正在检查日志文件..."
|
||||
|
||||
if [[ -d "$LOG_DIR" ]]; then
|
||||
local log_count
|
||||
log_count=$(find "$LOG_DIR" -name "*.log" -type f -mtime -1 2>/dev/null | wc -l)
|
||||
|
||||
if [[ "$log_count" -gt 0 ]]; then
|
||||
success "发现最近的日志文件 ($log_count 个文件来自最近24小时)"
|
||||
else
|
||||
warning "未发现最近的日志文件"
|
||||
fi
|
||||
|
||||
# 检查错误日志
|
||||
local error_count
|
||||
error_count=$(find "$LOG_DIR" -name "*.log" -type f -exec grep -l "ERROR" {} \; 2>/dev/null | wc -l)
|
||||
|
||||
if [[ "$error_count" -gt 0 ]]; then
|
||||
warning "$error_count 个日志文件包含错误"
|
||||
else
|
||||
success "最近日志中未发现错误消息"
|
||||
fi
|
||||
else
|
||||
error "日志目录未找到: $LOG_DIR"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查磁盘空间
|
||||
check_disk_space() {
|
||||
info "正在检查磁盘空间..."
|
||||
|
||||
local disk_usage
|
||||
disk_usage=$(df "$SCRIPT_DIR" | tail -1 | awk '{print $5}' | sed 's/%//')
|
||||
|
||||
if [[ "$disk_usage" -lt 80 ]]; then
|
||||
success "磁盘使用率: ${disk_usage}%"
|
||||
elif [[ "$disk_usage" -lt 90 ]]; then
|
||||
warning "磁盘使用率: ${disk_usage}% (接近限制)"
|
||||
else
|
||||
error "磁盘使用率: ${disk_usage}% (严重)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 检查内存使用情况
|
||||
check_memory() {
|
||||
info "正在检查内存使用情况..."
|
||||
|
||||
local mem_usage
|
||||
mem_usage=$(free | grep Mem | awk '{printf "%.0f", $3/$2 * 100.0}')
|
||||
|
||||
if [[ "$mem_usage" -lt 80 ]]; then
|
||||
success "内存使用率: ${mem_usage}%"
|
||||
elif [[ "$mem_usage" -lt 90 ]]; then
|
||||
warning "内存使用率: ${mem_usage}% (接近限制)"
|
||||
else
|
||||
error "内存使用率: ${mem_usage}% (严重)"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate health report
|
||||
generate_report() {
|
||||
local report_file="${SCRIPT_DIR}/health_report_$(date +%Y%m%d_%H%M%S).txt"
|
||||
|
||||
{
|
||||
echo "=== 学生换班级处理服务健康检查报告 ==="
|
||||
echo "检查时间: $(date)"
|
||||
echo "服务器信息: $(hostname)"
|
||||
echo ""
|
||||
|
||||
echo "=== 数据库连接 ==="
|
||||
if check_database; then
|
||||
echo "✓ 数据库连接正常"
|
||||
else
|
||||
echo "✗ 数据库连接异常"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 服务状态 ==="
|
||||
if check_service "class_change" "学生换班级处理服务"; then
|
||||
echo "✓ 学生换班级处理服务运行正常"
|
||||
else
|
||||
echo "✗ 学生换班级处理服务未运行"
|
||||
fi
|
||||
echo ""
|
||||
|
||||
echo "=== 业务数据检查 ==="
|
||||
check_pending_records
|
||||
echo ""
|
||||
check_recent_processing
|
||||
echo ""
|
||||
|
||||
echo "=== 系统资源 ==="
|
||||
check_disk_space
|
||||
echo ""
|
||||
check_memory
|
||||
echo ""
|
||||
|
||||
echo "=== 日志检查 ==="
|
||||
check_logs
|
||||
echo ""
|
||||
|
||||
echo "报告生成完成"
|
||||
} > "$report_file" 2>/dev/null
|
||||
|
||||
success "健康检查报告已生成: $report_file"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
echo ""
|
||||
echo "=== 学生换班级处理服务健康检查 ==="
|
||||
echo "检查时间: $(date)"
|
||||
echo "服务器信息: $(hostname)"
|
||||
echo ""
|
||||
|
||||
local checks_passed=0
|
||||
local total_checks=0
|
||||
|
||||
# Database connection
|
||||
echo "=== 数据库连接 ==="
|
||||
((total_checks++))
|
||||
check_database && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
# Service status
|
||||
echo "=== 服务状态 ==="
|
||||
((total_checks++))
|
||||
check_service "class_change" "学生换班级处理服务" && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
# Business data
|
||||
echo "=== 业务数据检查 ==="
|
||||
((total_checks++))
|
||||
check_pending_records && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
((total_checks++))
|
||||
check_recent_processing && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
# System resources
|
||||
echo "=== 系统资源 ==="
|
||||
((total_checks++))
|
||||
check_disk_space && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
((total_checks++))
|
||||
check_memory && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
# Logs
|
||||
echo "=== 日志检查 ==="
|
||||
((total_checks++))
|
||||
check_logs && ((checks_passed++))
|
||||
echo ""
|
||||
|
||||
# 总结
|
||||
echo "=== 检查总结 ==="
|
||||
local success_rate=$((checks_passed * 100 / total_checks))
|
||||
echo "通过检查: $checks_passed/$total_checks ($success_rate%)"
|
||||
|
||||
if [[ $success_rate -eq 100 ]]; then
|
||||
success "所有检查通过,服务运行正常"
|
||||
exit 0
|
||||
elif [[ $success_rate -ge 80 ]]; then
|
||||
warning "大部分检查通过,服务运行基本正常"
|
||||
exit 0
|
||||
else
|
||||
error "多项检查失败,建议立即检查服务状态"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# 命令行选项
|
||||
case "${1:-}" in
|
||||
--report)
|
||||
generate_report
|
||||
;;
|
||||
--help|-h)
|
||||
echo "用法: $0 [选项]"
|
||||
echo ""
|
||||
echo "选项:"
|
||||
echo " --report 生成详细的健康检查报告"
|
||||
echo " --help 显示此帮助信息"
|
||||
echo ""
|
||||
echo "无选项时,执行标准健康检查。"
|
||||
;;
|
||||
*)
|
||||
main "$@"
|
||||
;;
|
||||
esac
|
||||
@@ -0,0 +1,337 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===========================================
|
||||
# 学生换班级处理脚本 (修复版本)
|
||||
# 处理类型: CLASS_CHANGE(换班级)
|
||||
# ===========================================
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Force C locale to ensure consistent behavior across systems
|
||||
export LANG=C
|
||||
export LC_ALL=C
|
||||
|
||||
# Load configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "错误:配置文件 $CONFIG_FILE 未找到!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Create log directory
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Log file
|
||||
LOG_FILE="${LOG_DIR}/process_student_class_change_fixed_$(date +%Y%m%d_%H%M%S).log"
|
||||
|
||||
# Lock file to prevent multiple instances
|
||||
LOCK_FILE="${SCRIPT_DIR}/process_student_class_change_fixed.lock"
|
||||
|
||||
# Functions
|
||||
log() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
error_exit() {
|
||||
local message="$1"
|
||||
log "ERROR" "$message"
|
||||
# Remove lock file
|
||||
[[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Database functions - Fixed version
|
||||
execute_sql() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$sql" 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "SQL执行失败 (退出码: $exit_code)"
|
||||
log "ERROR" "数据库连接: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME"
|
||||
log "ERROR" "失败的SQL: $sql"
|
||||
log "ERROR" "MySQL错误详情: $result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Database query function - Fixed version for cross-platform compatibility
|
||||
execute_query() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
# Use -ss for ultra-silent mode to ensure clean tab-separated output
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "数据库查询执行失败 (退出码: $exit_code)"
|
||||
log "ERROR" "数据库连接: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME"
|
||||
log "ERROR" "失败的SQL: $sql"
|
||||
log "ERROR" "MySQL错误详情: $result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Process student class change
|
||||
process_student_class_change() {
|
||||
local record_id="$1"
|
||||
local student_id="$2"
|
||||
local student_no="$3"
|
||||
local new_class_id="$4"
|
||||
local operator_id="${5:-1}"
|
||||
|
||||
# Validate input parameters
|
||||
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$new_class_id" ]]; then
|
||||
log "ERROR" "参数不完整 - record_id: '$record_id', student_id: '$student_id', student_no: '$student_no', new_class_id: '$new_class_id'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "INFO" "Processing student class change - ID: $record_id, Student: $student_no ($student_id), New Class ID: $new_class_id"
|
||||
|
||||
# Get new class information
|
||||
local class_info_sql="
|
||||
SELECT
|
||||
c.college_id, c.college_name, c.major_id, c.major_name,
|
||||
c.class_code, c.class_name, c.class_type, c.grade,
|
||||
c.training_type, c.counselor_id, c.counselor_name,
|
||||
c.class_teacher_id, c.class_teacher_name, c.school_system
|
||||
FROM xg_class_msg c
|
||||
WHERE c.id = $new_class_id AND c.deleted = 0
|
||||
"
|
||||
|
||||
local class_info
|
||||
class_info=$(execute_query "$class_info_sql")
|
||||
|
||||
if [[ -z "$class_info" || "$class_info" == *"Empty set"* ]]; then
|
||||
log "ERROR" "获取班级ID为 $new_class_id 的班级信息失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Parse class information - Fixed parsing logic
|
||||
local class_data
|
||||
class_data=$(echo "$class_info" | grep -v "^mysql:" | grep -v "^$" | head -n 1)
|
||||
|
||||
if [[ -z "$class_data" ]]; then
|
||||
log "ERROR" "解析班级信息失败,无法获取数据行"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Use cut to extract specific fields reliably
|
||||
local college_id=$(echo "$class_data" | cut -f1)
|
||||
local college_name=$(echo "$class_data" | cut -f2)
|
||||
local major_id=$(echo "$class_data" | cut -f3)
|
||||
local major_name=$(echo "$class_data" | cut -f4)
|
||||
local class_code=$(echo "$class_data" | cut -f5)
|
||||
local class_name=$(echo "$class_data" | cut -f6)
|
||||
local class_type=$(echo "$class_data" | cut -f7)
|
||||
local grade=$(echo "$class_data" | cut -f8)
|
||||
local training_type=$(echo "$class_data" | cut -f9)
|
||||
local counselor_id=$(echo "$class_data" | cut -f10)
|
||||
local counselor_name=$(echo "$class_data" | cut -f11)
|
||||
local class_teacher_id=$(echo "$class_data" | cut -f12)
|
||||
local class_teacher_name=$(echo "$class_data" | cut -f13)
|
||||
local school_system=$(echo "$class_data" | cut -f14)
|
||||
|
||||
# Handle NULL values for IDs
|
||||
local counselor_id_value class_teacher_id_value
|
||||
if [[ "$counselor_id" == "NULL" || -z "$counselor_id" ]]; then
|
||||
counselor_id_value="NULL"
|
||||
else
|
||||
counselor_id_value="'$counselor_id'"
|
||||
fi
|
||||
|
||||
if [[ "$class_teacher_id" == "NULL" || -z "$class_teacher_id" ]]; then
|
||||
class_teacher_id_value="NULL"
|
||||
else
|
||||
class_teacher_id_value="'$class_teacher_id'"
|
||||
fi
|
||||
|
||||
# Start transaction
|
||||
local transaction_sql="
|
||||
START TRANSACTION;
|
||||
|
||||
-- 1. Backup original data to his tables (ignore if already exists)
|
||||
INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id;
|
||||
INSERT IGNORE INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = $student_id;
|
||||
|
||||
-- 2. Terminate cadre positions (干部信息终止)
|
||||
UPDATE xg_class_pos_msg SET
|
||||
is_current = 0,
|
||||
cadre_status = '4', -- 免职
|
||||
dismissal_date = CURDATE(),
|
||||
dismissal_reason = '学生换班级',
|
||||
term_end_date = CURDATE(),
|
||||
term_duration = TIMESTAMPDIFF(MONTH, term_start_date, CURDATE()),
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE student_id = $student_id AND is_current = 1;
|
||||
|
||||
-- 3. Update student information with new class data
|
||||
UPDATE xg_student_msg SET
|
||||
-- 基础班级信息
|
||||
college_id = '$college_id',
|
||||
college_name = '$college_name',
|
||||
major_id = '$major_id',
|
||||
major_name = '$major_name',
|
||||
class_id = '$new_class_id',
|
||||
class_name = '$class_name',
|
||||
grade = '$grade',
|
||||
|
||||
-- 预留字段从班级表关联获取的数据 (7182-7195行)
|
||||
school_system = '$school_system',
|
||||
academic_level = '$class_type', -- class_type 对应 academic_level
|
||||
training_type = '$training_type',
|
||||
counselor_id = $counselor_id_value,
|
||||
counselor_name = '$counselor_name',
|
||||
class_teacher_id = $class_teacher_id_value,
|
||||
class_teacher_name = '$class_teacher_name',
|
||||
|
||||
-- 更新信息
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE id = $student_id;
|
||||
|
||||
-- 4. Update class change record status
|
||||
UPDATE xg_student_class_change SET
|
||||
status = '1', -- 已处理
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE id = $record_id;
|
||||
|
||||
COMMIT;
|
||||
"
|
||||
|
||||
# 执行事务
|
||||
if execute_sql "$transaction_sql"; then
|
||||
log "INFO" "成功处理学生换班级 - ID: $record_id, 学生: $student_no"
|
||||
return 0
|
||||
else
|
||||
log "ERROR" "处理学生换班级失败 - ID: $record_id, 学生: $student_no"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
log "INFO" "启动学生换班级处理守护进程 (修复版本)"
|
||||
log "INFO" "处理类型: CLASS_CHANGE(换班级)"
|
||||
log "INFO" "以连续模式运行,间隔10分钟"
|
||||
|
||||
# 测试数据库连接
|
||||
log "INFO" "正在测试数据库连接..."
|
||||
log "INFO" "连接信息: $DB_USER@$DB_HOST:$DB_PORT/$DB_NAME"
|
||||
if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then
|
||||
error_exit "数据库连接失败 - 请检查连接参数和网络连接"
|
||||
fi
|
||||
log "INFO" "数据库连接测试成功"
|
||||
|
||||
# Main processing loop
|
||||
while true; do
|
||||
log "INFO" "开始新的处理周期"
|
||||
|
||||
# 获取未处理的记录
|
||||
local query_sql="
|
||||
SELECT id, student_id, student_no, new_class_id, update_by
|
||||
FROM xg_student_class_change
|
||||
WHERE status = '0'
|
||||
AND deleted = 0
|
||||
AND effective_time <= NOW()
|
||||
ORDER BY create_time ASC
|
||||
LIMIT $BATCH_SIZE;
|
||||
"
|
||||
|
||||
local records
|
||||
if ! records=$(execute_query "$query_sql"); then
|
||||
log "ERROR" "获取待处理记录失败,${CYCLE_INTERVAL}秒后重试"
|
||||
sleep $CYCLE_INTERVAL
|
||||
continue
|
||||
fi
|
||||
|
||||
# 检查是否有记录需要处理(过滤掉空行、MySQL警告信息和表头)
|
||||
local clean_records
|
||||
# 过滤掉MySQL警告、空行,然后排除表头行(第一行通常是列名)
|
||||
local filtered_records
|
||||
filtered_records=$(echo "$records" | grep -v "^mysql:" | grep -v "^$" | sed '1d')
|
||||
clean_records=$(echo "$filtered_records" | wc -l)
|
||||
|
||||
# 去除可能的空白字符
|
||||
clean_records=$(echo "$clean_records" | tr -d ' ')
|
||||
|
||||
if [[ $clean_records -eq 0 ]]; then
|
||||
log "INFO" "未找到未处理的记录,正在等待..."
|
||||
else
|
||||
log "INFO" "找到 $clean_records 条待处理记录"
|
||||
# 调试:显示前几条记录的信息
|
||||
if [[ $clean_records -gt 0 ]]; then
|
||||
log "DEBUG" "待处理记录预览:"
|
||||
echo "$filtered_records" | head -3 | while read -r line; do
|
||||
log "DEBUG" " $line"
|
||||
done
|
||||
fi
|
||||
|
||||
local processed_count=0
|
||||
local failed_count=0
|
||||
|
||||
# Create a temporary file to store records for processing
|
||||
local temp_records_file="${SCRIPT_DIR}/temp_class_change_records_fixed_$$.txt"
|
||||
echo "$filtered_records" > "$temp_records_file"
|
||||
|
||||
# Process each record from the temporary file
|
||||
while IFS=$'\t' read -r record_id student_id student_no new_class_id operator_id; do
|
||||
# Skip empty lines or invalid records
|
||||
[[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$new_class_id" ]] && continue
|
||||
|
||||
# Log the record being processed for debugging
|
||||
log "INFO" "读取到记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 新班级ID: $new_class_id, 操作员: ${operator_id:-1}"
|
||||
|
||||
local retry_count=0
|
||||
local success=false
|
||||
|
||||
while [[ $retry_count -lt $MAX_RETRY && $success == false ]]; do
|
||||
if process_student_class_change "$record_id" "$student_id" "$student_no" "$new_class_id" "$operator_id"; then
|
||||
success=true
|
||||
((processed_count++))
|
||||
else
|
||||
((retry_count++))
|
||||
if [[ $retry_count -lt $MAX_RETRY ]]; then
|
||||
log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)"
|
||||
sleep $RETRY_DELAY
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $success == false ]]; then
|
||||
((failed_count++))
|
||||
log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id"
|
||||
fi
|
||||
|
||||
done < "$temp_records_file"
|
||||
|
||||
# Clean up temporary file
|
||||
rm -f "$temp_records_file"
|
||||
|
||||
log "INFO" "处理周期完成 - 已处理: $processed_count, 失败: $failed_count"
|
||||
fi
|
||||
|
||||
# 等待配置的间隔时间后开始下一个周期
|
||||
log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个处理周期..."
|
||||
sleep $CYCLE_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -0,0 +1,220 @@
|
||||
# 学生状态变更处理系统 - 生产环境部署指南
|
||||
|
||||
## 📋 概述
|
||||
|
||||
本系统包含两个核心处理脚本,已修复Ubuntu环境兼容性问题:
|
||||
- `process_student_changes_fixed.sh` - 学生状态变更处理(休学/退学/毕业)
|
||||
- `process_student_resume_fixed.sh` - 学生复学处理
|
||||
|
||||
## 🚀 快速启动
|
||||
|
||||
### 1. 启动所有服务
|
||||
```bash
|
||||
cd /path/to/scripts
|
||||
./control_scripts.sh startall
|
||||
```
|
||||
|
||||
### 2. 检查运行状态
|
||||
```bash
|
||||
./control_scripts.sh statusall
|
||||
```
|
||||
|
||||
### 3. 健康检查
|
||||
```bash
|
||||
./control_scripts.sh health all
|
||||
```
|
||||
|
||||
### 4. 查看系统资源
|
||||
```bash
|
||||
./control_scripts.sh info
|
||||
```
|
||||
|
||||
## 📁 文件结构
|
||||
|
||||
```
|
||||
/scripts/
|
||||
├── control_scripts.sh # 生产环境控制脚本
|
||||
├── process_student_changes_fixed.sh # 状态变更处理脚本
|
||||
├── process_student_resume_fixed.sh # 复学处理脚本
|
||||
├── data.conf # 配置文件
|
||||
├── logs/ # 控制脚本日志目录
|
||||
│ └── control_scripts_YYYYMMDD.log
|
||||
└── student_status_change/ # 处理脚本日志目录
|
||||
└── process_student_*_YYYYMMDD_HHMMSS.log
|
||||
```
|
||||
|
||||
## ⚙️ 配置要求
|
||||
|
||||
### 数据库配置 (data.conf)
|
||||
```bash
|
||||
# Database configuration
|
||||
DB_HOST="your_db_host"
|
||||
DB_PORT="3306"
|
||||
DB_NAME="your_db_name"
|
||||
DB_USER="your_db_user"
|
||||
DB_PASS="your_db_password"
|
||||
|
||||
# Processing configuration
|
||||
BATCH_SIZE=100 # 每批处理记录数
|
||||
MAX_RETRY=3 # 最大重试次数
|
||||
RETRY_DELAY=5 # 重试间隔(秒)
|
||||
CYCLE_INTERVAL=600 # 处理周期间隔(秒)
|
||||
```
|
||||
|
||||
### 系统要求
|
||||
- Ubuntu 18.04+ / CentOS 7+
|
||||
- Bash 4.0+
|
||||
- MySQL 5.7+ / MariaDB 10.0+
|
||||
- 标准系统工具 (ps, kill, chmod等)
|
||||
|
||||
## 🎯 控制脚本命令
|
||||
|
||||
### 基础操作
|
||||
```bash
|
||||
# 启动/停止/重启
|
||||
./control_scripts.sh start changes # 启动状态变更处理
|
||||
./control_scripts.sh stop resume # 停止复学处理
|
||||
./control_scripts.sh restart changes # 重启状态变更处理
|
||||
|
||||
# 状态检查
|
||||
./control_scripts.sh status changes # 查看状态变更脚本状态
|
||||
./control_scripts.sh statusall # 查看所有脚本状态
|
||||
```
|
||||
|
||||
### 批量操作
|
||||
```bash
|
||||
# 启动所有脚本
|
||||
./control_scripts.sh startall
|
||||
|
||||
# 停止所有脚本
|
||||
./control_scripts.sh stopall
|
||||
|
||||
# 重启所有脚本 (需要时使用)
|
||||
./control_scripts.sh restart all
|
||||
```
|
||||
|
||||
### 监控和维护
|
||||
```bash
|
||||
# 健康检查
|
||||
./control_scripts.sh health changes # 检查单个脚本
|
||||
./control_scripts.sh health all # 检查所有脚本
|
||||
|
||||
# 系统资源监控
|
||||
./control_scripts.sh info
|
||||
```
|
||||
|
||||
## 🔍 故障排除
|
||||
|
||||
### 常见问题
|
||||
|
||||
#### 1. 脚本无法启动
|
||||
**症状**: `start` 命令失败
|
||||
**检查**:
|
||||
```bash
|
||||
# 检查脚本权限
|
||||
ls -la *.sh
|
||||
|
||||
# 检查配置文件
|
||||
cat data.conf
|
||||
|
||||
# 检查数据库连接
|
||||
mysql -h$DB_HOST -P$DB_PORT -u$DB_USER -p$DB_PASS $DB_NAME -e "SELECT 1;"
|
||||
```
|
||||
|
||||
#### 2. 脚本状态显示异常
|
||||
**症状**: `status` 显示未知状态
|
||||
**解决**:
|
||||
```bash
|
||||
# 清理可能的残留文件
|
||||
rm -f *.lock pids/*.pid
|
||||
|
||||
# 重启脚本
|
||||
./control_scripts.sh restart all
|
||||
```
|
||||
|
||||
#### 3. 数据库连接失败
|
||||
**症状**: 健康检查显示数据库连接失败
|
||||
**检查**:
|
||||
- 确认数据库服务运行
|
||||
- 验证连接参数
|
||||
- 检查网络连接
|
||||
|
||||
#### 4. 日志文件过大
|
||||
**解决**:
|
||||
```bash
|
||||
# 清理旧日志 (保留最近7天)
|
||||
find logs/ -name "*.log" -mtime +7 -delete
|
||||
find student_status_change/ -name "*.log" -mtime +7 -delete
|
||||
```
|
||||
|
||||
### 日志位置
|
||||
- **控制脚本日志**: `logs/control_scripts_YYYYMMDD.log`
|
||||
- **处理脚本日志**: `student_status_change/process_student_*_YYYYMMDD_HHMMSS.log`
|
||||
|
||||
## 📊 监控要点
|
||||
|
||||
### 关键指标
|
||||
1. **脚本运行状态**: 确保两个处理脚本都在运行
|
||||
2. **数据库连接**: 定期检查数据库连接性
|
||||
3. **处理效率**: 观察日志中的处理记录数和耗时
|
||||
4. **系统资源**: CPU/内存/磁盘使用率
|
||||
5. **错误日志**: 关注ERROR和WARN级别的日志
|
||||
|
||||
### 自动化监控脚本
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# 监控脚本示例
|
||||
|
||||
SCRIPT_DIR="/path/to/scripts"
|
||||
LOG_FILE="/var/log/student_monitor.log"
|
||||
|
||||
echo "$(date): 检查脚本状态" >> "$LOG_FILE"
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# 检查脚本状态
|
||||
if ! ./control_scripts.sh health all >> "$LOG_FILE" 2>&1; then
|
||||
echo "$(date): 健康检查失败,发送告警" >> "$LOG_FILE"
|
||||
# 发送告警邮件/短信等
|
||||
fi
|
||||
```
|
||||
|
||||
## 🔄 升级部署
|
||||
|
||||
### 停机升级
|
||||
```bash
|
||||
# 1. 停止所有服务
|
||||
./control_scripts.sh stopall
|
||||
|
||||
# 2. 备份当前脚本
|
||||
cp *.sh backup/
|
||||
|
||||
# 3. 部署新版本脚本
|
||||
# (复制新版本文件)
|
||||
|
||||
# 4. 启动服务
|
||||
./control_scripts.sh startall
|
||||
|
||||
# 5. 验证功能
|
||||
./control_scripts.sh health all
|
||||
```
|
||||
|
||||
### 热升级 (推荐)
|
||||
```bash
|
||||
# 逐个重启脚本,最小化服务中断
|
||||
./control_scripts.sh restart changes
|
||||
sleep 30
|
||||
./control_scripts.sh restart resume
|
||||
```
|
||||
|
||||
## 📞 支持
|
||||
|
||||
如遇到问题,请检查:
|
||||
1. 日志文件中的错误信息
|
||||
2. 系统资源使用情况
|
||||
3. 数据库连接状态
|
||||
4. 脚本执行权限
|
||||
|
||||
---
|
||||
|
||||
**最后更新**: 2025-12-26
|
||||
**版本**: Ubuntu兼容修复版本
|
||||
+205
-28
@@ -1,11 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===========================================
|
||||
# 学生状态变更处理脚本控制程序
|
||||
# 用于启动、停止、重启处理脚本
|
||||
# 学生状态变更处理脚本控制程序 - 生产环境版本
|
||||
# 用于启动、停止、重启处理脚本 (Ubuntu兼容性修复版本)
|
||||
# ===========================================
|
||||
#
|
||||
# 生产环境部署指南:
|
||||
# 1. 确保所有修复版本脚本存在:
|
||||
# - process_student_changes_fixed.sh (状态变更处理)
|
||||
# - process_student_resume_fixed.sh (复学处理)
|
||||
#
|
||||
# 2. 确保配置文件存在:
|
||||
# - data.conf (数据库配置和脚本参数)
|
||||
#
|
||||
# 3. 启动所有服务:
|
||||
# ./control_scripts.sh startall
|
||||
#
|
||||
# 4. 监控运行状态:
|
||||
# ./control_scripts.sh statusall
|
||||
#
|
||||
# 5. 健康检查:
|
||||
# ./control_scripts.sh health all
|
||||
#
|
||||
# 6. 查看系统资源:
|
||||
# ./control_scripts.sh info
|
||||
#
|
||||
# 日志文件位置:
|
||||
# - 控制脚本日志: logs/control_scripts_YYYYMMDD.log
|
||||
# - 处理脚本日志: student_status_change/process_student_*_YYYYMMDD_HHMMSS.log
|
||||
|
||||
set -euo pipefail
|
||||
# Disable strict error checking for better production resilience
|
||||
# set -euo pipefail # Temporarily disabled for production robustness
|
||||
|
||||
# Force C locale for consistent behavior across systems
|
||||
export LANG=C
|
||||
export LC_ALL=C
|
||||
|
||||
# Load configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
@@ -13,16 +42,33 @@ CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "错误:配置文件 $CONFIG_FILE 未找到!"
|
||||
echo "请确保 data.conf 文件存在于脚本目录中"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Script definitions
|
||||
declare -A SCRIPTS=(
|
||||
["changes"]="process_student_changes.sh"
|
||||
["resume"]="process_student_resume.sh"
|
||||
)
|
||||
# Production environment setup
|
||||
PRODUCTION_LOG_DIR="${SCRIPT_DIR}/logs"
|
||||
mkdir -p "$PRODUCTION_LOG_DIR"
|
||||
PRODUCTION_LOG_FILE="${PRODUCTION_LOG_DIR}/control_scripts_$(date +%Y%m%d).log"
|
||||
|
||||
# Script definitions - Production versions with Ubuntu compatibility fixes
|
||||
# Using indexed arrays for better bash compatibility
|
||||
SCRIPT_NAMES=("changes" "resume")
|
||||
SCRIPT_FILES=("process_student_changes_fixed.sh" "process_student_resume_fixed.sh")
|
||||
|
||||
# Function to get script file by name
|
||||
get_script_file() {
|
||||
local script_name="$1"
|
||||
for i in "${!SCRIPT_NAMES[@]}"; do
|
||||
if [[ "${SCRIPT_NAMES[$i]}" == "$script_name" ]]; then
|
||||
echo "${SCRIPT_FILES[$i]}"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# PID files
|
||||
PID_DIR="${SCRIPT_DIR}/pids"
|
||||
@@ -33,7 +79,13 @@ log() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "[$timestamp] [$level] $message"
|
||||
local log_message="[$timestamp] [$level] $message"
|
||||
|
||||
# Output to console
|
||||
echo "$log_message"
|
||||
|
||||
# Output to production log file
|
||||
echo "$log_message" >> "$PRODUCTION_LOG_FILE"
|
||||
}
|
||||
|
||||
get_pid_file() {
|
||||
@@ -76,9 +128,64 @@ is_running() {
|
||||
return 1 # Not running
|
||||
}
|
||||
|
||||
# Health check function for production monitoring
|
||||
health_check() {
|
||||
local script_name="$1"
|
||||
local script_file="${SCRIPT_DIR}/$(get_script_file "$script_name")"
|
||||
|
||||
log "INFO" "执行 $script_name 的健康检查..."
|
||||
|
||||
# Check if script file exists and is executable
|
||||
if [[ ! -f "$script_file" ]]; then
|
||||
log "ERROR" "$script_name 脚本文件不存在: $script_file"
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ ! -x "$script_file" ]]; then
|
||||
log "WARN" "$script_name 脚本文件没有执行权限,正在修复..."
|
||||
chmod +x "$script_file"
|
||||
fi
|
||||
|
||||
# Check database connectivity
|
||||
if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
|
||||
log "ERROR" "$script_name 数据库连接失败"
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if script is running
|
||||
if ! is_running "$script_name"; then
|
||||
log "WARN" "$script_name 脚本未运行"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "INFO" "$script_name 健康检查通过"
|
||||
return 0
|
||||
}
|
||||
|
||||
# Get system resource usage
|
||||
get_system_info() {
|
||||
log "INFO" "=== 系统资源信息 ==="
|
||||
|
||||
# CPU usage
|
||||
local cpu_usage=$(top -bn1 | grep "Cpu(s)" | sed "s/.*, *\([0-9.]*\)%* id.*/\1/" | awk '{print 100 - $1}')
|
||||
log "INFO" "CPU使用率: ${cpu_usage}%"
|
||||
|
||||
# Memory usage
|
||||
local mem_info=$(free -h | grep "^Mem:")
|
||||
log "INFO" "内存信息: $mem_info"
|
||||
|
||||
# Disk usage
|
||||
local disk_info=$(df -h "$SCRIPT_DIR" | tail -1 | awk '{print $1 ": " $5 " used (" $4 " free)"}')
|
||||
log "INFO" "磁盘使用: $disk_info"
|
||||
|
||||
# Process count
|
||||
local process_count=$(pgrep -f "process_student.*\.sh" | wc -l)
|
||||
log "INFO" "运行中的学生处理进程数: $process_count"
|
||||
}
|
||||
|
||||
start_script() {
|
||||
local script_name="$1"
|
||||
local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}"
|
||||
local script_file="${SCRIPT_DIR}/$(get_script_file "$script_name")"
|
||||
local pid_file=$(get_pid_file "$script_name")
|
||||
|
||||
if [[ ! -f "$script_file" ]]; then
|
||||
@@ -189,38 +296,74 @@ show_usage() {
|
||||
stop 停止指定的脚本
|
||||
restart 重启指定的脚本
|
||||
status 显示指定脚本的状态
|
||||
health 执行脚本健康检查
|
||||
startall 启动所有脚本
|
||||
stopall 停止所有脚本
|
||||
statusall 显示所有脚本的状态
|
||||
info 显示系统资源信息
|
||||
|
||||
脚本名称:
|
||||
changes 学生状态变更脚本 (休学/退学/毕业)
|
||||
resume 学生复学脚本 (复学)
|
||||
changes 学生状态变更脚本 (休学/退学/毕业) - Ubuntu兼容修复版本
|
||||
resume 学生复学脚本 (复学) - Ubuntu兼容修复版本
|
||||
all 所有脚本
|
||||
|
||||
示例:
|
||||
生产环境示例:
|
||||
$0 startall # 启动所有学生处理脚本
|
||||
$0 statusall # 检查所有脚本运行状态
|
||||
$0 health all # 执行所有脚本的健康检查
|
||||
$0 info # 查看系统资源使用情况
|
||||
$0 restart changes # 重启状态变更处理脚本
|
||||
$0 stopall # 停止所有处理脚本
|
||||
|
||||
传统示例:
|
||||
$0 start changes # 启动状态变更处理脚本
|
||||
$0 stop resume # 停止复学处理脚本
|
||||
$0 restart changes # 重启状态变更处理脚本
|
||||
$0 status all # 显示所有脚本的状态
|
||||
$0 startall # 启动所有脚本
|
||||
$0 stopall # 停止所有脚本
|
||||
$0 status changes # 显示状态变更脚本状态
|
||||
|
||||
注意:
|
||||
本脚本使用修复版本,已适配Ubuntu环境,解决了循环处理和数据库查询的兼容性问题
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
# Production environment initialization
|
||||
init_production_env() {
|
||||
log "INFO" "初始化生产环境..."
|
||||
|
||||
# Check script files exist
|
||||
for script_name in "${!SCRIPTS[@]}"; do
|
||||
local script_file="${SCRIPT_DIR}/${SCRIPTS[$script_name]}"
|
||||
if [[ ! -f "$script_file" ]]; then
|
||||
log "ERROR" "脚本文件不存在: $script_file"
|
||||
log "ERROR" "请确保已部署修复版本的脚本文件"
|
||||
exit 1
|
||||
fi
|
||||
done
|
||||
|
||||
# Test database connectivity
|
||||
if ! mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
|
||||
log "ERROR" "数据库连接失败,请检查配置"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "INFO" "生产环境初始化完成"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
# Initialize production environment
|
||||
init_production_env
|
||||
|
||||
local command="${1:-}"
|
||||
local script_name="${2:-}"
|
||||
|
||||
case "$command" in
|
||||
start)
|
||||
if [[ "$script_name" == "all" ]]; then
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
start_script "$script"
|
||||
done
|
||||
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
|
||||
elif get_script_file "$script_name" >/dev/null 2>&1; then
|
||||
start_script "$script_name"
|
||||
else
|
||||
log "ERROR" "未知的脚本名称: $script_name"
|
||||
@@ -231,10 +374,10 @@ main() {
|
||||
|
||||
stop)
|
||||
if [[ "$script_name" == "all" ]]; then
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
stop_script "$script"
|
||||
done
|
||||
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
|
||||
elif get_script_file "$script_name" >/dev/null 2>&1; then
|
||||
stop_script "$script_name"
|
||||
else
|
||||
log "ERROR" "未知的脚本名称: $script_name"
|
||||
@@ -245,10 +388,10 @@ main() {
|
||||
|
||||
restart)
|
||||
if [[ "$script_name" == "all" ]]; then
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
restart_script "$script"
|
||||
done
|
||||
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
|
||||
elif get_script_file "$script_name" >/dev/null 2>&1; then
|
||||
restart_script "$script_name"
|
||||
else
|
||||
log "ERROR" "未知的脚本名称: $script_name"
|
||||
@@ -259,10 +402,10 @@ main() {
|
||||
|
||||
status)
|
||||
if [[ "$script_name" == "all" ]]; then
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
status_script "$script"
|
||||
done
|
||||
elif [[ -n "${SCRIPTS[$script_name]}" ]]; then
|
||||
elif get_script_file "$script_name" >/dev/null 2>&1; then
|
||||
status_script "$script_name"
|
||||
else
|
||||
log "ERROR" "未知的脚本名称: $script_name"
|
||||
@@ -273,25 +416,59 @@ main() {
|
||||
|
||||
startall)
|
||||
log "INFO" "正在启动所有脚本..."
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
start_script "$script"
|
||||
done
|
||||
;;
|
||||
|
||||
stopall)
|
||||
log "INFO" "正在停止所有脚本..."
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
stop_script "$script"
|
||||
done
|
||||
;;
|
||||
|
||||
statusall)
|
||||
log "INFO" "正在检查所有脚本的状态..."
|
||||
for script in "${!SCRIPTS[@]}"; do
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
status_script "$script"
|
||||
done
|
||||
;;
|
||||
|
||||
health)
|
||||
if [[ "$script_name" == "all" ]]; then
|
||||
local all_healthy=true
|
||||
for script in "${SCRIPT_NAMES[@]}"; do
|
||||
if ! health_check "$script"; then
|
||||
all_healthy=false
|
||||
fi
|
||||
done
|
||||
if [[ "$all_healthy" == true ]]; then
|
||||
log "INFO" "所有脚本健康检查通过"
|
||||
exit 0
|
||||
else
|
||||
log "ERROR" "部分脚本健康检查失败"
|
||||
exit 1
|
||||
fi
|
||||
elif get_script_file "$script_name" >/dev/null 2>&1; then
|
||||
if health_check "$script_name"; then
|
||||
log "INFO" "$script_name 健康检查通过"
|
||||
exit 0
|
||||
else
|
||||
log "ERROR" "$script_name 健康检查失败"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
log "ERROR" "未知的脚本名称: $script_name"
|
||||
show_usage
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
|
||||
info)
|
||||
get_system_info
|
||||
;;
|
||||
|
||||
*)
|
||||
log "ERROR" "未知命令: $command"
|
||||
show_usage
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# Database configuration
|
||||
DB_HOST="172.16.0.67"
|
||||
DB_PORT="3306"
|
||||
DB_NAME="hzdyjs_xg"
|
||||
DB_USER="root"
|
||||
DB_PASS="Hzdyjs@Root@123456"
|
||||
|
||||
# Script configuration
|
||||
LOG_DIR="${SCRIPT_DIR}/student_status_change"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
LOCK_FILE="${SCRIPT_DIR}/script.lock"
|
||||
|
||||
# Processing configuration
|
||||
BATCH_SIZE=100
|
||||
MAX_RETRY=3
|
||||
RETRY_DELAY=5
|
||||
CYCLE_INTERVAL=600 # 循环间隔时间(秒),默认10分钟
|
||||
@@ -1,69 +0,0 @@
|
||||
# ===========================================
|
||||
# 学生状态变更处理脚本 - 可选的Crontab配置
|
||||
# ===========================================
|
||||
|
||||
# 注意:脚本现在采用持续运行模式,默认每10分钟自动处理一次
|
||||
# 此配置文件仅供特殊情况下的备用配置使用
|
||||
|
||||
# 如果不使用持续运行模式,可以使用以下crontab配置:
|
||||
# 1. 将以下内容添加到系统的 crontab 中:crontab -e
|
||||
# 2. 根据实际需要调整执行时间和频率
|
||||
# 3. 确保脚本路径正确
|
||||
# 4. 确保用户有执行权限
|
||||
|
||||
# 脚本所在目录(请根据实际情况修改)
|
||||
SCRIPT_DIR="/path/to/student_status_scripts"
|
||||
|
||||
# 每天早上8点执行学生状态变更处理
|
||||
0 8 * * * $SCRIPT_DIR/process_student_changes.sh
|
||||
|
||||
# 每天早上8点30分执行学生复学处理
|
||||
30 8 * * * $SCRIPT_DIR/process_student_resume.sh
|
||||
|
||||
# 每小时执行一次健康检查
|
||||
0 * * * * $SCRIPT_DIR/health_check.sh report
|
||||
|
||||
# 每周一早上6点重启所有服务(可选,用于定期重启确保稳定性)
|
||||
0 6 * * 1 $SCRIPT_DIR/stop_services.sh && sleep 5 && $SCRIPT_DIR/start_services.sh
|
||||
|
||||
# 每天晚上10点清理旧日志文件(保留7天)
|
||||
0 22 * * * find $SCRIPT_DIR/logs -name "*.log" -type f -mtime +7 -delete
|
||||
|
||||
# 每分钟检查服务状态,如果服务停止则自动重启(可选)
|
||||
# */1 * * * * $SCRIPT_DIR/control_scripts.sh statusall >/dev/null 2>&1 || ($SCRIPT_DIR/stop_services.sh force && $SCRIPT_DIR/start_services.sh)
|
||||
|
||||
# ===========================================
|
||||
# Crontab 语法说明
|
||||
# ===========================================
|
||||
# 分 时 日 月 周 命令
|
||||
# * * * * * command
|
||||
#
|
||||
# 字段说明:
|
||||
# 分 - 0-59
|
||||
# 时 - 0-23
|
||||
# 日 - 1-31
|
||||
# 月 - 1-12
|
||||
# 周 - 0-7 (0和7都表示星期日)
|
||||
#
|
||||
# 常用示例:
|
||||
# 0 8 * * * - 每天早上8点
|
||||
# */30 * * * * - 每30分钟
|
||||
# 0 */2 * * * - 每2小时
|
||||
# 0 9-17 * * 1-5 - 周一到周五的9点到17点,每小时执行一次
|
||||
# @reboot - 系统重启时执行
|
||||
|
||||
# ===========================================
|
||||
# 监控和告警建议
|
||||
# ===========================================
|
||||
|
||||
# 1. 监控日志中的ERROR关键字
|
||||
# 可以使用logwatch或自定义脚本监控日志
|
||||
|
||||
# 2. 监控数据库连接
|
||||
# */5 * * * * mysql -h host -u user -p pass -e "SELECT 1;" || echo "DB connection failed" | mail -s "DB Alert" admin@example.com
|
||||
|
||||
# 3. 监控磁盘空间
|
||||
# */30 * * * * df /var/log | awk 'NR==2 {if($5>90) print "Disk usage high: "$5}' | mail -s "Disk Alert" admin@example.com
|
||||
|
||||
# 4. 监控进程状态
|
||||
# */5 * * * * pgrep -f "process_student_changes.sh" >/dev/null || echo "Process died" | mail -s "Process Alert" admin@example.com
|
||||
@@ -82,6 +82,25 @@ execute_sql() {
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Database query function - Fixed version for cross-platform compatibility
|
||||
execute_query() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
# Use -ss for ultra-silent mode to ensure clean tab-separated output
|
||||
# Redirect stderr to /dev/null to discard warnings, only capture actual data
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>/dev/null)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "查询执行失败: $sql"
|
||||
log "ERROR" "MySQL错误码: $exit_code"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Process student status change
|
||||
process_student_change() {
|
||||
local record_id="$1"
|
||||
@@ -105,20 +124,16 @@ process_student_change() {
|
||||
local bed_ids=""
|
||||
|
||||
# Execute dormitory query with error handling
|
||||
if dorm_info=$(execute_sql "$dorm_query" 2>/dev/null); then
|
||||
# Parse the result (skip header if present)
|
||||
if [[ -n "$dorm_info" ]]; then
|
||||
# Remove warnings, keep only data rows
|
||||
dorm_info=$(echo "$dorm_info" | grep -v "mysql:" | grep -E "^[0-9]+\t" | head -n 1)
|
||||
if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then
|
||||
# Split by tab and handle NULL values
|
||||
IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info"
|
||||
if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then
|
||||
dorm_ids="$dorm_ids_raw"
|
||||
fi
|
||||
if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then
|
||||
bed_ids="$bed_ids_raw"
|
||||
fi
|
||||
if dorm_info=$(execute_query "$dorm_query" 2>/dev/null); then
|
||||
# Parse the result - handle NULL values properly
|
||||
if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then
|
||||
# Split by tab and handle NULL values
|
||||
IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info"
|
||||
if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then
|
||||
dorm_ids="$dorm_ids_raw"
|
||||
fi
|
||||
if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then
|
||||
bed_ids="$bed_ids_raw"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
@@ -285,18 +300,32 @@ main() {
|
||||
if [[ $record_count -le 1 ]]; then
|
||||
log "INFO" "未找到未处理的记录,正在等待..."
|
||||
else
|
||||
# 移除标题行和可能的警告信息
|
||||
records=$(echo "$records" | grep -v "mysql:" | grep -v "id\t" | grep -v "^$")
|
||||
|
||||
|
||||
local processed_count=0
|
||||
local failed_count=0
|
||||
|
||||
# Process each record
|
||||
# Process records directly, skip header and invalid lines
|
||||
local is_first_line=true
|
||||
while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
|
||||
# Skip empty lines
|
||||
[[ -z "$record_id" ]] && continue
|
||||
# Skip completely empty lines and MySQL warnings
|
||||
[[ -z "$record_id$student_id$student_no$change_type$operator_id" || "$record_id" =~ ^mysql: ]] && continue
|
||||
|
||||
# Skip header line (first non-empty line that looks like column names)
|
||||
if [[ $is_first_line == true ]]; then
|
||||
is_first_line=false
|
||||
# Check if this looks like a header line
|
||||
if [[ "$record_id" == "id" || "$record_id" =~ ^[[:space:]]*id[[:space:]]*$ ]]; then
|
||||
log "INFO" "跳过标题行"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate required fields
|
||||
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
|
||||
log "WARN" "跳过无效记录 - ID: '$record_id', 学生ID: '$student_id', 学号: '$student_no', 类型: '$change_type'"
|
||||
continue
|
||||
fi
|
||||
|
||||
log "INFO" "读取到记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 类型: $change_type, 操作员: ${operator_id:-1}"
|
||||
|
||||
local retry_count=0
|
||||
local success=false
|
||||
|
||||
Executable
+357
@@ -0,0 +1,357 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===========================================
|
||||
# 学生状态变更处理脚本 - 毕业/退学/休学 (修复版本)
|
||||
# 处理类型: XIU_XUE(休学), TUI_XUE(退学), BI_YE(毕业)
|
||||
# ===========================================
|
||||
|
||||
# set -euo pipefail # Temporarily disable to prevent script exit on errors
|
||||
|
||||
# Force C locale to ensure consistent behavior across systems
|
||||
export LANG=C
|
||||
export LC_ALL=C
|
||||
|
||||
# Load configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "错误:配置文件 $CONFIG_FILE 未找到!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Create log directory
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Log file
|
||||
LOG_FILE="${LOG_DIR}/process_student_changes_fixed_$(date +%Y%m%d_%H%M%S).log"
|
||||
|
||||
# Lock file to prevent multiple instances
|
||||
LOCK_FILE="${SCRIPT_DIR}/process_student_changes_fixed.lock"
|
||||
|
||||
# Functions
|
||||
log() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
error_exit() {
|
||||
local message="$1"
|
||||
log "ERROR" "$message"
|
||||
# Remove lock file
|
||||
[[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Database functions - Fixed version
|
||||
execute_sql() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$sql" 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "SQL执行失败: $sql"
|
||||
log "ERROR" "MySQL错误: $result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Database query function - Fixed version for cross-platform compatibility
|
||||
execute_query() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
# Use -ss for ultra-silent mode to ensure clean tab-separated output
|
||||
# Redirect stderr to /dev/null to discard warnings, only capture actual data
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>/dev/null)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "查询执行失败: $sql"
|
||||
log "ERROR" "MySQL错误码: $exit_code"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Process student status change
|
||||
process_student_change() {
|
||||
local record_id="$1"
|
||||
local student_id="$2"
|
||||
local student_no="$3"
|
||||
local change_type="$4"
|
||||
local operator_id="${5:-1}"
|
||||
|
||||
# Validate input parameters
|
||||
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
|
||||
log "ERROR" "参数不完整 - record_id: '$record_id', student_id: '$student_id', student_no: '$student_no', change_type: '$change_type'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "INFO" "正在处理学生状态变更 - ID: $record_id, 学生: $student_no ($student_id), 类型: $change_type"
|
||||
|
||||
# Get dormitory assignment info before transaction
|
||||
local dorm_query="
|
||||
SELECT GROUP_CONCAT(id), GROUP_CONCAT(bed_id)
|
||||
FROM xg_dorm_bed_student
|
||||
WHERE student_id = $student_id AND status = '0' AND deleted = 0;
|
||||
"
|
||||
|
||||
local dorm_info=""
|
||||
local dorm_ids=""
|
||||
local bed_ids=""
|
||||
|
||||
# Execute dormitory query with error handling
|
||||
if dorm_info=$(execute_query "$dorm_query" 2>/dev/null); then
|
||||
# Parse the result - handle NULL values properly
|
||||
if [[ -n "$dorm_info" && "$dorm_info" != "NULL" && "$dorm_info" != "NULL\tNULL" ]]; then
|
||||
# Split by tab and handle NULL values
|
||||
IFS=$'\t' read -r dorm_ids_raw bed_ids_raw <<< "$dorm_info"
|
||||
if [[ "$dorm_ids_raw" != "NULL" && -n "$dorm_ids_raw" ]]; then
|
||||
dorm_ids="$dorm_ids_raw"
|
||||
fi
|
||||
if [[ "$bed_ids_raw" != "NULL" && -n "$bed_ids_raw" ]]; then
|
||||
bed_ids="$bed_ids_raw"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
log "WARN" "查询宿舍分配信息失败,将跳过宿舍处理 - 学生ID: $student_id"
|
||||
fi
|
||||
|
||||
log "INFO" "找到宿舍分配 - ID: ${dorm_ids:-无}, 床位: ${bed_ids:-无}"
|
||||
|
||||
# Start transaction
|
||||
local transaction_sql="
|
||||
START TRANSACTION;
|
||||
|
||||
-- 1. Backup original data to his tables (ignore if already exists)
|
||||
INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id;
|
||||
INSERT IGNORE INTO sys_user_his SELECT * FROM sys_user WHERE user_id = $student_id;
|
||||
INSERT IGNORE INTO xg_class_pos_msg_his SELECT * FROM xg_class_pos_msg WHERE student_id = $student_id;
|
||||
INSERT IGNORE INTO club_member_his SELECT * FROM club_member WHERE user_id = $student_id;
|
||||
INSERT IGNORE INTO stgl_member_his SELECT * FROM stgl_member WHERE user_id = $student_id;
|
||||
INSERT IGNORE INTO xg_dorm_bed_student_his SELECT * FROM xg_dorm_bed_student WHERE student_id = $student_id;
|
||||
|
||||
-- 2. Update student status
|
||||
UPDATE xg_student_msg SET
|
||||
student_status = CASE
|
||||
WHEN '$change_type' = 'XIU_XUE' THEN '2'
|
||||
WHEN '$change_type' = 'TUI_XUE' THEN '4'
|
||||
WHEN '$change_type' = 'BI_YE' THEN '5'
|
||||
ELSE student_status
|
||||
END,
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE id = $student_id;
|
||||
|
||||
-- 3. Disable user account
|
||||
UPDATE sys_user SET
|
||||
status = '1',
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE user_id = $student_id AND account_type = '2';
|
||||
|
||||
-- 4. Process class position (cadre) - only for XIU_XUE, TUI_XUE, BI_YE
|
||||
UPDATE xg_class_pos_msg SET
|
||||
is_current = 0,
|
||||
cadre_status = CASE
|
||||
WHEN '$change_type' = 'XIU_XUE' THEN '6'
|
||||
WHEN '$change_type' IN ('TUI_XUE', 'BI_YE') THEN '4'
|
||||
ELSE cadre_status
|
||||
END,
|
||||
dismissal_date = CURDATE(),
|
||||
dismissal_reason = CASE
|
||||
WHEN '$change_type' = 'XIU_XUE' THEN '学生休学'
|
||||
WHEN '$change_type' = 'TUI_XUE' THEN '学生退学'
|
||||
WHEN '$change_type' = 'BI_YE' THEN '学生毕业'
|
||||
ELSE dismissal_reason
|
||||
END,
|
||||
term_end_date = CURDATE(),
|
||||
term_duration = TIMESTAMPDIFF(MONTH, term_start_date, CURDATE()),
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE student_id = $student_id AND is_current = 1;
|
||||
|
||||
-- 5. Process club membership - only for XIU_XUE, TUI_XUE, BI_YE
|
||||
UPDATE club_member SET
|
||||
member_status = '4',
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE user_id = $student_id AND member_status IN ('0', '1', '2');
|
||||
|
||||
-- 6. Process volunteer membership - only for XIU_XUE, TUI_XUE, BI_YE
|
||||
UPDATE stgl_member SET
|
||||
status = 4,
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE user_id = $student_id AND status IN (0, 1, 2);
|
||||
|
||||
-- 7. Process dormitory - only for TUI_XUE, BI_YE
|
||||
-- First, clear dormitory info from student record
|
||||
UPDATE xg_student_msg SET
|
||||
dormitory_building = NULL,
|
||||
dormitory_room = NULL,
|
||||
ext_field1 = NULL,
|
||||
update_time = NOW(),
|
||||
update_by = $operator_id
|
||||
WHERE id = $student_id;"
|
||||
|
||||
# Add dormitory processing only if assignments exist and are valid
|
||||
if [[ -n "$dorm_ids" && "$dorm_ids" != "NULL" && -n "$bed_ids" && "$bed_ids" != "NULL" ]]; then
|
||||
transaction_sql+="
|
||||
-- Process dormitory checkout for specific assignments
|
||||
UPDATE xg_dorm_bed_student SET
|
||||
status = '1',
|
||||
checkout_time = NOW(),
|
||||
update_time = NOW(),
|
||||
update_by = $operator_id
|
||||
WHERE FIND_IN_SET(id, '$dorm_ids') AND deleted = 0;
|
||||
|
||||
-- Update bed status for specific beds
|
||||
UPDATE xg_dorm_bed SET
|
||||
bed_status = '0'
|
||||
WHERE FIND_IN_SET(id, '$bed_ids') AND deleted = 0;"
|
||||
log "INFO" "将处理宿舍退宿 - 分配ID: $dorm_ids, 床位ID: $bed_ids"
|
||||
else
|
||||
log "INFO" "无需处理宿舍退宿(无有效宿舍分配)"
|
||||
fi
|
||||
|
||||
transaction_sql+="
|
||||
-- 8. Update change record status
|
||||
UPDATE xg_student_status_change SET
|
||||
process_status = 1,
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE id = $record_id;
|
||||
|
||||
COMMIT;
|
||||
"
|
||||
|
||||
# Execute transaction (using execute_sql to allow error output for debugging)
|
||||
if execute_sql "$transaction_sql"; then
|
||||
log "INFO" "成功处理学生状态变更 - ID: $record_id, 学生: $student_no"
|
||||
return 0
|
||||
else
|
||||
log "ERROR" "处理学生状态变更失败 - ID: $record_id, 学生: $student_no"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
log "INFO" "启动学生状态变更处理守护进程 (修复版本)"
|
||||
log "INFO" "处理类型: XIU_XUE(休学), TUI_XUE(退学), BI_YE(毕业)"
|
||||
log "INFO" "以连续模式运行,间隔10分钟"
|
||||
|
||||
# 测试数据库连接
|
||||
log "INFO" "正在测试数据库连接..."
|
||||
if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then
|
||||
error_exit "数据库连接失败"
|
||||
fi
|
||||
log "INFO" "数据库连接成功"
|
||||
|
||||
# Main processing loop
|
||||
while true; do
|
||||
log "INFO" "开始新的处理周期"
|
||||
|
||||
# 获取未处理的记录
|
||||
local query_sql="
|
||||
SELECT id, student_id, student_no, change_type, operator_id
|
||||
FROM xg_student_status_change
|
||||
WHERE process_status = 0
|
||||
AND change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE')
|
||||
AND deleted = 0
|
||||
AND effective_date <= NOW()
|
||||
ORDER BY create_time ASC
|
||||
LIMIT $BATCH_SIZE;
|
||||
"
|
||||
|
||||
local records
|
||||
records=$(execute_query "$query_sql")
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log "ERROR" "获取待处理记录失败"
|
||||
sleep $CYCLE_INTERVAL
|
||||
continue
|
||||
fi
|
||||
|
||||
# 检查是否有记录需要处理(过滤掉空行和MySQL警告信息)
|
||||
local clean_records
|
||||
clean_records=$(echo "$records" | grep -v "^mysql:" | grep -v "^$" | wc -l)
|
||||
|
||||
if [[ $clean_records -eq 0 ]]; then
|
||||
log "INFO" "未找到未处理的记录,正在等待..."
|
||||
else
|
||||
log "INFO" "找到 $clean_records 条待处理记录"
|
||||
|
||||
local processed_count=0
|
||||
local failed_count=0
|
||||
|
||||
# Process records directly from the query result, skip header and empty lines
|
||||
local is_first_line=true
|
||||
while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
|
||||
# Skip completely empty lines
|
||||
[[ -z "$record_id$student_id$student_no$change_type$operator_id" ]] && continue
|
||||
|
||||
# Skip header line (first non-empty line that looks like column names)
|
||||
if [[ $is_first_line == true ]]; then
|
||||
is_first_line=false
|
||||
# Check if this looks like a header line
|
||||
if [[ "$record_id" == "id" || "$record_id" =~ ^[[:space:]]*id[[:space:]]*$ ]]; then
|
||||
log "INFO" "跳过标题行"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate required fields
|
||||
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
|
||||
log "WARN" "跳过无效记录 - ID: '$record_id', 学生ID: '$student_id', 学号: '$student_no', 类型: '$change_type'"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Log the record being processed for debugging
|
||||
log "INFO" "读取到记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 类型: $change_type, 操作员: ${operator_id:-1}"
|
||||
|
||||
local retry_count=0
|
||||
local success=false
|
||||
|
||||
while [[ $retry_count -lt $MAX_RETRY && $success == false ]]; do
|
||||
if process_student_change "$record_id" "$student_id" "$student_no" "$change_type" "$operator_id"; then
|
||||
success=true
|
||||
((processed_count++))
|
||||
else
|
||||
((retry_count++))
|
||||
if [[ $retry_count -lt $MAX_RETRY ]]; then
|
||||
log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)"
|
||||
sleep $RETRY_DELAY
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $success == false ]]; then
|
||||
((failed_count++))
|
||||
log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id"
|
||||
fi
|
||||
|
||||
done <<< "$(echo "$records" | grep -v "^mysql:" | grep -v "^$")"
|
||||
|
||||
log "INFO" "处理周期完成 - 已处理: $processed_count, 失败: $failed_count"
|
||||
fi
|
||||
|
||||
# 等待配置的间隔时间后开始下一个周期
|
||||
log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个处理周期..."
|
||||
sleep $CYCLE_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
Executable
+252
@@ -0,0 +1,252 @@
|
||||
#!/bin/bash
|
||||
|
||||
# ===========================================
|
||||
# 学生状态变更处理脚本 - 复学 (修复版本)
|
||||
# 处理类型: FU_XUE(复学)
|
||||
# ===========================================
|
||||
|
||||
# set -euo pipefail # Temporarily disable to prevent script exit on errors
|
||||
|
||||
# Force C locale to ensure consistent behavior across systems
|
||||
export LANG=C
|
||||
export LC_ALL=C
|
||||
|
||||
# Load configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "错误:配置文件 $CONFIG_FILE 未找到!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
# Create log directory
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
# Log file
|
||||
LOG_FILE="${LOG_DIR}/process_student_resume_fixed_$(date +%Y%m%d_%H%M%S).log"
|
||||
|
||||
# Lock file to prevent multiple instances
|
||||
LOCK_FILE="${SCRIPT_DIR}/process_student_resume_fixed.lock"
|
||||
|
||||
# Functions
|
||||
log() {
|
||||
local level="$1"
|
||||
local message="$2"
|
||||
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
|
||||
echo "[$timestamp] [$level] $message" | tee -a "$LOG_FILE"
|
||||
}
|
||||
|
||||
error_exit() {
|
||||
local message="$1"
|
||||
log "ERROR" "$message"
|
||||
# Remove lock file
|
||||
[[ -f "$LOCK_FILE" ]] && rm -f "$LOCK_FILE"
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Database functions - Fixed version
|
||||
execute_sql() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$sql" 2>&1)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "SQL执行失败: $sql"
|
||||
log "ERROR" "MySQL错误: $result"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Database query function - Fixed version for cross-platform compatibility
|
||||
execute_query() {
|
||||
local sql="$1"
|
||||
local result
|
||||
|
||||
# Use -ss for ultra-silent mode to ensure clean tab-separated output
|
||||
# Redirect stderr to /dev/null to discard warnings, only capture actual data
|
||||
result=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$sql" 2>/dev/null)
|
||||
local exit_code=$?
|
||||
|
||||
if [[ $exit_code -ne 0 ]]; then
|
||||
log "ERROR" "查询执行失败: $sql"
|
||||
log "ERROR" "MySQL错误码: $exit_code"
|
||||
return 1
|
||||
fi
|
||||
|
||||
echo "$result"
|
||||
}
|
||||
|
||||
# Process student resume
|
||||
process_student_resume() {
|
||||
local record_id="$1"
|
||||
local student_id="$2"
|
||||
local student_no="$3"
|
||||
local change_type="$4"
|
||||
local operator_id="${5:-1}"
|
||||
|
||||
# Validate input parameters
|
||||
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
|
||||
log "ERROR" "参数不完整 - record_id: '$record_id', student_id: '$student_id', student_no: '$student_no', change_type: '$change_type'"
|
||||
return 1
|
||||
fi
|
||||
|
||||
log "INFO" "正在处理学生复学 - ID: $record_id, 学生: $student_no ($student_id), 类型: $change_type"
|
||||
|
||||
# Start transaction
|
||||
local transaction_sql="
|
||||
START TRANSACTION;
|
||||
|
||||
-- 1. Backup original data to his tables (ignore if already exists)
|
||||
INSERT IGNORE INTO xg_student_msg_his SELECT * FROM xg_student_msg WHERE id = $student_id;
|
||||
INSERT IGNORE INTO sys_user_his SELECT * FROM sys_user WHERE user_id = $student_id;
|
||||
|
||||
-- 2. Update student status to resume (复学)
|
||||
UPDATE xg_student_msg SET
|
||||
student_status = '1',
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE id = $student_id;
|
||||
|
||||
-- 3. Enable user account
|
||||
UPDATE sys_user SET
|
||||
status = '0',
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE user_id = $student_id AND account_type = '2';
|
||||
|
||||
-- 4. Update change record status
|
||||
UPDATE xg_student_status_change SET
|
||||
process_status = 1,
|
||||
update_by = $operator_id,
|
||||
update_time = NOW()
|
||||
WHERE id = $record_id;
|
||||
|
||||
COMMIT;
|
||||
"
|
||||
|
||||
# Execute transaction (using execute_sql to allow error output for debugging)
|
||||
if execute_sql "$transaction_sql"; then
|
||||
log "INFO" "成功处理学生复学 - ID: $record_id, 学生: $student_no"
|
||||
return 0
|
||||
else
|
||||
log "ERROR" "处理学生复学失败 - ID: $record_id, 学生: $student_no"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
log "INFO" "启动学生复学处理守护进程 (修复版本)"
|
||||
log "INFO" "处理类型: FU_XUE(复学)"
|
||||
log "INFO" "以连续模式运行,间隔10分钟"
|
||||
|
||||
# 测试数据库连接
|
||||
log "INFO" "正在测试数据库连接..."
|
||||
if ! execute_sql "SELECT 1;" >/dev/null 2>&1; then
|
||||
error_exit "数据库连接失败"
|
||||
fi
|
||||
log "INFO" "数据库连接成功"
|
||||
|
||||
# Main processing loop
|
||||
while true; do
|
||||
log "INFO" "开始新的复学处理周期"
|
||||
|
||||
# 获取未处理的记录
|
||||
local query_sql="
|
||||
SELECT id, student_id, student_no, change_type, operator_id
|
||||
FROM xg_student_status_change
|
||||
WHERE process_status = 0
|
||||
AND change_type = 'FU_XUE'
|
||||
AND deleted = 0
|
||||
AND effective_date <= NOW()
|
||||
ORDER BY create_time ASC
|
||||
LIMIT $BATCH_SIZE;
|
||||
"
|
||||
|
||||
local records
|
||||
records=$(execute_query "$query_sql")
|
||||
|
||||
if [[ $? -ne 0 ]]; then
|
||||
log "ERROR" "获取待处理记录失败"
|
||||
sleep $CYCLE_INTERVAL
|
||||
continue
|
||||
fi
|
||||
|
||||
# 检查是否有记录需要处理(过滤掉空行和MySQL警告信息)
|
||||
local clean_records
|
||||
clean_records=$(echo "$records" | grep -v "^mysql:" | grep -v "^$" | wc -l)
|
||||
|
||||
if [[ $clean_records -eq 0 ]]; then
|
||||
log "INFO" "未找到未处理的复学记录,正在等待..."
|
||||
else
|
||||
log "INFO" "找到 $clean_records 条待处理复学记录"
|
||||
|
||||
local processed_count=0
|
||||
local failed_count=0
|
||||
|
||||
# Process records directly from the query result, skip header and empty lines
|
||||
local is_first_line=true
|
||||
while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
|
||||
# Skip completely empty lines
|
||||
[[ -z "$record_id$student_id$student_no$change_type$operator_id" ]] && continue
|
||||
|
||||
# Skip header line (first non-empty line that looks like column names)
|
||||
if [[ $is_first_line == true ]]; then
|
||||
is_first_line=false
|
||||
# Check if this looks like a header line
|
||||
if [[ "$record_id" == "id" || "$record_id" =~ ^[[:space:]]*id[[:space:]]*$ ]]; then
|
||||
log "INFO" "跳过标题行"
|
||||
continue
|
||||
fi
|
||||
fi
|
||||
|
||||
# Validate required fields
|
||||
if [[ -z "$record_id" || -z "$student_id" || -z "$student_no" || -z "$change_type" ]]; then
|
||||
log "WARN" "跳过无效记录 - ID: '$record_id', 学生ID: '$student_id', 学号: '$student_no', 类型: '$change_type'"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Log the record being processed for debugging
|
||||
log "INFO" "读取到复学记录 - ID: $record_id, 学生ID: $student_id, 学号: $student_no, 类型: $change_type, 操作员: ${operator_id:-1}"
|
||||
|
||||
local retry_count=0
|
||||
local success=false
|
||||
|
||||
while [[ $retry_count -lt $MAX_RETRY && $success == false ]]; do
|
||||
if process_student_resume "$record_id" "$student_id" "$student_no" "$change_type" "$operator_id"; then
|
||||
success=true
|
||||
((processed_count++))
|
||||
else
|
||||
((retry_count++))
|
||||
if [[ $retry_count -lt $MAX_RETRY ]]; then
|
||||
log "WARN" "处理失败,$RETRY_DELAY 秒后重试... (尝试 $retry_count/$MAX_RETRY)"
|
||||
sleep $RETRY_DELAY
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ $success == false ]]; then
|
||||
((failed_count++))
|
||||
log "ERROR" "$MAX_RETRY 次尝试后仍处理失败 - ID: $record_id"
|
||||
fi
|
||||
|
||||
done <<< "$(echo "$records" | grep -v "^mysql:" | grep -v "^$")"
|
||||
|
||||
log "INFO" "复学处理周期完成 - 已处理: $processed_count, 失败: $failed_count"
|
||||
fi
|
||||
|
||||
# 等待配置的间隔时间后开始下一个周期
|
||||
log "INFO" "等待 $CYCLE_INTERVAL 秒后开始下一个复学处理周期..."
|
||||
sleep $CYCLE_INTERVAL
|
||||
done
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -0,0 +1,140 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Production environment debug script for student status change scripts
|
||||
# This script helps diagnose MySQL output format issues
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
CONFIG_FILE="${SCRIPT_DIR}/data.conf"
|
||||
|
||||
if [[ ! -f "$CONFIG_FILE" ]]; then
|
||||
echo "错误:配置文件 $CONFIG_FILE 未找到!"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
source "$CONFIG_FILE"
|
||||
|
||||
echo "=== 生产环境调试信息 ==="
|
||||
echo "时间: $(date)"
|
||||
echo "脚本目录: $SCRIPT_DIR"
|
||||
echo "SHELL: $SHELL"
|
||||
echo "BASH_VERSION: $BASH_VERSION"
|
||||
echo
|
||||
|
||||
echo "=== MySQL版本信息 ==="
|
||||
mysql --version
|
||||
echo
|
||||
|
||||
echo "=== 系统信息 ==="
|
||||
uname -a
|
||||
echo
|
||||
|
||||
# Test basic connection
|
||||
echo "=== 测试数据库连接 ==="
|
||||
if mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "SELECT 1;" >/dev/null 2>&1; then
|
||||
echo "数据库连接成功"
|
||||
else
|
||||
echo "数据库连接失败"
|
||||
exit 1
|
||||
fi
|
||||
echo
|
||||
|
||||
# Test query formats
|
||||
echo "=== 测试MySQL查询输出格式 ==="
|
||||
|
||||
QUERY="SELECT id, student_id, student_no, change_type, operator_id FROM xg_student_status_change WHERE process_status = 0 AND change_type IN ('XIU_XUE', 'TUI_XUE', 'BI_YE') AND deleted = 0 AND effective_date <= NOW() ORDER BY create_time ASC LIMIT 2;"
|
||||
|
||||
echo "查询SQL: $QUERY"
|
||||
echo
|
||||
|
||||
echo "1. 标准mysql -e 输出 (可能包含表格格式):"
|
||||
echo "----------------------------------------"
|
||||
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" -e "$QUERY" 2>&1
|
||||
echo "----------------------------------------"
|
||||
echo
|
||||
|
||||
echo "2. mysql -B 输出 (批量模式,无表格格式):"
|
||||
echo "----------------------------------------"
|
||||
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -B "$DB_NAME" -e "$QUERY" 2>&1
|
||||
echo "----------------------------------------"
|
||||
echo
|
||||
|
||||
echo "3. mysql -ss 输出 (超静默模式):"
|
||||
echo "----------------------------------------"
|
||||
mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -ss "$DB_NAME" -e "$QUERY" 2>&1
|
||||
echo "----------------------------------------"
|
||||
echo
|
||||
|
||||
echo "=== 详细分析 -B 参数输出 ==="
|
||||
RESULT_B=$(mysql -h"$DB_HOST" -P"$DB_PORT" -u"$DB_USER" -p"$DB_PASS" -B "$DB_NAME" -e "$QUERY" 2>&1)
|
||||
|
||||
echo "原始输出 (包含警告):"
|
||||
echo "\"$RESULT_B\""
|
||||
echo
|
||||
|
||||
echo "按行分割查看:"
|
||||
echo "$RESULT_B" | while IFS= read -r line; do
|
||||
echo "行: '$line'"
|
||||
done
|
||||
echo
|
||||
|
||||
echo "过滤MySQL警告后的结果:"
|
||||
FILTERED_RESULT=$(echo "$RESULT_B" | grep -v "^mysql:" | grep -v "^$")
|
||||
echo "\"$FILTERED_RESULT\""
|
||||
echo
|
||||
|
||||
echo "解析为变量 (使用tab分隔):"
|
||||
if [[ -n "$FILTERED_RESULT" ]]; then
|
||||
echo "$FILTERED_RESULT" | while IFS=$'\t' read -r record_id student_id student_no change_type operator_id; do
|
||||
echo "解析结果:"
|
||||
echo " record_id: '$record_id'"
|
||||
echo " student_id: '$student_id'"
|
||||
echo " student_no: '$student_no'"
|
||||
echo " change_type: '$change_type'"
|
||||
echo " operator_id: '$operator_id'"
|
||||
echo
|
||||
|
||||
# Test if variables are numeric
|
||||
echo "变量类型检查:"
|
||||
echo " record_id 是数字: $([[ '$record_id' =~ ^[0-9]+$ ]] && echo '是' || echo '否')"
|
||||
echo " student_id 是数字: $([[ '$student_id' =~ ^[0-9]+$ ]] && echo '是' || echo '否')"
|
||||
echo " operator_id 是数字或空: $([[ -z '$operator_id' || '$operator_id' =~ ^[0-9]+$ ]] && echo '是' || echo '否')"
|
||||
echo
|
||||
|
||||
# Simulate SQL construction
|
||||
echo "模拟SQL构造:"
|
||||
TEST_SQL="UPDATE xg_student_msg SET student_status = '2' WHERE id = '$student_id';"
|
||||
echo " $TEST_SQL"
|
||||
echo
|
||||
|
||||
# Test SQL execution (dry run - just show what would be executed)
|
||||
echo "SQL执行测试 (仅显示,不实际执行):"
|
||||
echo " mysql -h'$DB_HOST' -P'$DB_PORT' -u'$DB_USER' -p'***' '$DB_NAME' -e \"$TEST_SQL\""
|
||||
done
|
||||
else
|
||||
echo "没有找到数据行,检查是否有待处理的记录"
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "=== 脚本兼容性检查 ==="
|
||||
|
||||
# Check bash features
|
||||
echo "Bash特性检查:"
|
||||
echo " 支持pipefail: $(set -o | grep pipefail)"
|
||||
echo " 支持nounset: $(set -o | grep nounset)"
|
||||
|
||||
echo
|
||||
echo "=== 环境变量检查 ==="
|
||||
echo "PATH: $PATH"
|
||||
echo "LD_LIBRARY_PATH: ${LD_LIBRARY_PATH:-未设置}"
|
||||
|
||||
echo
|
||||
echo "=== 建议的修复方案 ==="
|
||||
echo "如果上述解析失败,请尝试以下修改:"
|
||||
echo "1. 在脚本开头添加: export LANG=C"
|
||||
echo "2. 修改MySQL查询使用 -ss 参数而不是 -B"
|
||||
echo "3. 检查数据表中是否有实际的待处理记录"
|
||||
echo "4. 验证operator_id字段是否可能为NULL"
|
||||
|
||||
echo
|
||||
echo "=== 调试完成 ==="
|
||||
echo "请将上述输出结果发送给开发人员"
|
||||
Reference in new issue
Block a user