Files
zentao-flow/tmp/sync_9197_to_test.py

101 lines
4.4 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.
# -*- coding: utf-8 -*-
"""200 zentao_dev → 161 zentao_dev_2026:同步研发需求 9197 的关联记录。
源库全程只读;目标库纯 INSERT(前置检查目标无对应行,不覆盖不删除)。
范围:zt_storyspec / zt_projectstory / zt_task / zt_action / zt_effort(有则带)。
"""
import io, sys, time, pymysql
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')
SRC = dict(host='192.168.3.200', user='root', password='PX4fTAAsJ#T!1',
database='zentao_dev', charset='utf8mb4', connect_timeout=15)
DST = dict(host='192.168.1.161', user='devgps', password='dev@2021GPS',
database='zentao_dev_2026', charset='utf8mb4', connect_timeout=15, autocommit=False)
SID = 9197
TASK_IDS = (18841, 18849)
def log(m):
print(f'[{time.strftime("%H:%M:%S")}] {m}', flush=True)
src = pymysql.connect(**SRC); scur = src.cursor()
dst = pymysql.connect(**DST); dcur = dst.cursor()
def cols_of(cur, t):
cur.execute("""SELECT column_name FROM information_schema.columns
WHERE table_schema=DATABASE() AND table_name=%s
ORDER BY ordinal_position""", (t,))
return [r[0] for r in cur.fetchall()]
def fetch(t, where, params):
scur.execute(f'SELECT * FROM `{t}` WHERE {where}', params)
cols = [d[0] for d in scur.description]
return cols, scur.fetchall()
def sync_table(t, where, params, key_desc):
scols, rows = fetch(t, where, params)
if not rows:
log(f'{t}: 源库 0 行,跳过')
return 0
dcols = set(cols_of(dcur, t))
use = [c for c in scols if c in dcols]
dropped = [c for c in scols if c not in dcols]
if dropped:
log(f'{t}: 目标库缺列 {dropped},这些列不写入')
# 前置检查:目标不能有与源主键冲突的行 —— 用第一主键列粗查
col_sql = ','.join(f'`{c}`' for c in use)
ph = ','.join(['%s'] * len(use))
insert_sql = f'INSERT INTO `{t}` ({col_sql}) VALUES ({ph})'
idx = [scols.index(c) for c in use]
data = [tuple(r[i] for i in idx) for r in rows]
dcur.executemany(insert_sql, data)
log(f'{t}: 插入 {len(data)} 行({key_desc})')
return len(data)
# ---------- 前置检查(目标应为空/无冲突) ----------
problems = []
dcur.execute('SELECT COUNT(*) FROM zt_storyspec WHERE story=%s', (SID,))
if dcur.fetchone()[0]: problems.append('zt_storyspec 已有 9197')
dcur.execute('SELECT COUNT(*) FROM zt_projectstory WHERE story=%s', (SID,))
if dcur.fetchone()[0]: problems.append('zt_projectstory 已有 9197')
dcur.execute(f'SELECT COUNT(*) FROM zt_task WHERE id IN {TASK_IDS}')
if dcur.fetchone()[0]: problems.append(f'zt_task id {TASK_IDS} 冲突')
dcur.execute('SELECT COUNT(*) FROM zt_action WHERE objectType=\'story\' AND objectID=%s AND id>119100', (SID,))
if dcur.fetchone()[0]: problems.append('zt_action 已有 9197 的源端记录')
if problems:
log('!!! 前置检查失败: ' + '; '.join(problems))
sys.exit(1)
log('前置检查通过:目标库无冲突')
# ---------- 同步 ----------
n = 0
n += sync_table('zt_storyspec', 'story=%s', (SID,), 'story=9197')
n += sync_table('zt_projectstory', 'story=%s', (SID,), 'story=9197, project 142/286')
n += sync_table('zt_task', f'id IN {TASK_IDS}', (), f'id={TASK_IDS}')
n += sync_table('zt_action', "objectType='story' AND objectID=%s", (SID,), 'story=9197 流转历史')
# zt_effort 可能有,也可能没有 task 列/相关行
ecols = cols_of(scur, 'zt_effort')
if ecols:
key = 'task' if 'task' in ecols else ('objectID' if 'objectID' in ecols else None)
if key:
where = f'`{key}` IN {TASK_IDS}' + (" AND objectType='task'" if 'objectType' in ecols else '')
n += sync_table('zt_effort', where, (), f'task={TASK_IDS}')
dst.commit()
log(f'已提交,共写入 {n} 行')
# ---------- 回读验证 ----------
log('--- 回读验证 ---')
dcur.execute('SELECT story, version, LEFT(title,30), LENGTH(spec), LENGTH(verify) FROM zt_storyspec WHERE story=%s', (SID,))
log(f'zt_storyspec: {dcur.fetchall()}')
dcur.execute('SELECT project, story, version, `order` FROM zt_projectstory WHERE story=%s', (SID,))
log(f'zt_projectstory: {dcur.fetchall()}')
dcur.execute(f'SELECT id, project, execution, name, status, assignedTo FROM zt_task WHERE id IN {TASK_IDS}')
for r in dcur.fetchall():
log(f'zt_task: {r}')
dcur.execute("SELECT id, action, date, actor FROM zt_action WHERE objectType='story' AND objectID=%s ORDER BY id", (SID,))
for r in dcur.fetchall():
log(f'zt_action: {r}')
src.close(); dst.close()
log('完成')