上传源码
This commit is contained in:
233
sync_data.py
Normal file
233
sync_data.py
Normal file
@@ -0,0 +1,233 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Lazer API 数据同步脚本
|
||||
用于将现有的 bancho.py 数据同步到新的 lazer 专用表中
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import pymysql
|
||||
from typing import Optional
|
||||
import logging
|
||||
from datetime import datetime
|
||||
|
||||
# 配置日志
|
||||
logging.basicConfig(
|
||||
level=logging.INFO,
|
||||
format='%(asctime)s - %(levelname)s - %(message)s',
|
||||
handlers=[
|
||||
logging.FileHandler('data_sync.log'),
|
||||
logging.StreamHandler(sys.stdout)
|
||||
]
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
class DatabaseSyncer:
|
||||
def __init__(self, host: str, port: int, user: str, password: str, database: str):
|
||||
"""初始化数据库连接配置"""
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.user = user
|
||||
self.password = password
|
||||
self.database = database
|
||||
self.connection = None
|
||||
|
||||
def connect(self):
|
||||
"""连接到数据库"""
|
||||
try:
|
||||
self.connection = pymysql.connect(
|
||||
host=self.host,
|
||||
port=self.port,
|
||||
user=self.user,
|
||||
password=self.password,
|
||||
database=self.database,
|
||||
charset='utf8mb4',
|
||||
autocommit=False
|
||||
)
|
||||
logger.info(f"成功连接到数据库 {self.database}")
|
||||
except Exception as e:
|
||||
logger.error(f"连接数据库失败: {e}")
|
||||
raise
|
||||
|
||||
def disconnect(self):
|
||||
"""断开数据库连接"""
|
||||
if self.connection:
|
||||
self.connection.close()
|
||||
logger.info("数据库连接已关闭")
|
||||
|
||||
def execute_sql_file(self, file_path: str):
|
||||
"""执行 SQL 文件"""
|
||||
if not os.path.exists(file_path):
|
||||
logger.error(f"SQL 文件不存在: {file_path}")
|
||||
return False
|
||||
|
||||
try:
|
||||
with open(file_path, 'r', encoding='utf-8') as f:
|
||||
sql_content = f.read()
|
||||
|
||||
# 分割SQL语句(简单实现,按分号分割)
|
||||
statements = [stmt.strip() for stmt in sql_content.split(';') if stmt.strip()]
|
||||
|
||||
cursor = self.connection.cursor()
|
||||
|
||||
for i, statement in enumerate(statements):
|
||||
# 跳过注释和空语句
|
||||
if statement.startswith('--') or not statement:
|
||||
continue
|
||||
|
||||
try:
|
||||
logger.info(f"执行第 {i+1}/{len(statements)} 条SQL语句...")
|
||||
cursor.execute(statement)
|
||||
|
||||
# 如果是SELECT语句,显示结果
|
||||
if statement.strip().upper().startswith('SELECT'):
|
||||
results = cursor.fetchall()
|
||||
if results:
|
||||
logger.info(f"查询结果: {results}")
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"执行SQL语句失败: {statement[:100]}...")
|
||||
logger.error(f"错误信息: {e}")
|
||||
# 继续执行其他语句
|
||||
continue
|
||||
|
||||
self.connection.commit()
|
||||
cursor.close()
|
||||
logger.info(f"成功执行SQL文件: {file_path}")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"执行SQL文件失败: {e}")
|
||||
if self.connection:
|
||||
self.connection.rollback()
|
||||
return False
|
||||
|
||||
def check_tables_exist(self, tables: list) -> dict:
|
||||
"""检查表是否存在"""
|
||||
results = {}
|
||||
cursor = self.connection.cursor()
|
||||
|
||||
for table in tables:
|
||||
try:
|
||||
cursor.execute(f"SHOW TABLES LIKE '{table}'")
|
||||
exists = cursor.fetchone() is not None
|
||||
results[table] = exists
|
||||
logger.info(f"表 '{table}' {'存在' if exists else '不存在'}")
|
||||
except Exception as e:
|
||||
logger.error(f"检查表 '{table}' 时出错: {e}")
|
||||
results[table] = False
|
||||
|
||||
cursor.close()
|
||||
return results
|
||||
|
||||
def get_table_count(self, table: str) -> int:
|
||||
"""获取表的记录数"""
|
||||
try:
|
||||
cursor = self.connection.cursor()
|
||||
cursor.execute(f"SELECT COUNT(*) FROM {table}")
|
||||
result = cursor.fetchone()
|
||||
count = result[0] if result else 0
|
||||
cursor.close()
|
||||
return count
|
||||
except Exception as e:
|
||||
logger.error(f"获取表 '{table}' 记录数失败: {e}")
|
||||
return -1
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
print("Lazer API 数据同步工具")
|
||||
print("=" * 50)
|
||||
|
||||
# 数据库配置
|
||||
db_config = {
|
||||
'host': input("数据库主机 [localhost]: ").strip() or 'localhost',
|
||||
'port': int(input("数据库端口 [3306]: ").strip() or '3306'),
|
||||
'user': input("数据库用户名: ").strip(),
|
||||
'password': input("数据库密码: ").strip(),
|
||||
'database': input("数据库名称: ").strip()
|
||||
}
|
||||
|
||||
syncer = DatabaseSyncer(**db_config)
|
||||
|
||||
try:
|
||||
# 连接数据库
|
||||
syncer.connect()
|
||||
|
||||
# 检查必要的原始表是否存在
|
||||
required_tables = ['users', 'stats']
|
||||
table_status = syncer.check_tables_exist(required_tables)
|
||||
|
||||
missing_tables = [table for table, exists in table_status.items() if not exists]
|
||||
if missing_tables:
|
||||
logger.error(f"缺少必要的原始表: {missing_tables}")
|
||||
return
|
||||
|
||||
# 显示原始表的记录数
|
||||
for table in required_tables:
|
||||
count = syncer.get_table_count(table)
|
||||
logger.info(f"表 '{table}' 当前有 {count} 条记录")
|
||||
|
||||
# 确认是否执行同步
|
||||
print("\n准备执行数据同步...")
|
||||
print("这将会:")
|
||||
print("1. 创建 lazer 专用表结构 (如果不存在)")
|
||||
print("2. 从现有表同步数据到新表")
|
||||
print("3. 不会修改或删除现有数据")
|
||||
|
||||
confirm = input("\n是否继续? (y/N): ").strip().lower()
|
||||
if confirm != 'y':
|
||||
print("操作已取消")
|
||||
return
|
||||
|
||||
# 执行表结构创建
|
||||
migrations_dir = os.path.join(os.path.dirname(__file__), 'migrations')
|
||||
|
||||
print("\n步骤 1: 创建表结构...")
|
||||
add_fields_sql = os.path.join(migrations_dir, 'add_missing_fields.sql')
|
||||
if os.path.exists(add_fields_sql):
|
||||
success = syncer.execute_sql_file(add_fields_sql)
|
||||
if not success:
|
||||
logger.error("创建表结构失败")
|
||||
return
|
||||
else:
|
||||
logger.warning(f"表结构文件不存在: {add_fields_sql}")
|
||||
|
||||
# 执行数据同步
|
||||
print("\n步骤 2: 同步数据...")
|
||||
sync_sql = os.path.join(migrations_dir, 'sync_legacy_data.sql')
|
||||
if os.path.exists(sync_sql):
|
||||
success = syncer.execute_sql_file(sync_sql)
|
||||
if not success:
|
||||
logger.error("数据同步失败")
|
||||
return
|
||||
else:
|
||||
logger.error(f"同步脚本不存在: {sync_sql}")
|
||||
return
|
||||
|
||||
# 显示同步后的统计信息
|
||||
print("\n步骤 3: 同步完成统计...")
|
||||
lazer_tables = [
|
||||
'lazer_user_profiles',
|
||||
'lazer_user_countries',
|
||||
'lazer_user_statistics',
|
||||
'lazer_user_kudosu',
|
||||
'lazer_user_counts'
|
||||
]
|
||||
|
||||
for table in lazer_tables:
|
||||
count = syncer.get_table_count(table)
|
||||
if count >= 0:
|
||||
logger.info(f"表 '{table}' 现在有 {count} 条记录")
|
||||
|
||||
print("\n数据同步完成!")
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print("\n\n操作被用户中断")
|
||||
except Exception as e:
|
||||
logger.error(f"同步过程中发生错误: {e}")
|
||||
finally:
|
||||
syncer.disconnect()
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user