【愚公系列】2022年12月 数据库-关系数据库同步框架Dotmim.Sync的使用

article/2025/8/26 14:50:11

文章目录

  • 前言
    • 1.移动智能的三种模式
    • 2.混合模式模式的瓶颈
    • 3.数据同步的解决方案
  • 一、关系数据库同步框架Dotmim.Sync的使用
    • 1.包介绍
    • 2.SqlServer到Sqlite同步测试基本使用
    • 3.SqlServer到Sqlite同步测试Web API代理
      • 3.1 服务端设置SqlServer同步服务
      • 3.2 客户端设置SqlLite同步服务
        • 3.2.1 普通客户端
        • 3.2.2 MAUI安卓应用
  • 总结


前言

1.移动智能的三种模式

众所周知,对于移动智能应用可以分为以下三种模式:

  • 在线模式:在线模式下系统数据一般存储在服务器端的大中型数据库(如 SQL Server、Oracle、MySQL 等),移动应用依赖于稳定可靠的网络连接。
  • 纯离线模式:纯离线模式下系统数据一般存储在移动终端的轻量级数据库(如 SQLite等),移动应用不需要网络连接。
  • “在线+离线”混合模式:“在线+离线”混合模式则比较复杂,通常情况下系统数据存储在服务器端,移动终端暂存部分数据,因而形成了分布式异构数据库。

2.混合模式模式的瓶颈

在混合模式模式下当移动终端或服务器端执行数据更新操作后,为了保证数据的完整性和一致性,需要进行双向的数据同步。然而,由于移动网络本身具有复杂性、动态性、弱连接性以及通信延迟与带宽相对有限等特性,因而移动应用的数据同步技术备受考验。

3.数据同步的解决方案

DotMim.Sync(DMS)是用于同步关系数据库的简单框架,在.Net Standard 2.0之上开发,可在Xamarin,MAUI,.NET Core 3.1,.NET 6和7等中使用。

Dotmim.Sync框架包含针对多种不同主流关系数据库的子项目解决方案,每个子项目均发布为NuGet程序包,便于开发人员基于.NET平台在项目中添加、移除与更新引用。Nuget 上一共发布了8个Nuget包:

在这里插入图片描述

DotMim.Sync 的github网址:https://github.com/Mimetis/Dotmim.Sync
在这里插入图片描述

DotMim.Sync 的文档网址:https://dotmimsync.readthedocs.io/
在这里插入图片描述

一、关系数据库同步框架Dotmim.Sync的使用

1.包介绍

Dotmim.Sync.Core是核心的NuGet程序包,主要执行数据同步的核心逻辑。

以下是基于 .NET平台在服务器端与客户端程序中分别引用相应的NuGet程序包,进而完成服务器端与客户端数据库数据的同步:

  • Dotmim.Sync.SqlServer:SQL Server数据库同步包
  • Dotmim.Sync.Sqlite:SQLite数据库同步包
  • Dotmim.Sync.MySql:MySQL数据库同步包
  • Dotmim.Sync.MariaDB:MariaDB数据库同步包
  • Dotmim.Sync.Web.Server 与 Dotmim.Sync.Web.Client NuGet:HTTP协议通过Web服务器完成服务器端与客户端数据库的同步操作

在这里插入图片描述

2.SqlServer到Sqlite同步测试基本使用

以.NET 7为例同步代码如下:

using Dotmim.Sync;
using Dotmim.Sync.Sqlite;
using Dotmim.Sync.SqlServer;SqlSyncProvider serverProvider = new SqlSyncProvider(@"Data Source=.;Initial Catalog=Dotmim;Integrated Security=true;User ID=sa;Password=1;");// Sqlite客户端提供程序充当“客户端”
SqliteSyncProvider clientProvider = new SqliteSyncProvider("Dotmim.db");//同步过程中涉及的表
//var setup = new SyncSetup("ProductCategory", "ProductDescription", "ProductModel",
// "Product", "ProductModelProductDescription", "Address", "Customer",
// "CustomerAddress", "SalesOrderHeader", "SalesOrderDetail");var setup = new SyncSetup("ProductCategory");
// 同步代理
SyncAgent agent = new SyncAgent(clientProvider, serverProvider);do
{var result = await agent.SynchronizeAsync(setup);Console.WriteLine(result);} while (Console.ReadKey().Key != ConsoleKey.Escape);

启动程序
在这里插入图片描述
尝试更新客户端或服务器数据库中的一行,然后再次按enter键

INSERT [dbo].[ProductCategory] VALUES(1,'sqlite-sync')

在这里插入图片描述
其他数据库类似就不做多介绍

3.SqlServer到Sqlite同步测试Web API代理

以下是web代理同步的整体框架图:
在这里插入图片描述

3.1 服务端设置SqlServer同步服务

创建 ASP.NET 应用程序后,我们将添加特定的 Web 服务器包和服务器提供程序:

  • Dotmim.Sync.Web.Server:这个包将允许我们通过.Net核心Web API公开我们需要的一切
  • Dotmim.Sync.SqlServer.ChangeTracking:此包将允许我们与SQL Server数据库进行通信。

在这里插入图片描述
在Program.cs添加如下代码

builder.Services.AddDistributedMemoryCache();
builder.Services.AddSession(options => options.IdleTimeout = TimeSpan.FromMinutes(30));var connectionString = builder.Configuration.GetSection("ConnectionStrings")["SqlConnection"];//------------------------------------------第一种方式-------------------------------------
var options = new SyncOptions { };
// [Required] 同步过程中涉及的表
var tables = new string[] {"ProductCategory" };// [Required]: 添加充当服务器中心的SqlSyncProvider.
builder.Services.AddSyncServer<SqlSyncChangeTrackingProvider>(connectionString, tables, options);//------------------------------------------第二种方式-------------------------------------
//var setup = new SyncSetup("ProductCategory");
//builder.Services.AddSyncServer<SqlSyncProvider>(connectionString, setup);//---------------------------------------多域配置------------------------------------------
//builder.Services.AddSyncServer<SqlSyncChangeTrackingProvider>(connectionString,
//            "prod", tables1, options);app.UseSession();

在这里插入图片描述
创建新控制器SyncController,单域使用

[ApiController]
[Route("api/[controller]")]
public class SyncController : ControllerBase
{private WebServerAgent webServerAgent;private readonly IWebHostEnvironment env;// 创建数据同步控制器,采用依赖注入的方式注入服务器端Web 代理提供程序:public SyncController(WebServerAgent webServerAgent, IWebHostEnvironment env){this.webServerAgent = webServerAgent;this.env = env;}/// <summary>/// 在控制器的 POST 方法中调用 HandleRequestAsync 方法,执行异步请求,完成数据同步功能:/// </summary>/// <returns></returns>[HttpPost]public Task Post()=> webServerAgent.HandleRequestAsync(this.HttpContext);/// <summary>/// 此GET处理程序是可选的。它允许您查看服务器上托管的配置/// </summary>[HttpGet]public async Task Get(){if (env.IsDevelopment()){await this.HttpContext.WriteHelloAsync(webServerAgent);}else{var stringBuilder = new StringBuilder();stringBuilder.AppendLine("<!doctype html>");stringBuilder.AppendLine("<html>");stringBuilder.AppendLine("<title>Web Server properties</title>");stringBuilder.AppendLine("<body>");stringBuilder.AppendLine(" PRODUCTION MODE. HIDDEN INFO ");stringBuilder.AppendLine("</body>");await this.HttpContext.Response.WriteAsync(stringBuilder.ToString());}}
}

创建新控制器SyncController,多域使用

[ApiController]
[Route("api/[controller]")]
public class SyncController : ControllerBase
{private IEnumerable<WebServerAgent> webserverAgents;private readonly IWebHostEnvironment env;// Injected thanks to Dependency Injectionpublic SyncController(IEnumerable<WebServerAgent> webServerAgents,IWebHostEnvironment env){this.webServerAgents = webServerAgents;this.env = env;}/// <summary>/// This POST handler is mandatory to handle all the sync process/// </summary>/// <returns></returns>[HttpPost]public Task Post(){var scopeName = HttpContext.GetScopeName();var webserverAgent = webserverAgents.FirstOrDefault(c => c.ScopeName == scopeName);await webserverAgent.HandleRequestAsync(HttpContext).ConfigureAwait(false);}/// <summary>/// This GET handler is optional./// It allows you to see the configuration hosted on the server/// </summary>[HttpGet]public async Task Get(){if (env.IsDevelopment()){await this.HttpContext.WriteHelloAsync(this.webserverAgents);}else{var stringBuilder = new StringBuilder();stringBuilder.AppendLine("<!doctype html>");stringBuilder.AppendLine("<html>");stringBuilder.AppendLine("<title>Web Server properties</title>");stringBuilder.AppendLine("<body>");stringBuilder.AppendLine(" PRODUCTION MODE. HIDDEN INFO ");stringBuilder.AppendLine("</body>");await this.HttpContext.Response.WriteAsync(stringBuilder.ToString());}}}

3.2 客户端设置SqlLite同步服务

3.2.1 普通客户端

var serverOrchestrator = new WebRemoteOrchestrator("https://localhost:44342/api/sync");// Second provider is using plain old Sql Server provider,
// relying on triggers and tracking tables to create the sync environment
var clientProvider = new SqlSyncProvider(clientConnectionString);// Creating an agent that will handle all the process
var agent = new SyncAgent(clientProvider, serverOrchestrator);do
{// Launch the sync processvar s1 = await agent.SynchronizeAsync();// Write resultsConsole.WriteLine(s1);} while (Console.ReadKey().Key != ConsoleKey.Escape);Console.WriteLine("End");

现在我们可以启动两个应用程序,一端是 Web Api,另一端是控制台应用程序。 只需按 输入 并通过 http 获取同步结果。
在这里插入图片描述

3.2.2 MAUI安卓应用

1、在项目的AndroidManifest.xml文件中添加网络访问、读写外部存储等权限。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"><application android:networkSecurityConfig="@xml/network_security_config" android:allowBackup="true" android:icon="@mipmap/appicon" android:roundIcon="@mipmap/appicon_round" android:supportsRtl="true"></application><uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" /><uses-permission android:name="android.permission.INTERNET" />
</manifest>

在这里插入图片描述
2、由于Google 从Android P开始已经明确规定禁止http协议额,但是我们的接口都是http协议,从Nougat(Android 7)一个名为“Network Security Configuration”的新安全功能也随之而来。网络安全性配置特性让应用可以在一个安全的声明性配置文件中自定义其网络安全设置,而无需修改应用代码。

10.10.10.10为连接到webapi的地址

<?xml version="1.0" encoding="utf-8"?><network-security-config> <domain-config cleartextTrafficPermitted="false"> <domain includeSubdomains="true">10.10.10.10</domain> </domain-config>
</network-security-config>

3、在数据同步事件中,开启子线程,在子线程中执行数据同步操作:

handler.AutomaticDecompression = DecompressionMethods.Gzip;this.httpClient = new HttpClient(handler);
// Check if we are trying to reach a IIs Express
//IIs Express does not allow any request other than localhost
// So far,hacking the Host-Content header to mimic localhost call
if(DeviceInfo.Platform == DevicePlatform.Android && syncApiUri.Host == "10.10.10.10")this.httpClient.DefaultRequestHeaders.Host = $"localhost:{syncApiUri.Port}";
this.httpclient.DefaultRequestHeaders.AcceptEncoding.Add(new StringWithQualityHeaderValue("gzip"));
this.webProxyProvider = new WebRemote0rchestrator(this.settings.SyncApiUrl, client: this.httpClient);
this.sqliteSyncProvider =new SqliteSyncProvider(this.settings.DataSource);
var clientOptions = new SyncOptions { BatchSize = settings.BatchSize, BatchDirectory = settings.BatchDirectory }
this.syncAgent = new SyncAgent(sqliteSyncProvider, webProxyProvider, clientoptions);
private async Task ExecuteSyncCommand(SyncType syncType){IsBusy = true;var progress = new Progress<ProgressArgs>(args =>{MainThread.BeginInvokeOnMainThread(() =>this.SyncProgress = args.ProgressPercentage;this.SyncProgressionText = args.Message;});});var r = await this.syncAgent.SynchronizeAsync(syncType, progress);MainThread.BeginInvokeOnMainThread(() => this.SyncProgressionText = r.ToString());
}

总结

执行数据同步的常规过程,由客户端发起数据同步 POST 请求,服务器端.NET Core Web API尝试执行数据同步任务。其次,当检测到数据冲突时,服务器端检测预先设置的 ConflictResolutionPolicy 属性值,如果其值为 Serverwins,则服务器端获胜,将服务器端的变化数据强制应用到客户端的数据库中,反之则客户端获胜,将客户端的变化数据强制应用到服务器端的数据库中。

  • 数据同步方向在 Dotmim.Sync 框架中,提供了用于表征数据同步方向的枚举 SyncDirection。该枚举包含 3 个值:Bidirectional(默认值)、DownloadOnly和Upload⁃Only,分别对应“双向同步”、“仅下载同步”与“仅上传同步”3 种方向,可以具体为每个数据表SetupTable分别设定同步方向。
  • 通常情况下冲突问题解决Dotmim.Sync 框架采用 SyncOption 对象的配置策略属性ConflictResolutionPolicy解决数据冲突问题。ConflictResolutionPolicy的可选项如下:
    • ConflictResolutionPolicy.Serverwins, 默认选项,表征服务端为所有冲突的获胜方。
    • ConflictResolutionPolicy.Clientwins 表征客户端为所有冲突的获胜方

http://chatgpt.dhexx.cn/article/2vUwU9uV.shtml

相关文章

django mysql数据同步_[django自动同步数据库]Django数据库同步操作技巧详解

同步数据库&#xff1a; 使用上述两条命令同步数据库 1.认识migrations目录&#xff1a; migrations目录作用&#xff1a;用来存放通过makemigrations命令生成的数据库脚本&#xff0c;里面的生成的脚本不要轻易修改。 要正常的使用数据库同步的功能&#xff0c;app目录下必须要…

SQLSERVER数据库同步

SQLSERVER数据库数据同步 1、实现方法2、实现发布3、实现订阅 1、实现方法 使用的是SQL自带的发布与订阅功能&#xff0c;SQL Server版本是2008&#xff0c;一台发布&#xff0c;一台订阅&#xff0c;实现数据库的数据同步。 2、实现发布 打开复制&#xff0c;右击本地发布&…

MySQL第九讲 MySQL集群主从搭建指定数据库同步数据

1、全库同步与部分同步 之前提到&#xff0c;我们目前配置的主从同步是针对全库配置的&#xff0c;而实际环境中&#xff0c;一般并 不需要针对全库做备份&#xff0c;而只需要对一些特别重要的库或者表来进行同步。那如何 针对库和表做同步配置呢&#xff1f; 首先在Master端…

Python数据库同步神器(一键同步)

1.背景&#xff1a; 最近公司项目的用户中心模块经常出现线上问题&#xff0c;测试人员需要将线上真实数据导入到测试环境中去复现Bug。公司有3套测试环境&#xff0c;来回切换并校验数据比较麻烦&#xff0c;于是就有了如下的数据库同步神器。 2.界面&#xff1a; 3.源代码&…

分布式数据库同步

分布式部署时数据库之间的数据同步 数据的同步原理就是同步binlog日志到需要复制的其他的数据库上&#xff0c;其他数据库根据binlog日志里面的ddl和dml语句,执行该语句同步到当前数据库&#xff0c;就能保证多个数据库的数据的一致性。 Binlog日志主要是的数据库执行的ddl、…

异构数据库同步方案

目录 1 概述 2 原理 3 参数 1 概述 为减轻生产库负载&#xff0c;避免在其上直接运行分析应用拖垮系统&#xff0c;需要将生产系统产生的业务数据实时同步到大数据分析平台。 凭借异构&#xff08;主从库不同类型、主从对象不同属主模式&#xff09;数据处理能力&#xff…

IDEA 之because it is included into a circular dependency循环依赖的解决办法

问题场景&#xff1a; 今天启动项目的时候突然遇到这个错误导致无法启动 Information:2019/8/26 11:34 - Compilation completed with 1 error and 0 warnings in 6 s 52 ms Error:Cannot build artifact aws_multi_branch_1.0.0:war exploded because it is included into a…

Maven dependencyManagement 详解

dependencyManagement&#xff08;以下简称&#xff1a;《依赖管理器》&#xff09; 《依赖管理器》简介 Maven中的《依赖管理器》元素提供了一种管理依赖版本号的方式。在《依赖管理器》元素中声明所依赖的jar包的版本号等信息&#xff0c;那么所有子项目再次引入此依赖jar包…

Maven之dependencyManagement

1. 父项目的dependencyManagement 最开始&#xff0c;知道dependencyManagement是管理jar包版本的&#xff0c;如果在父项目中的该节点下声明了包的版本&#xff0c;子项目中在Dependencies中引用该包时就不需要声明版本了&#xff0c;这样保证多个子项目能够使用相同的包版本…

dependency-track 初始化源码解析

因项目的关键因素&#xff0c;需查看dependency-check源码流程。个人学习用。自己读代码可以根据web.xml的几个listener来debug。 1、org.dependencytrack.RequirementsVerifier 校验java版本&#xff0c;内存等运行时环境。 2、org.dependencytrack.upgrade.UpgradeInitiali…

Maven中的dependencyManagement 详解

Maven中的dependencyManagement 详解 大家好&#xff0c;我是酷酷的韩金群~ 1.作用: 在Maven中dependencyManagement的作用其实相当于一个对所依赖jar包进行版本管理的管理器。 2.pom.xml文件中&#xff0c;jar的版本判断的两种途径: (1)如果dependencies里的dependency自己…

dependency walker工具简介及使用

dependency walker工具 简介使用 简介 官方概述&#xff1a; Dependency Walker is a free utility that scans any 32-bit or 64-bit Windows module (exe, dll, ocx, sys, etc.) and builds a hierarchical tree diagram of all dependent modules. For each module found, …

pytest.mark.dependency用例依赖

这是一个pytest第三方插件&#xff0c;主要解决用例之间的依赖关系。如果依赖的上下文失败后续的用例会被标识为跳过执行&#xff0c;相当于执行了pytest.mark.skip。 1.安装 安装命令如下&#xff1a; pip install pytest-dependency执行上述命令后&#xff0c;再执行pip i…

dependencyManagement使用简介

dependencyManagement使用简介 Maven中的dependencyManagement元素提供了一种管理依赖版本号的方式。在dependencyManagement元素中声明所依赖的jar包的版本号等信息&#xff0c;那么所有子项目再次引入此依赖jar包时则无需显式的列出版本号。Maven会沿着父子层级向上寻找拥有…

Dependency-check

文章目录 前言工具简介工具原理原理检测过程NVDCVSS 工具安装工具地址环境依赖工具安装Jenkins PluginCommand LineOn *nixOn WindowsOn Mac &#xff08;rec) Maven PluginAnt Task 使用示例命令行方式(Mac)插件方式 报告解读CSV格式报告HTML格式报告 工具对比参考 前言 公司…

maven中dependency的属性(依赖)配置

groupId&#xff0c;artfactId&#xff0c;version&#xff0c;type&#xff0c;classifier&#xff0c;scope&#xff0c;systemPath&#xff0c;exclusions&#xff0c;optional 是 maven的9种依赖属性&#xff0c; 其中groupId&#xff0c;artfactId&#xff0c;version是三…

Maven -- dependency详解

PS&#xff1a;部分来源官网文档&#xff0c;翻译不到位&#xff0c;请移步官网 一 &#xff1a;type&#xff1a;个人理解&#xff1a;依赖<dependency>通过其子标签 定位了某个特定的唯一构件&#xff0c;所以type--依赖类型&#xff0c;更准确的说应该是依赖的构件…

MySQL中“full outer join“的实现

一: 先创建两个表 二: 使用【left join】 union 【right join】 select t1.dim_a, t1.qty qty_a, t2.dim_a dim_b, t2.qty qty_b from ta t1 left join tb t2 on t1.dim_at2.dim_a union select t1.dim_a, t1.qty qty_a, t2.dim_a dim_b, t2.qty qty_b from ta t1 right join…

left join 和 left outer join 的区别

通俗的讲&#xff1a; A left join B 的连接的记录数与A表的记录数同 A right join B 的连接的记录数与B表的记录数同 A left join B 等价B right join A table A: Field_K, Field_A 1 a 3 b 4 c table B: …

SQL中inner join、outer join和cross join的区别

缺省情况下是inner join,开发中使用的left join和right join属于outer join,另外outer join还包括full join.下面我通过图标让大家认识它们的区别。 现有两张表&#xff0c;Table A 是左边的表。Table B 是右边的表。其各有四条记录&#xff0c;其中有两条记录name是相同的&…