CORE FEATURES

核心功能一览

项目管理、自动检测、SQL 方言适配、断点续传 —— 一个 jar 包全包了。含 13 张后台界面截图

项目管理

配置源库/目标库,多项目并行互不干扰。每个项目独立启动/暂停,列表分页展示(默认 20 条/页,可跳页)。

连接测试

保存前即可验证连通性。选择数据库类型后自动生成 JDBC URL,非内置驱动填写 jar 路径即可动态加载。

对象选择

表 / 视图 / 存储过程分组勾选,支持搜索与批量操作。每张表的增量检测策略直接标注,一目了然。

同步内容

表结构、表数据、索引、视图、存储过程与函数。目标库不存在时按目标方言自动创建,DDL 变更自动传播。

SQL 方言适配

类型映射、函数名转换、标识符引号、分页语法、存储过程包装。异构库之间的桥梁,每种方言有专门的实现。

实时同步

轮询检测(默认 2 秒),也可用 Cron 表达式精确编排。进程重启后从上次游标继续,停机期间的变更会被补齐。

故障恢复

三层锁机制(Quartz + JVM + 数据库行锁)确保跨重启安全。崩溃实例的锁可被接管,不会永久阻塞项目。

变更记录

每次变更的对象名、类型、影响行数、耗时与完整错误详情。与项目列表同一套分页,每一次同步都可追溯,问题排查不靠猜。

安全与权限

密码 BCrypt 哈希存储,连接密码 AES-256 加密。管理员/访客两级权限,访客仅只读。支持修改密码。

SCREENSHOTS

效果截图

从登录到看板,从配置到日志,每个环节都有清晰的界面

登录:先过一道口令

用户名 + 密码,右上角可随时切换主题与语言。默认口令没改之前,登录后每个页面顶部都会挂一条红色警告。

  • 初始账号 admin 和 view
  • 密码 BCrypt 单向哈希存储
  • 管理员/访客两级权限体系
登录页面截图

看板:全局同步态势一屏掌握

项目数、连接数、同步表数、24 小时变更量与最近活动流。所有关键指标一目了然。

  • 全局数据概览,表头与数值逐列对齐
  • 项目概览 / 最近活动各只列前 5 条,底部入口跳转完整列表
  • 快速导航到各模块
看板页面截图

暗色主题:整套配色一起换

右上角一键切换。看板、卡片、表格、图标都跟着走,不是只把背景刷黑、留下一片刺眼的浅色控件。

  • 仅覆盖 CSS 变量,组件无需第二套深色规则
  • 未手动选择时跟随系统偏好
  • 监听系统主题变化实时跟随
  • 切换按钮的月亮 / 太阳图标固定金黄色,昼夜两种底色下都醒目
暗色主题看板截图

英文界面:右上角一键切换

点导航栏的「中 / EN」按钮即可在中英文之间切换,菜单、表单、状态与错误提示整套文案一起换,选择记在浏览器里。首次访问未手动选择时,默认语言按浏览器时区智能推断。

  • 菜单 / 表单 / 状态 / 错误提示整套文案一起换
  • 优先级:语言 Cookie › 浏览器时区 › Accept-Language
  • 境外华人用户的时区往往比浏览器语言更准
Jync 英文界面截图

数据库连接:源 / 目标分栏,保存前先测通

连接按用途拆成「源数据库连接」「目标数据库连接」两张表,各自独立分页;选择数据库类型后自动生成 JDBC URL,可预览、可测试。十四种常用驱动随包内置(含 OceanBase、瀚高、海量、崖山等信创库,TiDB 复用 MySQL 驱动),GBase、神通及自定义驱动填写 jar 路径即可动态加载。

  • 新建连接必须选择用途:源(数据读出)/ 目标(数据写入)
  • 独立 URLClassLoader 加载外部 jar,不污染应用类加载器
  • 密码加密后入库,测试连接通过再保存
数据库连接页面截图

新增连接:先定用途,类型选好 URL 自己拼

必选「源数据库连接」或「目标数据库连接」用途;再填主机、端口、库名,默认端口随数据库类型自动联动,JDBC URL 当场生成,不用记各家数据库的连接串格式。

  • 支持预设类型和自定义数据库
  • 驱动类名自动填充,默认端口随类型联动
  • GBase / 神通 / 自定义类型运行时动态加载厂商驱动 jar
新增数据库连接截图

项目列表:多任务并行,启停自如

每个项目一组「源库 → 目标库」,独立启动/暂停,状态与最近同步时间一目了然。列表分页展示,页码多时也不会铺满整排。

  • 多项目并行互不干扰,随时启动/暂停
  • 分页:默认 20 条/页,可选 15 / 20 / 30 / 50 / 100 并跳页
  • 页数多时中间以省略号收起,点省略号就地多展开 5 页
项目列表页面截图

项目详情:逐表勾选与游标策略可视化

表 / 视图 / 存储过程分组勾选,支持搜索与批量操作;每张表的增量检测策略直接标注。

  • TIMESTAMP 策略:可检测更新
  • IDENTITY / NONE 策略显著提示 —— 意味着更新可能同步不到
  • FULL_COMPARE 策略:全表比对
  • 「立即同步」运行中再点不会丢:本轮结束后自动补跑一轮,连点多次只补一轮
  • 只读账号下写入操作不可见
项目详情页面截图

新建项目:源与目标各选一条连接

一个项目就是一条「源库 → 目标库」链路。新建时源、目标下拉各自只列出对应用途的连接,不会把只该写入的库错选成源。

  • 源 / 目标下拉按连接用途过滤,选不错方向
  • 建好后进项目详情勾选要同步的表 / 视图 / 存储过程
  • 权限按 HTTP 方法判定:新建等写操作一律要求管理员,访客界面上看不到入口
新建项目弹窗截图

变更日志:每一次变更都可追溯

对象名、变更类型、影响行数、耗时与完整错误详情。问题排查不靠猜,全在日志里。

  • 每次同步的明细记录,错误详情完整展示
  • 支持按时间范围筛选,与项目列表同一套分页
  • 第 2 页起自动刷新禁用 —— 日志按时间倒序,刷新会让正在读的行一直换位置
变更日志页面截图

AI 配置:多供应商共存,同一时刻只启用一个

存储过程里的不兼容语法,靠文本替换只能走到一定程度。AI 配置 提供另一条路:让模型起草一份候选,由你审阅后落库。

  • 支持 OpenAI 兼容 与 Anthropic 两种协议
  • 保存前先探测端点 —— 发一次真实请求,而非 TCP 探活
  • 密钥与数据库密码同样 AES-256 加密存储
  • AI 只产出候选,永不直接参与同步
  • sync.ai.enabled=false 可彻底下线该功能
AI 配置页面截图

新增供应商:保存前先探测端点

新增 AI 供应商时,保存前会发一次真实请求探测端点,而非 TCP 探活 —— 密钥错误、模型名写错、Base URL 差一段路径这三类问题只有真发请求才暴露得出来。

  • 密钥与数据库密码同样 AES-256 加密存储
  • 探测不通过无法保存,配错当场知道
  • 多供应商共存,同一时刻只启用一个
新增 AI 供应商页面截图

系统信息:运行参数与版本一目了然

原「设置」菜单改名为「系统信息」:实例标识、Java 版本、已调度项目数、同步默认参数与并发恢复机制集中只读展示;版本信息卡片显示当前版本、GitHub 最新版本和本版更新内容。更新检查在后台进行,不拖慢页面,纯内网也能看当前版本和更新内容。

  • 运行参数集中只读展示
  • 版本卡片:当前版本 / GitHub 最新版本 / 本版更新内容
  • 可用 --app.update-check.enabled=false 关闭更新检查
系统信息页面截图
DESIGN

并发与一致性设计

增量窗口闭区间 · 先提交后推进 · 幂等写入 · 三层锁 · 安全回退

增量窗口闭区间

先读取 MAX(游标列) 作为水位线,再查询 游标列 > 上次游标 AND 游标列 <= 本次水位线。同步期间新写入的数据自然落在窗口之外,下个周期被捕获。

先提交后推进

先提交目标库数据,再持久化游标。若两者之间崩溃,下次重放同一窗口,不会丢数据。代价是同一行可能被投递两次,由幂等写入消化。

幂等写入

每一行通过基于主键的 upsert 写入,重复执行收敛到同一状态。每种数据库适配各自的 upsert 语法:INSERT ... ON DUPLICATE KEY UPDATE、MERGE INTO、UPDATE-then-INSERT 等。

三层锁机制

Quartz 调度锁 + JVM ReentrantLock + 数据库行锁(带租约)。崩溃实例的锁可被接管,不会永久阻塞项目。启动时主动释放本实例上次遗留的锁。

CURSOR STRATEGY

增量检测策略

一行数据能否被同步,只取决于它的游标列值有没有涨到上次记录之上

增量同步只有一条查询
SELECT * FROM 表 WHERE 游标列 > 上次游标 AND 游标列 <= 本次水位 ORDER BY 游标列
策略触发条件检测新增检测更新
TIMESTAMP 存在符合最后修改时间命名约定的时间戳类型列 ✅ ✅ 前提是该列真被更新
IDENTITY 存在符合创建时间命名约定的列,或单列数字主键 ✅ ❌ 永远检测不到
FULL_COMPARE 无可用游标列,且行数 ≤ full-compare-max-rows(默认 20000) ✅ ✅ 每周期全表 upsert
NONE 无可用游标列且表过大 ❌ ❌ 仅首次全量加载
⚠️ 游标列必须是「改一行它就会变大」的列。 用单列数字主键(id)或创建时间(create_time)做游标,UPDATE 不会改变它们的值, 那一行的游标值原地不动 —— 修改永远同步不到,只有新增能过去。 这不是缺陷,而是「用普通查询做增量、不碰源库 binlog 也不建触发器」这个前提的必然代价。

✅ 判为 TIMESTAMP 的列名(16 个)

UPDATE_TIME UPDATED_AT UPDATETIME UPDATED_TIME LAST_MODIFIED LASTMODIFIED LAST_UPDATE LAST_UPDATED MODIFY_TIME MODIFIED_AT MODIFIED_TIME GMT_MODIFIED ROW_VERSION ROWVERSION SYS_UPDATE_TIME DATA_CHANGE_TIME

⚠️ 判为 IDENTITY 的列名(7 个)

CREATE_TIME CREATED_AT CREATETIME CREATED_TIME GMT_CREATE INSERT_TIME ADD_TIME

创建时间不随修改而变,因此这些列只能检测新增。

匹配规则:大小写不敏感,- 视作 _,按包含匹配。
并且列类型必须确实是时间类型 —— 名为 update_time 的 VARCHAR 不会被当作游标,因为字符串比较的顺序不可靠。

FRONTEND

前端设计

手写 CSS + 设计令牌,无框架、无构建步骤,内网离线可用

主题切换

主题写在 <html data-theme>,只覆盖 CSS 变量,因此组件无需第二套深色规则。未手动选择时跟随系统 prefers-color-scheme 并实时响应变化。<head> 内联脚本在首屏渲染前应用主题,避免深色用户看到一帧白底闪烁。

时区优先的语言判定

优先级:语言 Cookie › 浏览器时区 › Accept-Language › 简体中文。 为什么时区优先?境外华人用户的浏览器语言常常是英文,但人在国内时区 —— 时区是「想看哪种语言」更准的信号。

离线/内网可用

所有前端资源均在仓库内,运行时不发起任何外部请求:手写样式、原生 JS、本地托管的图标字体、内联渐变 SVG。字体使用系统字体栈,不引入 webfont。静态资源总体积约 440KB。

验证方式:抓取任意页面 HTML,其中 src/href 引用的外部 http(s) 地址数量为 0。