fix(dsync): ①pk_cols约束名'PRIMARY KEY'改'PRIMARY'——MySQL/MariaDB主键约束名就是PRIMARY,查空致主键列表为空,upsert全走INSERT撞1062(测试机实测抓到,首表subject即崩);②导入循环加显式try/ROLLBACK——任何未捕获异常主动回滚关连接,不靠进程退出隐式回滚(泄漏未提交事务会持MDL锁)
This commit is contained in:
parent
8be4e8f940
commit
2fe3d446dc
@ -104,12 +104,15 @@ def select_domains(defn, wanted):
|
|||||||
|
|
||||||
|
|
||||||
def pk_cols(conn, table):
|
def pk_cols(conn, table):
|
||||||
|
# 主键约束名是 'PRIMARY'(MySQL/MariaDB 同)——写成 'PRIMARY KEY' 恒查空,
|
||||||
|
# 主键列表为空会让 upsert 全走 INSERT 撞 1062(2026-09-09 测试机实测抓到)
|
||||||
with conn.cursor() as cur:
|
with conn.cursor() as cur:
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"SELECT column_name FROM information_schema.key_column_usage "
|
"SELECT column_name FROM information_schema.key_column_usage "
|
||||||
"WHERE table_schema=DATABASE() AND table_name=%s AND constraint_name='PRIMARY KEY' "
|
"WHERE table_schema=DATABASE() AND table_name=%s AND constraint_name='PRIMARY' "
|
||||||
"ORDER BY ordinal_position", (table,))
|
"ORDER BY ordinal_position", (table,))
|
||||||
return [r["column_name"] if "column_name" in r else r["COLUMN_NAME"] for r in cur.fetchall()]
|
rows = cur.fetchall()
|
||||||
|
return [(r.get("column_name") or r.get("COLUMN_NAME")) for r in rows]
|
||||||
|
|
||||||
|
|
||||||
def table_cols(conn, table):
|
def table_cols(conn, table):
|
||||||
@ -297,31 +300,37 @@ def cmd_import(pkg_file, dry_run=False):
|
|||||||
pk = pk_cols(conn, tbl)
|
pk = pk_cols(conn, tbl)
|
||||||
tcols = set(table_cols(conn, tbl))
|
tcols = set(table_cols(conn, tbl))
|
||||||
n_i = n_u = n_o = 0
|
n_i = n_u = n_o = 0
|
||||||
for row in meta["rows"]:
|
try:
|
||||||
if org_col and str(row.get(org_col) or "") not in orgs:
|
for row in meta["rows"]:
|
||||||
n_o += 1
|
if org_col and str(row.get(org_col) or "") not in orgs:
|
||||||
stats["org_skipped"] += 1
|
n_o += 1
|
||||||
continue
|
stats["org_skipped"] += 1
|
||||||
if dry_run:
|
continue
|
||||||
# 预演也查存在性,给出准确的新增/更新预估
|
if dry_run:
|
||||||
ex = False
|
# 预演也查存在性,给出准确的新增/更新预估
|
||||||
if pk:
|
ex = False
|
||||||
where = " AND ".join("`%s`=%%s" % c for c in pk)
|
if pk:
|
||||||
with conn.cursor() as cur:
|
where = " AND ".join("`%s`=%%s" % c for c in pk)
|
||||||
cur.execute("SELECT 1 FROM `%s` WHERE %s LIMIT 1" % (tbl, where),
|
with conn.cursor() as cur:
|
||||||
tuple(str(row.get(c, "")) for c in pk))
|
cur.execute("SELECT 1 FROM `%s` WHERE %s LIMIT 1" % (tbl, where),
|
||||||
ex = cur.fetchone() is not None
|
tuple(str(row.get(c, "")) for c in pk))
|
||||||
if ex:
|
ex = cur.fetchone() is not None
|
||||||
n_u += 1
|
if ex:
|
||||||
else:
|
n_u += 1
|
||||||
|
else:
|
||||||
|
n_i += 1
|
||||||
|
continue
|
||||||
|
res = upsert_row(conn, tbl, pk, row, tcols)
|
||||||
|
stats[res if res in stats else "skipped"] += 1
|
||||||
|
if res == "inserted":
|
||||||
n_i += 1
|
n_i += 1
|
||||||
continue
|
elif res == "updated":
|
||||||
res = upsert_row(conn, tbl, pk, row, tcols)
|
n_u += 1
|
||||||
stats[res if res in stats else "skipped"] += 1
|
except Exception as e:
|
||||||
if res == "inserted":
|
# 任何未捕获异常都显式 ROLLBACK——绝不靠进程退出隐式回滚(连接可能泄漏未提交事务持 MDL 锁)
|
||||||
n_i += 1
|
conn.rollback()
|
||||||
elif res == "updated":
|
conn.close()
|
||||||
n_u += 1
|
die("导入表 %s 失败,已 ROLLBACK: %s" % (tbl, str(e)[:300]))
|
||||||
print(" %-24s 新增%d 更新%d%s" % (tbl, n_i, n_u,
|
print(" %-24s 新增%d 更新%d%s" % (tbl, n_i, n_u,
|
||||||
(" 机构过滤跳过%d" % n_o) if n_o else ""))
|
(" 机构过滤跳过%d" % n_o) if n_o else ""))
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user