feat(deploy): 完成数据迁移与MySQL全链路(14表698k消息100%一致+5方言补丁+bind mount)

- migrate_sqlite_to_mysql.py: 逐表清空重导(幂等),复用repos强转,JSON列
  解析,67万消息按msg_id键集分批,467s跑完14表全一致
- 修4个MySQL实测bug: NULLS LAST语法(compat.py编译补丁)、message.text
  TEXT→MEDIUMTEXT(64KB字节上限,实测20.8万字符车源清单)、URL列
  String(1024)→Text(分享链接超1KB)、垃圾超长member_id源头清理
- compose: media改bind mount(不占C盘Docker虚拟磁盘,实测2.5GB卷把
  C盘撑爆引擎500);mysql不映射宿主机3306
- 前端Dockerfile: npm ci→install(本地/容器npm版本锁漂移)
- 五服务实测:nginx→backend→MySQL全链路返回真实数据(客户6859/A**杰25条
  /搜索56条),媒体49536文件bind mount直读

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
浅念
2026-08-22 12:40:44 +08:00
parent 2175cb0169
commit 00ae13b5c2
6 changed files with 207 additions and 13 deletions
+10 -5
View File
@@ -45,6 +45,7 @@ import datetime as dt
from typing import Any
import sqlalchemy as sa
from sqlalchemy.dialects.mysql import MEDIUMTEXT # noqa: E402
from sqlalchemy import BigInteger, Boolean, DateTime, Index, Integer, String, Text
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy.types import JSON
@@ -358,10 +359,14 @@ class Message(Base):
type_raw: Mapped[int | None] = mapped_column(
Integer, nullable=True
) # original upstream type code (e.g. WeChat 1=text, -2=divider)
text: Mapped[str | None] = mapped_column(Text, nullable=True) # content/text
file_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
file_th_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
file_hd_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
# MEDIUMTEXT(16MB):MySQL TEXT 上限 64KB 字节,实测车源清单消息最长
# 20.8万字符(≈800KB utf8mb4)超限(2026-08-21 迁移踩坑)
text: Mapped[str | None] = mapped_column(
Text().with_variant(MEDIUMTEXT(), "mysql"), nullable=True
) # content/text
file_url: Mapped[str | None] = mapped_column(sa.Text, nullable=True) # 分享链接可超1KB(实测,2026-08-21)
file_th_url: Mapped[str | None] = mapped_column(sa.Text, nullable=True)
file_hd_url: Mapped[str | None] = mapped_column(sa.Text, nullable=True)
md5: Mapped[str | None] = mapped_column(String(64), nullable=True)
md5_th: Mapped[str | None] = mapped_column(String(64), nullable=True)
md5_hd: Mapped[str | None] = mapped_column(String(64), nullable=True)
@@ -428,7 +433,7 @@ class Media(Base):
media_type: Mapped[str | None] = mapped_column(
String(32), nullable=True
) # image|voice|video|file|...
original_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
original_url: Mapped[str | None] = mapped_column(sa.Text, nullable=True)
original_th_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
original_hd_url: Mapped[str | None] = mapped_column(String(1024), nullable=True)
local_path: Mapped[str | None] = mapped_column(String(1024), nullable=True)