Files
MBTI_wang/scripts/mysql_mirror_krimp_wechat_users.py

151 lines
4.8 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
将「源库」里 openid 以 krimp_ 开头的 wechat_users 行INSERT IGNORE 到「目标库」。
用于:数据已写入仓库 api/.env 指向的腾讯云,但 mbtiapi 线上仍连宝塔本机 MySQL 时,
把 krimp 导入用户同步到线上实际读写的库。
源/目标配置格式与 api/.env 相同DATABASE_HOSTNAME、DATABASE_HOSTPORT、…
用法:
# 复制 api/.env.mysql.line内容=线上服务器 api/.env 里数据库段),勿提交 Git
python3 scripts/mysql_mirror_krimp_wechat_users.py \\
--source-env api/.env \\
--target-env api/.env.mysql.line
仅校验连接、不写入:
python3 scripts/mysql_mirror_krimp_wechat_users.py --target-env api/.env.mysql.line --dry-run
"""
from __future__ import annotations
import argparse
import re
import sys
from pathlib import Path
try:
import pymysql
except ImportError:
sys.exit("需要 pymysql")
def load_env(path: Path) -> dict[str, str]:
cfg: dict[str, str] = {}
if not path.is_file():
return cfg
for line in path.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
m = re.match(r"^([A-Z0-9_]+)\s*=\s*(.*)$", line)
if m:
cfg[m.group(1)] = m.group(2).strip()
return cfg
def connect(cfg: dict[str, str]):
return pymysql.connect(
host=cfg.get("DATABASE_HOSTNAME", "127.0.0.1"),
port=int(cfg.get("DATABASE_HOSTPORT", "3306")),
user=cfg.get("DATABASE_USERNAME", "root"),
password=cfg.get("DATABASE_PASSWORD", ""),
database=cfg.get("DATABASE_DATABASE", "mbti"),
charset="utf8mb4",
)
def main() -> None:
root = Path(__file__).resolve().parents[1]
ap = argparse.ArgumentParser()
ap.add_argument("--source-env", type=Path, default=root / "api" / ".env")
ap.add_argument("--target-env", type=Path, required=True)
ap.add_argument("--batch", type=int, default=200)
ap.add_argument("--dry-run", action="store_true")
args = ap.parse_args()
src_cfg = load_env(args.source_env)
dst_cfg = load_env(args.target_env)
if not dst_cfg.get("DATABASE_HOSTNAME"):
sys.exit(f"目标配置无效或文件不存在: {args.target_env}")
pre_s = src_cfg.get("DATABASE_PREFIX", "mbti_")
pre_d = dst_cfg.get("DATABASE_PREFIX", "mbti_")
tbl_s = f"{pre_s}wechat_users"
tbl_d = f"{pre_d}wechat_users"
src = connect(src_cfg)
dst = connect(dst_cfg)
inserted = 0
try:
with src.cursor() as cs, dst.cursor() as cd:
cs.execute(f"SHOW COLUMNS FROM `{tbl_s}`")
src_order = [r[0] for r in cs.fetchall()]
cd.execute(f"SHOW COLUMNS FROM `{tbl_d}`")
dst_set = {r[0] for r in cd.fetchall()}
columns = [c for c in src_order if c != "id" and c in dst_set]
col_sql = ", ".join(f"`{c}`" for c in columns)
placeholders = ", ".join(["%s"] * len(columns))
insert_sql = f"INSERT IGNORE INTO `{tbl_d}` ({col_sql}) VALUES ({placeholders})"
cs.execute(
f"SELECT COUNT(*) FROM `{tbl_s}` WHERE `openid` LIKE %s", ("krimp_%",)
)
n_src = cs.fetchone()[0]
if args.dry_run:
print(
{
"dry_run": True,
"source_rows_krimp": n_src,
"source_table": tbl_s,
"target_table": tbl_d,
}
)
return
with src.cursor() as cs, dst.cursor() as cd:
cs.execute(
f"SELECT {col_sql} FROM `{tbl_s}` WHERE `openid` LIKE %s",
("krimp_%",),
)
batch = []
for row in cs:
batch.append(row)
if len(batch) >= args.batch:
cd.executemany(insert_sql, batch)
inserted += cd.rowcount
dst.commit()
batch = []
if batch:
cd.executemany(insert_sql, batch)
inserted += cd.rowcount
dst.commit()
with dst.cursor() as cd:
cd.execute(
f"SELECT COUNT(*) FROM `{tbl_d}` WHERE `openid` LIKE %s", ("krimp_%",)
)
n_dst = cd.fetchone()[0]
cd.execute(f"SELECT COUNT(*) FROM `{tbl_d}`")
total_dst = cd.fetchone()[0]
print(
{
"ok": True,
"source_krimp": n_src,
"target_krimp_after": n_dst,
"target_total_after": total_dst,
"insert_ignore_rowcount_sum": inserted,
}
)
finally:
src.close()
dst.close()
if __name__ == "__main__":
main()