C# WPF 折线图制作(可以连接数据库)

一、项目核心信息

1. 技术栈

  • 框架:WPF(Windows Presentation Foundation)

  • 数据存储:SQLite + SqlSugar(ORM 框架)

  • 图表展示:LiveCharts.Wpf(开源图表库)

  • 功能定位:可视化展示年度销量数据,支持动态追加月度数据并持久化到数据库。

2. 核心文件说明

文件 / 类 作用
SalesRecord.cs 销量数据实体类,映射 SQLite 中的 SalesRecord
DbHelper.cs 数据库操作工具类,封装 SqlSugar 连接、建表、数据增查逻辑
UCLineChart.xaml 折线图用户控件布局,包含图表容器和追加数据按钮
UCLineChart.xaml.cs 图表逻辑处理,包括数据初始化、图表渲染、动态追加数据等核心逻辑

3.项目结构梳理

复制代码
LineChart2/
├─ DbHelper.cs          // Sugar ORM数据库操作封
├─ SalesRecord.cs       // 销量数据实体类
├─ UCLineChart.xaml        // 折线图用户控件XAML
├─ UCLineChart.xaml.cs     // 折线图逻辑(整合数据库)
├─ MainWindow.xaml         // 主窗口
└─ SalesData.db            // SQLite数据库文件(运行后生成)

二、核心代码解析与使用示例

1. 数据库层使用

(1)SalesRecord 实体(数据映射)
复制代码
// 核心特性说明
[SugarTable("SalesRecord")] // 指定数据库表名
public class SalesRecord
{
    [SugarColumn(IsPrimaryKey = true, IsIdentity = true)] // 主键+自增
    public int Id { get; set; }
​
    [SugarColumn(ColumnName = "Year")] // 映射数据库字段名(可选,默认属性名)
    public int SalesYear { get; set; } // 年份
​
    public int Month { get; set; } // 月份(1-12)
    public double SalesValue { get; set; } // 销量值
    public DateTime CreateTime { get; set; } = DateTime.Now; // 数据创建时间
}

使用示例:创建一条 2024 年 6 月的销量数据

复制代码
var newRecord = new SalesRecord
{
    SalesYear = 2024,
    Month = 6,
    SalesValue = 180.5 // 销量值支持小数,图表会自动格式化
};
(2)DbHelper 工具类(数据库操作)

核心功能 1:初始化数据库连接

复制代码
// 静态构造函数自动初始化,无需手动调用
// 数据库文件路径:程序运行目录/SalesData.db
// 关键配置:自动关闭连接、从特性读取主键配置

核心功能 2:数据操作封装(使用示例)

复制代码
// 1. 批量插入数据(初始化默认数据时使用)
var defaultData = new List<SalesRecord>
{
    new SalesRecord { SalesYear = 2024, Month = 1, SalesValue = 120 },
    new SalesRecord { SalesYear = 2024, Month = 2, SalesValue = 150 }
};
DbHelper.BatchInsertSalesData(defaultData.ToArray());
​
// 2. 插入单条数据并返回自增ID
int newId = DbHelper.InsertSalesData(newRecord);
Console.WriteLine($"新增数据ID:{newId}");
​
// 3. 查询指定年份数据
List<SalesRecord> 2024Data = DbHelper.GetSalesDataByYear(2024);
foreach (var item in 2024Data)
{
    Console.WriteLine($"{item.Month}月销量:{item.SalesValue}");
}
​
// 4. 查询所有数据
List<SalesRecord> allData = DbHelper.GetAllSalesData();

2. 图表层使用

(1)XAML 布局(UCLineChart.xaml)
复制代码
<!-- 核心图表控件配置 -->
<lvc:CartesianChart x:Name="chart"
                    Series="{Binding SeriesCollection}" 
                    LegendLocation="Top"
                    Background="White">
    <!-- Y轴:销量(件),格式化显示整数 -->
    <lvc:CartesianChart.AxisY>
        <lvc:Axis Title="销量(件)" 
                  LabelFormatter="{Binding YFormatter}"
                  Foreground="#333333"/>
    </lvc:CartesianChart.AxisY>
    <!-- X轴:月份,绑定标签数组 -->
    <lvc:CartesianChart.AxisX>
        <lvc:Axis Title="月份" 
                  Labels="{Binding Labels}"
                  Foreground="#333333"/>
    </lvc:CartesianChart.AxisX>
</lvc:CartesianChart>
(2)图表逻辑(UCLineChart.xaml.cs)

核心功能 1:初始化图表数据(从数据库加载)

复制代码
private void InitChartDataFromDb()
{
    SeriesCollection = new SeriesCollection();
    var allSalesData = DbHelper.GetAllSalesData();
​
    // 无数据时初始化默认数据
    if (!allSalesData.Any())
    {
        InitDefaultDataAndWriteToDb(); // 写入2023/2024年1-5月默认数据
        allSalesData = DbHelper.GetAllSalesData();
    }
​
    // 按年份分组构建折线
    var groupedData = allSalesData.GroupBy(r => r.SalesYear);
    foreach (var group in groupedData)
    {
        int year = group.Key;
        var values = group.OrderBy(r => r.Month).Select(r => r.SalesValue).ToList();
​
        // 创建折线系列(不同年份区分样式)
        LineSeries series = new LineSeries
        {
            Title = $"{year}年",
            Values = new ChartValues<double>(values),
            LineSmoothness = 0.3, // 折线平滑度
            StrokeThickness = 2, // 线条粗细
            PointGeometrySize = 8 // 数据点大小
        };
​
        // 样式区分:2024年蓝色圆形,2023年红色方形
        series.Stroke = year == 2024 ? Brushes.DodgerBlue : Brushes.OrangeRed;
        series.PointForeground = year == 2024 ? Brushes.DodgerBlue : Brushes.OrangeRed;
        series.PointGeometry = year == 2024 ? DefaultGeometries.Circle : DefaultGeometries.Square;
​
        SeriesCollection.Add(series);
    }
​
    // 构建X轴标签(1-当前最大月份)
    _currentMaxMonth = allSalesData.Max(r => r.Month);
    Labels = Enumerable.Range(1, _currentMaxMonth).Select(m => $"{m}月").ToArray();
}

核心功能 2:动态追加数据(按钮点击事件)

复制代码
private void BtnAddData_Click(object sender, RoutedEventArgs e)
{
    // 1. 月份自增
    _currentMaxMonth++;
    int newMonth = _currentMaxMonth;
​
    // 2. 生成随机销量(100-200)
    double sales2024 = _random.Next(100, 200);
    double sales2023 = _random.Next(100, 200);
​
    // 3. 写入数据库(持久化)
    DbHelper.InsertSalesData(new SalesRecord { SalesYear = 2024, Month = newMonth, SalesValue = sales2024 });
    DbHelper.InsertSalesData(new SalesRecord { SalesYear = 2023, Month = newMonth, SalesValue = sales2023 });
​
    // 4. 更新图表数据点
    SeriesCollection[0].Values.Add(sales2024); // 2024年系列
    SeriesCollection[1].Values.Add(sales2023); // 2023年系列
​
    // 5. 更新X轴标签(修复数组直接扩容的CS0206错误)
    string[] tempLabels = Labels;
    Array.Resize(ref tempLabels, tempLabels.Length + 1);
    tempLabels[tempLabels.Length - 1] = $"{newMonth}月";
    Labels = tempLabels;
​
    // 6. 刷新UI绑定
    chart.AxisX[0].Labels = Labels;
​
    // 7. 更新按钮文本(追加7月→追加8月...)
    (sender as Button).Content = $"追加{newMonth + 1}月数据";
}

3. 完整使用示例(主窗口集成)

步骤 1:在 MainWindow.xaml 中引用控件
复制代码
<Window x:Class="LineChart2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="clr-namespace:LineChart2"
        Title="销量折线图" Height="500" Width="800">
    <Grid>
        <!-- 引用自定义折线图控件 -->
        <local:UCLineChart/>
    </Grid>
</Window>
步骤 2:运行效果
  1. 首次运行:

    • 自动创建 SalesData.db 数据库文件;

    • 写入 2023/2024 年 1-5 月默认数据;

    • 图表显示两条折线(2023 年红色方形点,2024 年蓝色圆形点),X 轴标签为 "1 月 - 5 月"。

  2. 点击 "追加 6 月数据" 按钮:

    • 数据库新增 2023/2024 年 6 月随机销量数据;

    • 图表自动追加 6 月数据点,X 轴标签更新为 "1 月 - 6 月";

    • 按钮文本变为 "追加 7 月数据",重复点击可继续追加后续月份。

三、环境配置与依赖

1. NuGet 包安装

包名 版本(建议) 作用
SqlSugarCore 5.1.4.100 SQLite 数据库 ORM 操作
System.Data.SQLite 1.0.118 SQLite 数据提供程序
LiveCharts.Wpf 0.97.0 WPF 图表展示核心库
LiveCharts 0.97.0 LiveCharts 基础核心库

2. 安装命令(Package Manager Console)

复制代码
Install-Package SqlSugarCore -Version 5.1.4.100
Install-Package System.Data.SQLite -Version 1.0.118
Install-Package LiveCharts.Wpf -Version 0.97.0

四、扩展与定制示例

1. 定制折线样式

修改 InitChartDataFromDbLineSeries 的配置:

复制代码
LineSeries series = new LineSeries
{
    Title = $"{year}年",
    Values = new ChartValues<double>(values),
    LineSmoothness = 0.8, // 更平滑的折线(0-1)
    StrokeThickness = 3, // 加粗线条
    PointGeometrySize = 10, // 放大数据点
    Fill = Brushes.LightBlue // 折线下方填充颜色(2024年)
};
// 自定义颜色(如2025年用绿色三角形)
if (year == 2025)
{
    series.Stroke = Brushes.Green;
    series.PointForeground = Brushes.Green;
    series.PointGeometry = DefaultGeometries.Triangle;
}

2. 扩展多年份数据

InitDefaultDataAndWriteToDb 中添加 2025 年数据:

复制代码
// 2025年1-5月数据
double[] sales2025 = { 110, 140, 160, 170, 190 };
for (int i = 0; i < sales2025.Length; i++)
{
    defaultData.Add(new SalesRecord
    {
        SalesYear = 2025,
        Month = i + 1,
        SalesValue = sales2025[i]
    });
}

3. 限制最大月份(仅展示 12 个月)

修改 BtnAddData_Click 事件:

复制代码
private void BtnAddData_Click(object sender, RoutedEventArgs e)
{
    if (_currentMaxMonth >= 12)
    {
        MessageBox.Show("已追加到12月,无法继续追加!");
        (sender as Button).IsEnabled = false;
        return;
    }
    // 原有追加逻辑...
}

五、常见问题与解决

1. 图表无数据显示

  • 检查数据库文件是否生成(程序运行目录 / SalesData.db);

  • 调试 DbHelper.GetAllSalesData() 是否返回数据;

  • 确认 SeriesCollection 已赋值且 DataContext = this; 执行。

2. 追加数据后 X 轴标签不更新

  • 确保执行 chart.AxisX[0].Labels = Labels; 刷新绑定;

  • 检查 Labels 数组扩容逻辑是否正确(必须通过临时变量中转)。

3. 数据库连接失败

  • 确认 System.Data.SQLite 包安装完整,适配项目平台(x86/x64/AnyCPU);

  • 检查连接字符串格式:Data Source={dbPath}; 为 SQLite 标准格式,路径无特殊字符。

六、运行流程总结

  1. 程序启动 → DbHelper 初始化 SQLite 连接 → 自动创建 SalesRecord 表;

  2. UCLineChart 加载 → 从数据库查询数据 → 无数据则写入默认 1-5 月数据;

  3. 按年份分组渲染折线图 → 显示 1-5 月销量;

  4. 点击追加按钮 → 月份 + 1 → 生成随机销量 → 写入数据库 → 更新图表数据和标签;

  5. 重复点击可追加到 12 月,数据持久化到数据库,重启程序后仍能加载历史数据。

七、完整代码

DbHelper.cs

复制代码
using SqlSugar;
using LineChart2;
using System;
using System.IO;
using System.Linq;
using System.Collections.Generic;
​
namespace LineChart2
{
    public class DbHelper
    {
        // Sugar数据库连接实例(单例)
        public static SqlSugarClient Db { get; private set; }
​
        static DbHelper()
        {
            // 初始化连接
            InitDb();
        }
​
        /// <summary>
        /// 初始化SQLite连接
        /// </summary>
        private static void InitDb()
        {
            // 获取数据库文件路径(项目根目录)
            string dbPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "SalesData.db");
​
            Db = new SqlSugarClient(new ConnectionConfig
            {
                ConnectionString = $"Data Source={dbPath};", // SQLite连接字符串
                DbType = DbType.Sqlite, // 数据库类型
                IsAutoCloseConnection = true, // 自动关闭连接
                InitKeyType = InitKeyType.Attribute // 从特性读取主键/自增配置
            });
​
            // 初始化数据表(不存在则创建)
            Db.CodeFirst.InitTables(typeof(SalesRecord));
​
            // 开启日志(调试用,生产可关闭)
            Db.Aop.OnLogExecuting = (sql, pars) =>
            {
                Console.WriteLine($"SQL:{sql} \r\n参数:{string.Join(",", pars.Select(p => p.ParameterName + "=" + p.Value))}");
            };
        }
​
        #region 销量数据操作封装
        /// <summary>
        /// 批量插入销量数据
        /// </summary>
        public static void BatchInsertSalesData(SalesRecord[] records)
        {
            Db.Insertable(records).ExecuteCommand();
        }
​
        /// <summary>
        /// 插入单条销量数据
        /// </summary>
        public static int InsertSalesData(SalesRecord record)
        {
            return Db.Insertable(record).ExecuteReturnIdentity();
        }
​
        /// <summary>
        /// 根据年份查询销量数据
        /// </summary>
        public static List<SalesRecord> GetSalesDataByYear(int year)
        {
            return Db.Queryable<SalesRecord>()
                     .Where(r => r.SalesYear == year)
                     .OrderBy(r => r.Month)
                     .ToList();
        }
​
        /// <summary>
        /// 查询所有年份的销量数据
        /// </summary>
        public static List<SalesRecord> GetAllSalesData()
        {
            return Db.Queryable<SalesRecord>()
                     .OrderBy(r => r.SalesYear)
                     .ToList();
        }
        #endregion
    }
}
​
​

Model.cs

复制代码
using SqlSugar;
using System;
​
namespace LineChart2
{
    /// <summary>
    /// 销量数据表实体
    /// </summary>
    [SugarTable("SalesRecord")]
    public class SalesRecord
    {
        /// <summary>
        /// 主键(自增)
        /// </summary>
        [SugarColumn(IsPrimaryKey = true, IsIdentity = true)]
        public int Id { get; set; }
​
        /// <summary>
        /// 年份(2023/2024)
        /// </summary>
        [SugarColumn(ColumnName = "Year")]
        public int SalesYear { get; set; }
​
        /// <summary>
        /// 月份(1-12)
        /// </summary>
        public int Month { get; set; }
​
        /// <summary>
        /// 销量数值
        /// </summary>
        public double SalesValue { get; set; }
​
        /// <summary>
        /// 创建时间
        /// </summary>
        public DateTime CreateTime { get; set; } = DateTime.Now;
    }
}
​
​
​

UCLineChart.xaml

复制代码
<UserControl x:Class="LineChart2.UCLineChart"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:local="clr-namespace:LineChart2"
             xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
             mc:Ignorable="d" 
             d:DesignHeight="450" d:DesignWidth="800">
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>
​
        <lvc:CartesianChart x:Name="chart"
                            Series="{Binding SeriesCollection}" 
                            LegendLocation="Top"
                            Background="White">
            <lvc:CartesianChart.AxisY>
                <lvc:Axis Title="销量(件)" 
                          LabelFormatter="{Binding YFormatter}"
                          Foreground="#333333"/>
            </lvc:CartesianChart.AxisY>
            <lvc:CartesianChart.AxisX>
                <lvc:Axis Title="月份" 
                          Labels="{Binding Labels}"
                          Foreground="#333333"/>
            </lvc:CartesianChart.AxisX>
        </lvc:CartesianChart>
​
        <!-- 追加数据按钮 -->
        <Button Grid.Row="1" 
                Content="追加6月数据" 
                Width="120" Height="30"
                Margin="10"
                Click="BtnAddData_Click"/>
    </Grid>
</UserControl>
    
    
    

UCLineChart.xaml.cs

复制代码
using LiveCharts;
using LiveCharts.Defaults;
using LiveCharts.Wpf;
using LineChart2;
using LineChart2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
​
namespace LineChart2
{
    public partial class UCLineChart : UserControl
    {
        public SeriesCollection SeriesCollection { get; set; }
        public string[] Labels { get; set; }
        public Func<double, string> YFormatter { get; set; }
​
        // 模拟销量数据
        private readonly Random _random = new Random();
        // 当前最大月份(用于追加数据)
        private int _currentMaxMonth = 5;
​
        public UCLineChart()
        {
            InitializeComponent();
​
            // 初始化图表数据(优先从数据库读取)
            InitChartDataFromDb();
​
            // Y轴格式化(显示整数)
            YFormatter = value => $"{value:N0}";
​
            DataContext = this;
        }
​
        /// <summary>
        /// 从数据库初始化图表数据
        /// </summary>
        private void InitChartDataFromDb()
        {
            SeriesCollection = new SeriesCollection();
​
            // 1. 查询所有销量数据
            var allSalesData = DbHelper.GetAllSalesData();
​
            // 2. 如果数据库无数据,初始化默认数据并写入数据库
            if (!allSalesData.Any())
            {
                InitDefaultDataAndWriteToDb();
                allSalesData = DbHelper.GetAllSalesData();
            }
​
            // 3. 按年份分组构建折线系列
            var groupedData = allSalesData.GroupBy(r => r.SalesYear);
            foreach (var group in groupedData)
            {
                int year = group.Key;
                var values = group.OrderBy(r => r.Month).Select(r => r.SalesValue).ToList();
​
                // 创建折线系列
                LineSeries series = new LineSeries
                {
                    Title = $"{year}年",
                    Values = new ChartValues<double>(values),
                    LineSmoothness = 0.3,
                    StrokeThickness = 2,
                    PointGeometrySize = 8
                };
​
                // 不同年份设置不同颜色
                series.Stroke = year == 2024 ? Brushes.DodgerBlue : Brushes.OrangeRed;
                series.PointForeground = year == 2024 ? Brushes.DodgerBlue : Brushes.OrangeRed;
                series.PointGeometry = year == 2024 ? DefaultGeometries.Circle : DefaultGeometries.Square;
​
                SeriesCollection.Add(series);
            }
​
            // 4. 构建X轴标签(1-当前最大月份)
            _currentMaxMonth = allSalesData.Max(r => r.Month);
            Labels = Enumerable.Range(1, _currentMaxMonth).Select(m => $"{m}月").ToArray();
        }
​
        /// <summary>
        /// 初始化默认数据并写入数据库
        /// </summary>
        private void InitDefaultDataAndWriteToDb()
        {
            List<SalesRecord> defaultData = new List<SalesRecord>();
​
            // 2024年1-5月数据
            double[] sales2024 = { 120, 150, 110, 180, 160 };
            for (int i = 0; i < sales2024.Length; i++)
            {
                defaultData.Add(new SalesRecord
                {
                    SalesYear = 2024,
                    Month = i + 1,
                    SalesValue = sales2024[i]
                });
            }
​
            // 2023年1-5月数据
            double[] sales2023 = { 100, 130, 140, 150, 130 };
            for (int i = 0; i < sales2023.Length; i++)
            {
                defaultData.Add(new SalesRecord
                {
                    SalesYear = 2023,
                    Month = i + 1,
                    SalesValue = sales2023[i]
                });
            }
​
            // 批量写入数据库
            DbHelper.BatchInsertSalesData(defaultData.ToArray());
        }
​
        // 追加数据按钮点击事件
        private void BtnAddData_Click(object sender, RoutedEventArgs e)
        {
            // 1. 月份+1
            _currentMaxMonth++;
            int newMonth = _currentMaxMonth;
​
            // 2. 生成随机销量(100-200)
            double sales2024 = _random.Next(100, 200);
            double sales2023 = _random.Next(100, 200);
​
            // 3. 写入数据库
            DbHelper.InsertSalesData(new SalesRecord { SalesYear = 2024, Month = newMonth, SalesValue = sales2024 });
            DbHelper.InsertSalesData(new SalesRecord { SalesYear = 2023, Month = newMonth, SalesValue = sales2023 });
​
            // 4. 追加数据点到图表
            SeriesCollection[0].Values.Add(sales2024);
            SeriesCollection[1].Values.Add(sales2023);
​
            // 5. 更新X轴标签(修复CS0206错误)
            // 步骤1:将属性赋值给临时变量
            string[] tempLabels = Labels;
            // 步骤2:对临时变量执行数组扩容
            Array.Resize(ref tempLabels, tempLabels.Length + 1);
            // 步骤3:给扩容后的数组赋值新标签
            tempLabels[tempLabels.Length - 1] = $"{newMonth}月";
            // 步骤4:将临时变量赋值回属性
            Labels = tempLabels;
​
            // 6. 刷新绑定(触发UI更新)
            chart.AxisX[0].Labels = Labels;
​
            // 更新按钮文本(追加7月、8月...)
            (sender as Button).Content = $"追加{newMonth + 1}月数据";
        }
    }
}
​
​
​

MainWindow.xaml

复制代码
<Window x:Class="LineChart2.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:LineChart2"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Grid Margin="10">
            <!-- 自定义折线图用户控件 -->
            <local:UCLineChart x:Name="ucLineChart"
                           HorizontalAlignment="Stretch"
                           VerticalAlignment="Stretch"
                           Background="#F5F5F5"
                           BorderBrush="#E0E0E0"
                           BorderThickness="1"
                           />
​
        </Grid>
    </Grid>
</Window>
​

效果展示:

相关推荐
想摆烂的不会研究的研究生20 分钟前
每日八股——Redis(1)
数据库·经验分享·redis·后端·缓存
唐宋元明清218822 分钟前
.NET 磁盘管理-技术方案选型
windows·c#·存储
码熔burning31 分钟前
MySQL 8.0 新特性爆笑盘点:从青铜到王者的骚操作都在这儿了!(万字详解,建议收藏)
数据库·mysql
故事不长丨37 分钟前
C#正则表达式完全攻略:从基础到实战的全场景应用指南
开发语言·正则表达式·c#·regex
猫头虎38 分钟前
2025最新OpenEuler系统安装MySQL的详细教程
linux·服务器·数据库·sql·mysql·macos·openeuler
哈库纳玛塔塔1 小时前
放弃 MyBatis,拥抱新一代 Java 数据访问库
java·开发语言·数据库·mybatis·orm·dbvisitor
@LetsTGBot搜索引擎机器人2 小时前
2025 Telegram 最新免费社工库机器人(LetsTG可[特殊字符])搭建指南(含 Python 脚本)
数据库·搜索引擎·机器人·开源·全文检索·facebook·twitter
计算机毕设VX:Fegn08953 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计
冉冰学姐3 小时前
SSM校园排球联赛管理系统y513u(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面
数据库·ssm 框架应用·开题报告、
Tony Bai4 小时前
【分布式系统】03 复制(上):“权威中心”的秩序 —— 主从架构、一致性与权衡
大数据·数据库·分布式·架构