You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
buffer_platform/app/migration.py

92 lines
3.0 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

"""
数据缓冲平台 - SQLite 到 MySQL 数据迁移
"""
import logging
from sqlalchemy import create_engine
from sqlalchemy.orm import make_transient, sessionmaker
from app.config import DB_PATH
from app.models import MarketData, SymbolTimestamp
from app.mysql_database import MySQLSessionLocal
def _prepare_records_for_new_session(records):
"""将 ORM 实例转换为可在新 session 中插入的 transient 状态。"""
for record in records:
make_transient(record)
record.id = None
logger = logging.getLogger(__name__)
def migrate_sqlite_to_mysql():
"""从 SQLite 迁移 market_data 和 symbol_timestamps 数据到 MySQL。
幂等设计:当 MySQL 对应表已存在数据时直接跳过,避免重复写入。
返回 True 表示执行了迁移False 表示跳过或失败。
"""
if MySQLSessionLocal is None:
logger.warning("MySQL 未初始化,跳过数据迁移")
return False
sqlite_engine = create_engine(
f"sqlite:///{DB_PATH}",
connect_args={"check_same_thread": False},
)
SQLiteSession = sessionmaker(bind=sqlite_engine)
mysql_session = MySQLSessionLocal()
try:
market_data_count = mysql_session.query(MarketData).count()
symbol_timestamp_count = mysql_session.query(SymbolTimestamp).count()
migrated_market_data = False
migrated_symbol_timestamps = False
sqlite_session = SQLiteSession()
try:
market_data_records = sqlite_session.query(MarketData).all()
symbol_timestamp_records = sqlite_session.query(SymbolTimestamp).all()
finally:
sqlite_session.close()
if market_data_count > 0:
logger.info(
f"MySQL market_data 表已存在数据,跳过迁移 "
f"(market_data: {market_data_count})"
)
else:
_prepare_records_for_new_session(market_data_records)
if market_data_records:
mysql_session.add_all(market_data_records)
migrated_market_data = True
if symbol_timestamp_count > 0:
logger.info(
f"MySQL symbol_timestamps 表已存在数据,跳过迁移 "
f"(symbol_timestamps: {symbol_timestamp_count})"
)
else:
_prepare_records_for_new_session(symbol_timestamp_records)
if symbol_timestamp_records:
mysql_session.add_all(symbol_timestamp_records)
migrated_symbol_timestamps = True
if not migrated_market_data and not migrated_symbol_timestamps:
logger.info("MySQL 已存在数据,跳过迁移")
return False
mysql_session.commit()
logger.info(
f"迁移完成: market_data: {len(market_data_records)} 条, "
f"symbol_timestamps: {len(symbol_timestamp_records)}"
)
return True
except Exception as e:
logger.error(f"数据迁移失败: {e}")
mysql_session.rollback()
return False
finally:
mysql_session.close()