django 使用绑定多个数据库实现数据的同步

文章目录

    • [1. 配置多数据库](#1. 配置多数据库)
    • [2. 定义模型](#2. 定义模型)
    • [3. 跨库同步任务](#3. 跨库同步任务)
    • [4. 要点说明](#4. 要点说明)
    • [5. 进一步优化](#5. 进一步优化)
  • [🔑 需求分解](#🔑 需求分解)
  • [📌 1. 模型定义](#📌 1. 模型定义)
  • [📌 2. 字段映射配置](#📌 2. 字段映射配置)
  • [📌 3. 增量批量同步函数](#📌 3. 增量批量同步函数)
  • [📌 4. Celery 定时任务](#📌 4. Celery 定时任务)
  • [📌 5. 特点](#📌 5. 特点)
  • [⚡️ 建议](#⚡️ 建议)
    • [📌 1. Redis 配置](#📌 1. Redis 配置)
    • [📌 2. 同步配置(多表映射)](#📌 2. 同步配置(多表映射))
    • [📌 3. 通用同步服务](#📌 3. 通用同步服务)
    • [📌 4. Celery 任务](#📌 4. Celery 任务)
    • [📌 5. Celery 定时配置](#📌 5. Celery 定时配置)
    • [📌 6. 效果](#📌 6. 效果)

明白了 ✅ 你的需求是:

  • 项目里有两个数据库:

    • default → SQL Server
    • wms → MySQL
  • 要把 default 中某个表的部分字段 ,同步到 wms 中的某个表

这类跨库同步在 Django 里完全可以做到,关键在于 多数据库配置 + 数据库路由/指定数据库操作


1. 配置多数据库

settings.py

python 复制代码
DATABASES = {
    "default": {   # SQL Server
        "ENGINE": "mssql",
        "NAME": "default_db",
        "USER": "sa",
        "PASSWORD": "your_password",
        "HOST": "127.0.0.1",
        "PORT": "1433",
        "OPTIONS": {
            "driver": "ODBC Driver 17 for SQL Server",
        },
    },
    "wms": {   # MySQL
        "ENGINE": "django.db.backends.mysql",
        "NAME": "wms_db",
        "USER": "root",
        "PASSWORD": "your_password",
        "HOST": "127.0.0.1",
        "PORT": "3306",
    },
}

2. 定义模型

假设 default 里有 Customer 表(SQL Server),
wms 里有 WmsCustomer 表(MySQL)。

python 复制代码
# myapp/models.py
from django.db import models

# default 数据库(SQL Server)
class Customer(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    email = models.EmailField()

    class Meta:
        managed = False  # 不要让 Django 管理(迁移),因为表已经存在
        db_table = "customer"
        app_label = "default_app"


# wms 数据库(MySQL)
class WmsCustomer(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    email = models.EmailField()

    class Meta:
        managed = False
        db_table = "wms_customer"
        app_label = "wms_app"

3. 跨库同步任务

写一个简单的管理命令(或者 Celery 任务):

python 复制代码
# myapp/management/commands/sync_customers.py
from django.core.management.base import BaseCommand
from myapp.models import Customer, WmsCustomer
from django.db import transaction

class Command(BaseCommand):
    help = "同步 default.customer 到 wms.wms_customer"

    def handle(self, *args, **kwargs):
        customers = Customer.objects.using("default").all()

        with transaction.atomic(using="wms"):
            for c in customers:
                WmsCustomer.objects.using("wms").update_or_create(
                    id=c.id,
                    defaults={
                        "name": c.name,
                        "email": c.email,
                    }
                )
        self.stdout.write(self.style.SUCCESS("同步完成"))

运行:

bash 复制代码
python manage.py sync_customers

4. 要点说明

  • .using("xxx") 可以指定操作哪个数据库。
  • transaction.atomic(using="wms") 保证同步到 wms 时是原子性的。
  • update_or_create 用于避免重复插入,按主键 id 匹配。
  • 如果表结构不完全一致,可以只映射需要的字段。

5. 进一步优化

  • 你可以把这个同步逻辑放到 Celery 定时任务,比如每分钟跑一次。
  • 如果是大数据量,最好用 批量操作bulk_create / bulk_update)来提高效率。

要不要我帮你写一个 支持批量同步(每次 1000 条)的 Celery 定时任务版本,避免大表同步时性能问题?

👌 明白了,你的需求升级成了一个 跨库字段映射 + 增量同步 + 批量处理 + Celery 定时任务 的场景。这个在实际项目里非常常见(例如:从 ERP / WMS / CRM 系统同步数据)。我帮你设计一个通用的方案。


🔑 需求分解

  1. 多数据库default (SQL Server) → wms (MySQL)。
  2. 字段映射:源表 10 个字段,目标表只取其中 5 个。
  3. 增量同步 :基于 last_modified 字段(源库记录更新时间)。
  4. 批量同步:每次批量插入/更新 1000 条。
  5. 定时任务:Celery Beat 定时触发。

📌 1. 模型定义

python 复制代码
# myapp/models.py
from django.db import models

# SQL Server 源表 (default 数据库)
class Customer(models.Model):
    id = models.AutoField(primary_key=True)
    name = models.CharField(max_length=100)
    email = models.EmailField()
    phone = models.CharField(max_length=20)
    address = models.TextField()
    last_modified = models.DateTimeField()  # 用来做增量同步

    class Meta:
        managed = False
        db_table = "customer"
        app_label = "default_app"


# MySQL 目标表 (wms 数据库)
class WmsCustomer(models.Model):
    id = models.AutoField(primary_key=True)
    full_name = models.CharField(max_length=100)
    email = models.EmailField()
    contact = models.CharField(max_length=20)
    updated_at = models.DateTimeField()

    class Meta:
        managed = False
        db_table = "wms_customer"
        app_label = "wms_app"

📌 2. 字段映射配置

可以用一个字典配置 源字段 → 目标字段

python 复制代码
FIELD_MAPPING = {
    "name": "full_name",
    "email": "email",
    "phone": "contact",
    "last_modified": "updated_at",
}

📌 3. 增量批量同步函数

python 复制代码
# myapp/services/sync_service.py
from django.db import transaction
from myapp.models import Customer, WmsCustomer
from django.utils.timezone import now

FIELD_MAPPING = {
    "name": "full_name",
    "email": "email",
    "phone": "contact",
    "last_modified": "updated_at",
}

BATCH_SIZE = 1000


def sync_customers(last_sync_time=None):
    """增量批量同步"""
    queryset = Customer.objects.using("default").all()

    if last_sync_time:
        queryset = queryset.filter(last_modified__gt=last_sync_time)

    total = queryset.count()
    print(f"需要同步 {total} 条数据")

    for start in range(0, total, BATCH_SIZE):
        batch = queryset.order_by("last_modified")[start:start+BATCH_SIZE]

        objs = []
        for src in batch:
            mapped_data = {
                FIELD_MAPPING[src_field]: getattr(src, src_field)
                for src_field in FIELD_MAPPING.keys()
            }
            objs.append(WmsCustomer(**mapped_data))

        with transaction.atomic(using="wms"):
            WmsCustomer.objects.using("wms").bulk_create(
                objs, batch_size=BATCH_SIZE, ignore_conflicts=True
            )

    return total

📌 4. Celery 定时任务

python 复制代码
# myapp/tasks.py
from celery import shared_task
from django.utils.timezone import now
from .services.sync_service import sync_customers
from myapp.models import TaskLog


@shared_task
def sync_customers_task():
    try:
        # 假设 last_sync_time 可以存储在某个表或缓存中
        last_sync_time = None  # TODO: 从缓存或数据库中取上次同步时间
        total = sync_customers(last_sync_time=last_sync_time)

        # TODO: 同步成功后,更新 last_sync_time
        TaskLog.objects.using("wms").create(
            task_name="sync_customers_task",
            status="success",
            message=f"成功同步 {total} 条数据"
        )
    except Exception as e:
        TaskLog.objects.using("wms").create(
            task_name="sync_customers_task",
            status="failure",
            message=str(e)
        )
        raise

celery.py 里添加定时配置:

python 复制代码
from celery.schedules import crontab

app.conf.beat_schedule = {
    "sync-customers-every-5-min": {
        "task": "myapp.tasks.sync_customers_task",
        "schedule": crontab(minute="*/5"),  # 每 5 分钟执行一次
    },
}

📌 5. 特点

  • 批量写入bulk_create,一次性提交。
  • 增量同步 :根据 last_modified,只同步变化的。
  • 字段映射:通过字典配置,不需要硬编码。
  • Celery 定时:可配置为 5 秒、5 分钟或每天定时。
  • 日志记录 :用 TaskLog 表存储执行状态,可在 Django Admin 查看。

⚡️ 建议

如果 数据量特别大(几十万+),可以考虑:

  1. 先在 SQL Server 里加索引(针对 last_modified)。
  2. iterator() 避免一次性加载所有数据。
  3. 如果目标库里可能有数据更新,考虑用 bulk_update 替代 bulk_create

要不要我帮你把这个 同步服务 改成支持 配置多个表的映射规则(比如一个配置文件里定义:源表 A → 目标表 B,源表 C → 目标表 D),这样就能用一套框架同步任意表了?

好主意 ✅

你想要的就是做一个 通用的跨库同步服务

  • 支持 多个表的配置化同步
  • 每个表的字段映射可以配置
  • 增量同步 :基于 last_modified
  • Redis 存储每个表的 last_sync_time,避免落地数据库

我给你一个完整的方案:


📌 1. Redis 配置

settings.py

python 复制代码
# Redis 用于保存每个表的 last_sync_time
REDIS_HOST = "127.0.0.1"
REDIS_PORT = 6379
REDIS_DB = 1

新建一个 redis 客户端工具 utils/redis_client.py

python 复制代码
import redis
from django.conf import settings

redis_client = redis.StrictRedis(
    host=settings.REDIS_HOST,
    port=settings.REDIS_PORT,
    db=settings.REDIS_DB,
    decode_responses=True
)

📌 2. 同步配置(多表映射)

myapp/sync_config.py

python 复制代码
SYNC_CONFIG = {
    "customer": {
        "source_model": "myapp.Customer",
        "target_model": "myapp.WmsCustomer",
        "field_mapping": {
            "name": "full_name",
            "email": "email",
            "phone": "contact",
            "last_modified": "updated_at",
        },
        "batch_size": 1000,
    },
    "order": {
        "source_model": "myapp.Order",
        "target_model": "myapp.WmsOrder",
        "field_mapping": {
            "order_no": "order_code",
            "amount": "total_price",
            "last_modified": "updated_at",
        },
        "batch_size": 500,
    }
}

📌 3. 通用同步服务

myapp/services/sync_service.py

python 复制代码
import importlib
from django.db import transaction
from django.utils.dateparse import parse_datetime
from utils.redis_client import redis_client


def load_model(model_path):
    """动态加载模型: e.g. 'myapp.Customer'"""
    app, model = model_path.split(".")
    return getattr(importlib.import_module(app + ".models"), model)


def sync_table(table_name, config):
    """同步单个表"""
    source_model = load_model(config["source_model"])
    target_model = load_model(config["target_model"])
    field_mapping = config["field_mapping"]
    batch_size = config.get("batch_size", 1000)

    # 从 Redis 获取上次同步时间
    last_sync_str = redis_client.get(f"sync:{table_name}:last_sync")
    last_sync_time = parse_datetime(last_sync_str) if last_sync_str else None

    # 增量查询
    queryset = source_model.objects.using("default").all()
    if last_sync_time:
        queryset = queryset.filter(last_modified__gt=last_sync_time)

    total = queryset.count()
    print(f"[{table_name}] 待同步 {total} 条数据")

    last_updated = None
    for start in range(0, total, batch_size):
        batch = queryset.order_by("last_modified")[start:start+batch_size]

        objs = []
        for src in batch:
            mapped_data = {
                field_mapping[src_field]: getattr(src, src_field)
                for src_field in field_mapping.keys()
            }
            objs.append(target_model(**mapped_data))
            last_updated = getattr(src, "last_modified", None)

        with transaction.atomic(using="wms"):
            target_model.objects.using("wms").bulk_create(
                objs, batch_size=batch_size, ignore_conflicts=True
            )

    # 更新 Redis 中的 last_sync_time
    if last_updated:
        redis_client.set(f"sync:{table_name}:last_sync", last_updated.isoformat())

    return total

📌 4. Celery 任务

myapp/tasks.py

python 复制代码
from celery import shared_task
from myapp.sync_config import SYNC_CONFIG
from myapp.services.sync_service import sync_table
from myapp.models import TaskLog


@shared_task
def sync_all_tables_task():
    for table_name, config in SYNC_CONFIG.items():
        try:
            total = sync_table(table_name, config)
            TaskLog.objects.using("wms").create(
                task_name=f"sync_{table_name}",
                status="success",
                message=f"同步 {total} 条数据"
            )
        except Exception as e:
            TaskLog.objects.using("wms").create(
                task_name=f"sync_{table_name}",
                status="failure",
                message=str(e)
            )
            raise

📌 5. Celery 定时配置

celery.py

python 复制代码
from celery.schedules import crontab

app.conf.beat_schedule = {
    "sync-all-tables-every-5-min": {
        "task": "myapp.tasks.sync_all_tables_task",
        "schedule": crontab(minute="*/5"),  # 每 5 分钟同步一次
    },
}

📌 6. 效果

  • 配置化sync_config.py 里定义任意表的同步规则(源表、目标表、字段映射)。
  • 增量同步 :基于 last_modified,只同步有变动的数据。
  • 批量处理bulk_create 分批写入。
  • Redis 记录 :每个表的 last_sync_time 都存在 Redis,不污染数据库。
  • 后台可查 :执行结果记录在 TaskLog,可在 Django Admin 查看。

⚡ 这个框架可以扩展成 通用数据同步平台

要不要我帮你加上 支持删除同步(比如 SQL Server 有数据删除,MySQL 也要同步删除),这样就是"完全镜像同步"?

相关推荐
_bong3 小时前
python的高阶函数
开发语言·python
麦兜*3 小时前
Spring Boot 项目 Docker 化:从零到一的完整实战指南
数据库·spring boot·redis·后端·spring·缓存·docker
zl9798993 小时前
MySQL-数据库日志
数据库·mysql·database
七夜zippoe3 小时前
微服务配置中心高可用设计:从踩坑到落地的实战指南(一)
java·数据库·微服务
HyperAI超神经3 小时前
【TVM 教程】设置 RPC 系统
开发语言·网络·人工智能·python·网络协议·rpc·tvm
重启的码农3 小时前
kv数据库-leveldb (11) 版本集 (VersionSet / Version)
数据库
数智顾问3 小时前
实战:基于 BRPC+Etcd 打造轻量级 RPC 服务——从注册到调用的核心架构与基础实现
数据库
咕白m6254 小时前
使用 Python 删除 Excel 中的指定行、列
python