From 01ff87326494d71e017c516c7e6ff3e3ec8d5c31 Mon Sep 17 00:00:00 2001 From: hailin Date: Mon, 12 Jan 2026 08:33:21 -0800 Subject: [PATCH] fix(mining-admin): use Prisma relationMode=prisma for CDC sync tables Switch to Prisma's "prisma" relation mode to handle CDC event ordering issues. This mode emulates foreign key relations at the Prisma Client layer instead of creating database-level FK constraints, which is the recommended approach for CDC scenarios where event arrival order cannot be guaranteed. Reference: https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/relation-mode Co-Authored-By: Claude Opus 4.5 --- .../migration.sql | 19 +++++++++++-- .../mining-admin-service/prisma/schema.prisma | 28 +++++++++++++------ 2 files changed, 37 insertions(+), 10 deletions(-) rename backend/services/mining-admin-service/prisma/migrations/{20260113000000_remove_cdc_foreign_keys => 20260113000000_use_prisma_relation_mode}/migration.sql (53%) diff --git a/backend/services/mining-admin-service/prisma/migrations/20260113000000_remove_cdc_foreign_keys/migration.sql b/backend/services/mining-admin-service/prisma/migrations/20260113000000_use_prisma_relation_mode/migration.sql similarity index 53% rename from backend/services/mining-admin-service/prisma/migrations/20260113000000_remove_cdc_foreign_keys/migration.sql rename to backend/services/mining-admin-service/prisma/migrations/20260113000000_use_prisma_relation_mode/migration.sql index 209cce74..fa74406f 100644 --- a/backend/services/mining-admin-service/prisma/migrations/20260113000000_remove_cdc_foreign_keys/migration.sql +++ b/backend/services/mining-admin-service/prisma/migrations/20260113000000_use_prisma_relation_mode/migration.sql @@ -1,7 +1,9 @@ -- ============================================================================= --- 移除 CDC 同步表的外键约束 +-- 切换到 Prisma relationMode = "prisma" +-- 移除数据库层的外键约束,改由 Prisma Client 在应用层模拟外键关系 +-- -- 原因:CDC 事件异步到达,顺序不可控,子表记录可能在父表记录之前到达 --- 参考:https://estuary.dev/blog/cdc-done-correctly/ +-- 参考:https://www.prisma.io/docs/orm/prisma-schema/data-model/relations/relation-mode -- ============================================================================= -- 移除 synced_contribution_accounts 表的外键约束 @@ -19,3 +21,16 @@ DROP CONSTRAINT IF EXISTS "synced_mining_accounts_accountSequence_fkey"; -- 移除 synced_trading_accounts 表的外键约束 ALTER TABLE "synced_trading_accounts" DROP CONSTRAINT IF EXISTS "synced_trading_accounts_accountSequence_fkey"; + +-- 为 accountSequence 字段添加索引以优化 JOIN 性能(如果不存在) +CREATE INDEX IF NOT EXISTS "synced_contribution_accounts_accountSequence_idx" +ON "synced_contribution_accounts"("accountSequence"); + +CREATE INDEX IF NOT EXISTS "synced_referrals_accountSequence_idx" +ON "synced_referrals"("accountSequence"); + +CREATE INDEX IF NOT EXISTS "synced_mining_accounts_accountSequence_idx" +ON "synced_mining_accounts"("accountSequence"); + +CREATE INDEX IF NOT EXISTS "synced_trading_accounts_accountSequence_idx" +ON "synced_trading_accounts"("accountSequence"); diff --git a/backend/services/mining-admin-service/prisma/schema.prisma b/backend/services/mining-admin-service/prisma/schema.prisma index d0c0a3fe..a8674360 100644 --- a/backend/services/mining-admin-service/prisma/schema.prisma +++ b/backend/services/mining-admin-service/prisma/schema.prisma @@ -3,8 +3,9 @@ generator client { } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "postgresql" + url = env("DATABASE_URL") + relationMode = "prisma" // CDC场景:Prisma层模拟外键关系,数据库不创建FK约束 } // ============================================================================= @@ -163,8 +164,11 @@ model SyncedUser { syncedAt DateTime @default(now()) updatedAt DateTime @updatedAt - // CDC 同步表不设置外键约束,因为事件到达顺序不可控 - // 使用 accountSequence 作为逻辑关联键,查询时用 LEFT JOIN + // 关联同步表 + contributionAccount SyncedContributionAccount? + miningAccount SyncedMiningAccount? + tradingAccount SyncedTradingAccount? + referral SyncedReferral? @@index([phone]) @@index([status]) @@ -179,7 +183,7 @@ model SyncedUser { model SyncedContributionAccount { id String @id @default(uuid()) - accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence,无外键约束 + accountSequence String @unique personalContribution Decimal @db.Decimal(30, 8) @default(0) teamLevelContribution Decimal @db.Decimal(30, 8) @default(0) teamBonusContribution Decimal @db.Decimal(30, 8) @default(0) @@ -192,6 +196,8 @@ model SyncedContributionAccount { syncedAt DateTime @default(now()) updatedAt DateTime @updatedAt + user SyncedUser @relation(fields: [accountSequence], references: [accountSequence]) + @@map("synced_contribution_accounts") } @@ -201,7 +207,7 @@ model SyncedContributionAccount { model SyncedReferral { id String @id @default(uuid()) - accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence,无外键约束 + accountSequence String @unique referrerAccountSequence String? // 推荐人账户序列号 referrerUserId BigInt? // 1.0 的 referrer_id originalUserId BigInt? // 1.0 的 user_id @@ -210,6 +216,8 @@ model SyncedReferral { syncedAt DateTime @default(now()) updatedAt DateTime @updatedAt + user SyncedUser @relation(fields: [accountSequence], references: [accountSequence]) + @@index([referrerAccountSequence]) @@index([depth]) @@map("synced_referrals") @@ -301,7 +309,7 @@ model SyncedNetworkProgress { model SyncedMiningAccount { id String @id @default(uuid()) - accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence,无外键约束 + accountSequence String @unique totalMined Decimal @db.Decimal(30, 8) @default(0) availableBalance Decimal @db.Decimal(30, 8) @default(0) frozenBalance Decimal @db.Decimal(30, 8) @default(0) @@ -309,6 +317,8 @@ model SyncedMiningAccount { syncedAt DateTime @default(now()) updatedAt DateTime @updatedAt + user SyncedUser @relation(fields: [accountSequence], references: [accountSequence]) + @@map("synced_mining_accounts") } @@ -318,7 +328,7 @@ model SyncedMiningAccount { model SyncedTradingAccount { id String @id @default(uuid()) - accountSequence String @unique // 逻辑关联 SyncedUser.accountSequence,无外键约束 + accountSequence String @unique shareBalance Decimal @db.Decimal(30, 8) @default(0) cashBalance Decimal @db.Decimal(30, 8) @default(0) frozenShares Decimal @db.Decimal(30, 8) @default(0) @@ -328,6 +338,8 @@ model SyncedTradingAccount { syncedAt DateTime @default(now()) updatedAt DateTime @updatedAt + user SyncedUser @relation(fields: [accountSequence], references: [accountSequence]) + @@map("synced_trading_accounts") }