当前位置: 首页 > news >正文

解锁 C# 与 LiteDB 嵌入式 NoSQL 数据库

一、开篇:邂逅 C# 与 LiteDB 新世界

在当今的软件开发领域,数据管理如同建筑的基石,而选择一款合适的数据库则是项目成功与否的关键因素之一。对于 C# 开发者来说,面对琳琅满目的数据库选项,如何抉择常常令人头疼。今天,就为大家揭开一款轻量级嵌入式 NoSQL 数据库 ——LiteDB 的神秘面纱,看看它与 C# 碰撞能擦出怎样奇妙的火花。

当我们开启一个新的 C# 项目,无论是桌面应用、移动应用,还是小型的后端服务,数据存储与读取的高效性、便捷性都是必须考量的重点。传统的关系型数据库固然强大,在处理复杂关联数据和事务时游刃有余,但对于一些追求简洁、快速部署,以及数据结构相对灵活的场景,嵌入式 NoSQL 数据库展现出了独特的优势。LiteDB 应运而生,它完全由 C# 编写,仿佛是为 C# 生态量身定制,能够无缝嵌入到应用程序中,无需额外的服务器配置,就像给你的代码世界增添了一个隐秘而强大的 “数据百宝箱”,让数据管理变得轻松自如。接下来,就让我们一步步走进 C# 与 LiteDB 构建的精彩天地。

二、LiteDB 初印象:轻量级的魔法盒子

2.1 是什么让 LiteDB 脱颖而出

LiteDB 是一款开源的嵌入式 NoSQL 数据库引擎,它完全由 C# 编写,天生就与 C# 应用程序有着极高的亲和力。其最为显著的特性之一就是小巧玲珑,整个数据库核心库通常仅有几百 KB 大小,以一个简单的.db 文件形式存在,无需像传统数据库那样依赖独立的服务器进程,能够直接嵌入到你的 C# 应用中,无论是 Windows 桌面应用、.NET Core 跨平台应用,还是基于 Xamarin 开发的移动端应用,都可以轻松携带这个 “数据百宝箱”,随时随地管理数据,仿佛给应用赋予了一个专属的、隐形的数据管家。

在数据存储格式上,LiteDB 采用 BSON(Binary JSON),这种格式既保留了 JSON 的灵活性与可读性,又在存储和传输效率上进行了优化,让结构化数据的存储变得游刃有余。对于开发者而言,LiteDB 还支持 LINQ 查询,这无疑是一大福音。熟悉 C# 的开发者们可以直接使用 LINQ 语法来操作数据库,无缝对接已有的编程习惯,降低学习成本,快速实现复杂的数据筛选、排序与聚合等操作,极大提升开发效率。同时,LiteDB 还具备 ACID 事务特性,能够确保在多操作并发场景下数据的原子性、一致性、隔离性与持久性,为数据安全保驾护航,即便在一些对数据完整性要求苛刻的小型商业应用场景下,也能稳稳应对。

2.2 适用场景大揭秘

小型桌面应用是 LiteDB 的 “主战场” 之一。想象一下,你正在开发一款个人记账软件,只需要记录日常收支、分类统计等简单数据,使用 LiteDB 就无需搭建复杂的数据库服务器,数据直接存储在本地的.db 文件中,软件启动迅速,操作流畅,即开即用,而且备份数据也仅仅是复制一个文件的事儿,像 Windows 下的便捷记账工具、Mac 上的待办事项清单应用等,LiteDB 都能完美适配,为应用赋予简洁而强大的数据管理能力。

在移动应用开发领域,特别是对于那些有本地数据存储需求,但又受限于移动端设备存储资源与网络条件的应用,LiteDB 同样表现卓越。以一款离线阅读的 APP 为例,它需要缓存文章内容、用户阅读进度等信息,LiteDB 可以在用户离线时高效存储这些数据,待网络恢复后再进行同步更新,凭借其轻量级特性,不会占用过多手机存储空间与电量,让应用在资源有限的移动端环境下依然能够提供稳定、流畅的数据服务。

对于物联网(IoT)设备而言,LiteDB 更是开启了数据管理的新大门。这些设备往往内存有限、算力不高,且通常处于分布式、弱网络甚至离线的工作环境。比如一个智能农业监测系统中的众多传感器节点,需要记录温湿度、光照强度等环境数据,LiteDB 能够以极小的资源开销嵌入到设备固件中,实时存储采集到的数据,在需要时供上位机或云端读取分析,实现对设备运行状态与环境信息的精准掌控,助力 IoT 设备在复杂多变的现实场景中稳定运行,发挥最大效能。

三、准备启航:安装与初始化

3.1 借助 NuGet 引入 LiteDB

在开启 LiteDB 之旅的第一步,就是要将它引入到我们的 C# 项目中。幸运的是,这一过程非常便捷,借助 NuGet 包管理器就能轻松搞定。

如果你是 Visual Studio 的忠实用户,只需右键单击你的 C# 项目,在弹出的菜单中选择 “管理 NuGet 程序包”,随后在打开的 NuGet 窗口中,切换到 “浏览” 选项卡,在搜索框中输入 “LiteDB”,稍等片刻,就能找到对应的包。点击 “安装” 按钮,Visual Studio 就会自动下载并安装 LiteDB 及其相关依赖项,整个过程一气呵成,就像为你的项目找到了一把开启数据宝藏的神奇钥匙。

要是你更习惯使用命令行工具,也没问题。打开命令行窗口,切换到你的项目目录下,输入 “Install-Package LiteDB” 并回车,.NET CLI 就会迅速响应,从 NuGet 源拉取 LiteDB 并安装到你的项目中,如同施展了一场无声的魔法,让 LiteDB 悄然融入你的代码世界。

3.2 创建你的数据库 “日记本”

成功引入 LiteDB 后,接下来就要创建我们的数据库了。在 LiteDB 中,数据库以一个.db 文件的形式存在,就如同一个装满数据的魔法日记本。

使用 LiteDatabase 类就能轻松创建或打开数据库连接,示例代码如下:

using LiteDB;
// 这里的 'path/to/your/database.db' 需要替换为你实际想要存放数据库文件的路径
var db = new LiteDatabase("path/to/your/database.db");

需要注意的是,这个路径既可以是绝对路径,也可以是相对路径。若使用相对路径,它通常是相对于你的应用程序启动目录而言。例如,你想把数据库文件放在项目的 “Data” 文件夹下,就可以写成 “Data/mydb.db”。在创建数据库时,如果指定路径下的.db 文件不存在,LiteDB 会自动帮你创建一个全新的数据库文件;要是文件已存在,它则会智能地打开已有数据库,确保你的数据随时待命,等待你的操作指令。初始化数据库连接这一步,就像是开启了通往数据世界的大门,为后续的数据存储与读取铺就了道路,让我们离高效管理数据的目标又近了一步。

四、数据建模:定义你的专属 “魔法蓝图”

在 LiteDB 的世界里,数据建模就像是绘制一张精密的魔法蓝图,它决定了我们如何组织和存储数据,让数据的管理更加有序、高效。在 LiteDB 中,一切皆可文档,这意味着我们可以通过创建简单的 C# 类来定义数据模型,每个类的实例就如同一份份独特的文档,被存储到数据库中。

以一个奇幻风格的 “巫师” 模型为例,假设我们要创建一个数据库来记录魔法学院中巫师们的信息,代码如下:

public class Wizard
{[BsonId]public int Id { get; set; } // 每个巫师的唯一标识,使用 [BsonId] 标记为主键,方便数据的快速检索与关联public string Name { get; set; } // 巫师的名字,如“哈利·波特”public int HouseId { get; set; } // 所属学院 ID,关联到学院信息public List<string> SpellsKnown { get; set; } // 掌握的魔法列表,体现复杂数据结构,支持存储多个魔法技能
}

在这个模型中,Id 属性被标记为 [BsonId],这是 LiteDB 识别文档主键的重要标识。就像现实世界中每个人都有独一无二的身份证号一样,主键确保了每个巫师记录在数据库中的唯一性,方便后续的数据查询、更新与删除操作能够精准定位到目标数据。Name 字段用于存储巫师的姓名,它是一个简单的字符串类型,直观地展现巫师的身份标识。HouseId 作为整数类型,关联着学院的唯一标识符,通过这个字段,我们可以轻松地建立起巫师与所属魔法学院之间的联系,实现数据之间的关联查询,比如查询某个学院下所有巫师的信息。而 SpellsKnown 字段则是一个 List 类型,它巧妙地展示了 LiteDB 处理复杂数据结构的能力,能够存储巫师所掌握的多个魔法技能,无论是简单的照明咒 “Lumos”,还是强大的守护咒 “Expecto Patronum”,都可以被有序地记录下来,让数据模型更加贴近真实的业务场景需求,为后续丰富多样的数据操作奠定坚实基础。通过精心设计这样的数据模型,我们就如同为数据库赋予了智慧的大脑,让它能够精准、高效地存储与管理数据,满足各类奇幻冒险般的业务需求。

五、核心魔法:增删查改全攻略

5.1 录入数据:挥动插入咒语

有了精心设计的数据模型和初始化的数据库连接,接下来就是向数据库中录入数据了,这就好比将一本本魔法秘籍放入我们的魔法图书馆。

在 LiteDB 中,使用 Insert 方法就能轻松实现数据插入。假设我们已经创建了 Wizard 模型,并且获取到了对应的集合 wizardsCollection(通过 db.GetCollection(“wizards”)),现在要插入哈利・波特的信息:

var harry = new Wizard
{Name = "Harry Potter",HouseId = 1,SpellsKnown = new List<string> { "Lumos", "Expelliarmus" }
};
wizardsCollection.Insert(harry);

这里,Insert 方法会将 harry 这个 Wizard 实例作为一个文档插入到 wizards 集合中。如果集合中还不存在 Id 值相同的文档,它会自动为 harry 分配一个唯一的 Id(若 Wizard 模型中的 Id 为自增类型,如 int 且无特殊设置,LiteDB 会按顺序递增生成;若 Id 为 ObjectId 等其他类型,也会按相应规则生成唯一标识)。需要注意的是,插入操作是幂等的,多次插入相同的文档(即具有相同 Id),除非集合设置了特殊的唯一索引约束,否则不会报错,但也不会重复插入数据,只是默默地忽略重复插入请求,确保数据的一致性与简洁性。

5.2 精准查找:念动查询密语

数据录入后,如何从海量的信息中精准捞出我们想要的数据呢?LiteDB 提供了强大的查询功能,让你仿佛拥有了一双洞察数据的 “魔法之眼”。

使用 FindOne 方法可以根据特定条件查找单个文档。比如,我们想要查找名为 “哈利・波特” 的巫师信息:

var harryFound = wizardsCollection.FindOne(w => w.Name == "Harry Potter");
if (harryFound!= null)
{Console.WriteLine($"找到巫师: {harryFound.Name}");Console.WriteLine($"所属学院: #{harryFound.HouseId}");Console.WriteLine($"掌握的魔法: {string.Join(", ", harryFound.SpellsKnown)}");
}
else
{Console.WriteLine("该巫师尚未加入我们的收藏!");
}

这段代码通过一个 Lambda 表达式 w => w.Name == “Harry Potter” 作为查询条件,精准定位到符合条件的巫师记录。若找到,便能详细展示其姓名、所属学院和掌握的魔法技能;若未找到,则给出友好提示。

而 FindAll 方法则更为强大,它能返回满足特定条件的所有文档。假设我们要查找所有属于格兰芬多学院(假设学院 ID 为 1)的巫师:

var gryffindors = wizardsCollection.FindAll(w => w.HouseId == 1);
foreach (var wizard in gryffindors)
{Console.WriteLine($"巫师: {wizard.Name},掌握魔法: {string.Join(", ", wizard.SpellsKnown)}");
}

这里利用 FindAll 结合条件查询,一次性捞出所有目标巫师信息,遍历输出,让数据一目了然。无论是简单的等值查询,还是复杂的包含、范围查询(如查询掌握特定魔法或魔法数量在某个区间的巫师),都可以通过灵活运用 LINQ 表达式来实现,满足各种刁钻的数据检索需求。

5.3 修改更新:施展改写魔法

在魔法世界里,巫师的成长伴随着魔法技能的提升与信息的变更,同样,在 LiteDB 中,数据也需要与时俱进地更新。

Update 方法就是我们手中的 “魔法修改笔”。例如,哈利・波特在冒险过程中学会了新魔法 “Expecto Patronum”,我们需要更新他的信息:

var updateResult = wizardsCollection.Update(w => w.Name == "Harry Potter",w => new Wizard { SpellsKnown = new List<string> { "Lumos", "Expelliarmus", "Expecto Patronum" } });

第一个参数 w => w.Name == “Harry Potter” 用于定位到要更新的目标文档,第二个参数则是一个新的 Wizard 实例,包含了更新后的魔法技能列表。LiteDB 会智能地比对新旧数据,仅更新发生变化的字段,高效且精准。需要注意的是,如果更新条件匹配不到任何文档,Update 操作将悄无声息地结束,不会引发错误,所以在执行更新前,最好先确认目标文档是否存在,或者结合查询操作来验证更新的必要性与准确性,确保数据更新按预期进行。

5.4 数据移除:释放删除魔力

当某些数据不再需要时,为了保持数据库的 “整洁”,就需要施展删除魔法了。

Delete 方法可以帮我们轻松移除指定的数据。比如,在一场大战后,我们要删除伏地魔(假设其名字为 “Voldemort”)的记录:

var deleteResult = wizardsCollection.Delete(w => w.Name == "Voldemort");

通过简单的条件表达式,就能精准地将符合条件的文档从集合中删除。如果条件匹配到多个文档,LiteDB 会一并将它们移除,确保数据清理的彻底性。与更新操作类似,若删除条件未找到匹配文档,Delete 操作也会平静地结束,不会报错,开发者需要自行把控删除条件的准确性,避免误删重要数据,维护数据的安全性与完整性。

六、进阶魔法:索引、事务与加密

6.1 索引加持:加速查询之旅

在数据库的世界里,随着数据量的不断增长,查询效率逐渐成为开发者关注的焦点。LiteDB 为我们提供了强大的索引功能,就如同在一本厚重的魔法书中创建了详细的目录,能够让数据查询瞬间定位,大大提升检索速度。

索引的原理基于特定的数据结构,它对文档中的某个或某些字段进行排序与存储,使得查询时无需遍历整个数据集,就能快速逼近目标数据。例如,在我们之前的 “巫师” 数据库中,如果经常需要根据巫师的名字来查找记录,那么为 Name 字段创建索引将极大优化查询性能。

创建索引的代码非常简洁,在获取集合后,使用 EnsureIndex 方法即可:

var wizardsCollection = db.GetCollection<Wizard>("wizards");
wizardsCollection.EnsureIndex(x => x.Name);

这里,EnsureIndex 方法会为 Wizard 类中的 Name 字段创建一个索引。创建索引后,当执行类似 FindOne(w => w.Name == “Harry Potter”) 这样的查询时,LiteDB 不再需要逐一比对每个文档的 Name 字段,而是借助索引快速定位到符合条件的文档,查询速度得到质的飞跃。尤其是在数据量达到成千上万条时,有无索引的查询耗时差异会非常明显,原本可能需要数秒甚至更长时间的查询,在索引的助力下,可能瞬间就能得到结果,让应用的响应速度得到极大提升,为用户带来流畅的数据交互体验。

6.2 事务保障:守护数据安全

在涉及多个数据操作且这些操作需要作为一个整体要么全部成功、要么全部失败的场景下,事务就如同数据世界的 “守护天使”,确保数据的一致性与完整性。

以一个简单的转账场景为例,假设我们有一个记录用户账户信息的数据库,包含 UserId、Balance 等字段。当用户 A 向用户 B 转账 100 金币时,需要先从用户 A 的账户扣除 100 金币,再向用户 B 的账户增加 100 金币,这两个操作必须同时成功,否则就会出现数据不一致的问题,比如 A 的钱扣了但 B 没收到,或者 B 收到钱了但 A 没扣款。

在 LiteDB 中,使用事务来保障这一过程的正确性:

using (var trans = db.BeginTrans())
{var usersCollection = db.GetCollection<User>("users");var userA = usersCollection.FindOne(u => u.UserId == "A");userA.Balance -= 100;usersCollection.Update(userA);var userB = usersCollection.FindOne(u => u.UserId == "B");userB.Balance += 100;usersCollection.Update(userB);trans.Commit();
}

在这段代码中,首先通过 BeginTrans 开启一个事务,然后在事务内执行对用户 A 和用户 B 账户的更新操作,如果在执行过程中没有出现异常,最后调用 Commit 方法提交事务,此时两个更新操作才会真正持久化到数据库;若在事务执行期间发生任何错误,比如数据库连接突然中断、更新操作违反了数据约束等,事务会自动回滚,之前对用户 A 和用户 B 账户所做的修改都会被撤销,确保数据库状态回到事务开始前的模样,数据的一致性和完整性得以完美守护,让应用在复杂的数据操作场景下稳如泰山。

6.3 加密防护:筑牢数据堡垒

在当今数字化时代,数据隐私与安全至关重要,尤其是涉及用户敏感信息的数据库,一旦泄露,后果不堪设想。LiteDB 为我们提供了加密数据文件的能力,如同给数据库披上了一层隐形的铠甲,让数据在存储层面就得到严密保护。

要对数据库文件进行加密,在创建 LiteDatabase 实例时,只需指定加密密钥即可:

using var db = new LiteDatabase("path/to/your/database.db", new LiteDB.FileOptions { Password = "mySecretKey" });

这里,mySecretKey 就是我们设置的加密密钥,它必须是 8 字节长度的字符串。设置加密后,LiteDB 会使用指定密钥对数据库文件进行加密存储,当应用程序读取数据时,也需要提供相同的密钥才能解密并正常访问数据。在实际应用中,对于金融类应用存储用户账户余额、交易记录,医疗类应用保存患者病历信息等场景,加密功能能够有效防止数据在存储介质上被非法获取与解读,确保用户隐私不被侵犯,让数据在安全的轨道上稳健运行,为应用的可靠发展保驾护航。

七、实战演练:打造一个小型应用

纸上得来终觉浅,让我们通过一个完整的实战案例,深入体会 C# 与 LiteDB 的强大组合。假设我们要开发一个简单的图书管理桌面应用程序,它需要实现图书信息的录入、查询、借阅管理以及统计分析等功能。

需求分析阶段,我们明确了应用的核心功能。对于图书信息,需要记录书名、作者、出版社、出版年份、ISBN 号以及库存数量等字段;借阅管理则涉及借阅人姓名、借阅时间、预计归还时间等信息。考虑到应用面向小型图书馆或个人藏书管理场景,数据量不大,且对部署便捷性要求较高,LiteDB 无疑是数据库的绝佳选择。

技术选型上,基于 Windows 平台开发,选用 C# 的 Windows Forms 框架搭建界面,结合 LiteDB 进行数据存储。这样既能利用 C# 的强大功能快速构建界面交互,又能借助 LiteDB 轻松管理数据,两者相得益彰。

在功能模块设计方面,主要分为图书信息管理、借阅管理与统计分析三大模块。图书信息管理模块负责图书的添加、编辑、删除与查询操作;借阅管理模块实现借阅记录的录入、归还操作以及逾期未还图书的提醒;统计分析模块则能按作者、出版社等维度统计图书数量,为图书馆员或个人藏书者提供数据洞察。

编码实现时,首先创建对应的 C# 数据模型类,如 Book 类和 Loan 类:

public class Book
{[BsonId]public int Id { get; set; }public string Title { get; set; }public string Author { get; set; }public string Publisher { get; set; }public int PublicationYear { get; set; }public string ISBN { get; set; }public int StockQuantity { get; set; }
}public class Loan
{[BsonId]public int Id { get; set; }public int BookId { get; set; }public string BorrowerName { get; set; }public DateTime BorrowDate { get; set; }public DateTime DueDate { get; set; }
}

接着,在应用启动时初始化 LiteDB 数据库连接:

using LiteDB;
public partial class MainForm : Form
{private LiteDatabase _db;public MainForm(){InitializeComponent();_db = new LiteDatabase("books.db");}
}

在图书信息管理模块,添加图书的代码如下:

var booksCollection = _db.GetCollection<Book>("books");
var newBook = new Book
{Title = txtTitle.Text,Author = txtAuthor.Text,Publisher = txtPublisher.Text,PublicationYear = int.Parse(txtPublicationYear.Text),ISBN = txtISBN.Text,StockQuantity = int.Parse(txtStockQuantity.Text)
};
booksCollection.Insert(newBook);

查询图书可根据不同条件灵活运用 FindOne 和 FindAll 方法,例如按书名查询:

var result = booksCollection.FindOne(b => b.Title.Contains(txtSearchTitle.Text));
if (result!= null)
{// 展示图书详细信息
}
else
{MessageBox.Show("未找到匹配图书");
}

借阅管理模块中,记录借阅信息:

var loansCollection = _db.GetCollection<Loan>("loans");
var newLoan = new Loan
{BookId = selectedBook.Id,BorrowerName = txtBorrowerName.Text,BorrowDate = DateTime.Now,DueDate = DateTime.Now.AddDays(14)
};
loansCollection.Insert(newLoan);

归还图书时,更新借阅记录并调整图书库存:

var loanToUpdate = loansCollection.FindOne(l => l.Id == selectedLoan.Id);
loanToUpdate.BorrowerName = "";
loanToUpdate.BorrowDate = default;
loanToUpdate.DueDate = default;
loansCollection.Update(loanToUpdate);var bookToUpdate = booksCollection.FindOne(b => b.Id == loanToUpdate.BookId);
bookToUpdate.StockQuantity++;
booksCollection.Update(bookToUpdate);

统计分析模块,按作者统计图书数量:

var authorStats = booksCollection.FindAll().GroupBy(b => b.Author).Select(g => new { Author = g.Key, Count = g.Count() });
foreach (var stat in authorStats)
{// 将统计结果展示在界面上
}

通过这个实战案例,我们清晰地看到 C# 与 LiteDB 如何默契配合,快速构建出功能完备的小型应用,满足实际业务需求,无论是个人开发者还是小型团队,都能利用这对组合高效开启项目开发之旅,让创意迅速落地为实用的软件产品。

八、总结:C# 与 LiteDB 的未来征程

至此,我们一同领略了 C# 与 LiteDB 携手带来的强大数据管理魔力。从初次相识 LiteDB 的轻量级魅力,到熟练运用它进行数据的增删查改、索引构建、事务处理以及数据加密,再到实战打造小型应用,每一步都见证了这对组合的高效与便捷。

LiteDB 凭借其小巧玲珑、嵌入式无服务器、支持复杂数据结构与 LINQ 查询等诸多优势,为 C# 开发者在小型项目、桌面应用、移动端以及物联网设备等领域的数据存储需求提供了近乎完美的解决方案。它极大地降低了开发门槛,让开发者能够将更多精力聚焦于业务逻辑创新,快速实现应用从构思到落地。

展望未来,随着技术的不断迭代演进,C# 语言本身在性能优化、语法糖拓展等方面持续进步,LiteDB 也势必紧跟步伐,进一步优化存储效率、查询性能,强化分布式场景下的协同能力,解锁更多高级功能。两者的深度融合将为开发者打开一扇通往更广阔创意天地的大门,无论是新兴的智能穿戴设备数据管理、跨平台的小型云服务构建,还是传统行业数字化转型中的各类小型系统开发,C# 与 LiteDB 都有望成为开发者手中的神兵利器,助力大家在创新的道路上扬帆远航,创造更多精彩绝伦的软件佳作。愿大家怀揣探索之心,持续挖掘这对组合的无限潜力,让代码世界绽放更耀眼光芒。

相关文章:

解锁 C# 与 LiteDB 嵌入式 NoSQL 数据库

一、开篇&#xff1a;邂逅 C# 与 LiteDB 新世界 在当今的软件开发领域&#xff0c;数据管理如同建筑的基石&#xff0c;而选择一款合适的数据库则是项目成功与否的关键因素之一。对于 C# 开发者来说&#xff0c;面对琳琅满目的数据库选项&#xff0c;如何抉择常常令人头疼。今…...

7 分布式定时任务调度框架

先简单介绍下分布式定时任务调度框架的使用场景和功能和架构&#xff0c;然后再介绍世面上常见的产品 我们在大型的复杂的系统下&#xff0c;会有大量的跑批&#xff0c;定时任务的功能&#xff0c;如果在独立的子项目中单独去处理这些任务&#xff0c;随着业务的复杂度的提高…...

七星棋类游戏源码:两百玩法开源修复

这套七星棋类源码&#xff0c;覆盖六大省区&#xff08;湖南双端、湖北、山西、江苏、贵州等&#xff09;&#xff0c;安卓与苹果端都能轻松适配&#xff0c;汇集 6 个端口与 200 多种子游戏玩法。此版本为二次开发修复版&#xff0c;功能完备且源码完全公开&#xff0c;包括乐…...

未来世界:科技引领的奇幻篇章

科技发展的这么快&#xff0c;未来的世界将会是什么样的呢&#xff1f; 在人类历史的长河中&#xff0c;科技始终是推动社会进步的核心力量。从古老的四大发明到如今的人工智能、基因编辑、量子计算等前沿技术&#xff0c;科技发展的速度日新月异。我们不禁会想&#xff0c;在…...

[python3]Uvicorn库

Uvicorn 是一个用于运行 ASGI&#xff08;Asynchronous Server Gateway Interface&#xff09;应用程序的轻量级服务器。ASGI 是 Python Web 应用程序接口的一种扩展&#xff0c;它不仅支持传统的同步 Web 请求处理&#xff0c;还支持异步请求处理、WebSockets 以及 HTTP/2。 h…...

istio-proxy oom问题排查步骤

1. 查看cluster数量 cluster数量太多会导致istio-proxy占用比较大的内存&#xff0c;此时需检查是否dr资源的host设置有配置为* 2. 查看链路数据采样率 若采样率设置过高&#xff0c;在压测时需要很大的内存来维护链路数据。可以调低采样率或增大istio-proxy内存。 检查iop中…...

Flutter:使用FVM安装多个Flutter SDK 版本和使用教程

一、FVM简介 FVM全称&#xff1a;Flutter Version Management FVM通过引用每个项目使用的Flutter SDK版本来帮助实现一致的应用程序构建。它还允许您安装多个Flutter版本&#xff0c;以快速验证和测试您的应用程序即将发布的Flutter版本&#xff0c;而无需每次等待Flutter安装。…...

关于物联网的基础知识(二)——物联网体系结构分层

成长路上不孤单&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a;&#x1f60a; 【14后&#x1f60a;///计算机爱好者&#x1f60a;///持续分享所学&#x1f60a;///如有需要欢迎收藏转发///&#x1f60a;】 今日分享关于物联网的基础知识&#xff08;二&a…...

[程序设计]—代理模式

[程序设计]—代理模式&#x1f473; 本文章记录学习于——52.面向切面&#xff1a;AOP-场景模拟_哔哩哔哩_bilibili 最近闲来无事&#xff0c;在学习Spring的源码&#xff1a; 后面慢慢更新源码系列blog&#xff0c;希望多多关注&#x1f64f;&#x1f64f; 目前已经总结的b…...

26、【OS】【Nuttx】用cmake构建工程

背景 之前wiki 14、【OS】【Nuttx】Nsh中运行第一个程序 都是用 make 构建&#xff0c;准备切换 cmake 进行构建&#xff0c;方便后续扩展开发 Nuttx cmake 适配 nuttx项目路径下输入 make distclean&#xff0c;清除之前工程配置 adminpcadminpc:~/nuttx_pdt/nuttx$ make …...

C#中序列化的选择:JSON、XML、二进制与Protobuf详解

C#中序列化的选择&#xff1a;JSON、XML、二进制与Protobuf详解 在C#开发中&#xff0c;序列化是将对象转换为可存储或传输的格式的过程&#xff0c;而反序列化则是将存储或传输的数据重新转换为对象的过程。选择合适的序列化方式对应用程序的性能、可维护性和兼容性至关重要。…...

单片机实现模式转换

[任务] 要求通过单片机实现以下功能&#xff1a; 1.单片机有三种工作模式(定义全局变量MM表示模式&#xff0c;MM1&#xff0c;2&#xff0c;3表示三种不同的模式) LED控制模式 风扇控制模式 蜂鸣器控制模式 2.可以在某一个模式下通过拓展板KEY1按键控制设备 (按…...

Shader -> SweepGradient扫描渐变着色器详解

XML文件 <com.example.myapplication.MyViewxmlns:android"http://schemas.android.com/apk/res/android"android:layout_width"match_parent"android:layout_gravity"center"android:layout_height"400dp"/>自定义View代码 c…...

鼠标过滤驱动

文章目录 概述代码参考资料 概述 其编写过程大体与键盘过滤驱动相似&#xff0c;只需要切换一下附加的目标设备以及创建的设备类型等。但在该操作后依然无法捕获到Vmware创建的win7操作系统的鼠标irp信息&#xff0c;于是通过在获取鼠标驱动&#xff0c;遍历其所有的设备进而附…...

【深度学习】数据操作入门

数据操作 为了能够完成各种数据操作&#xff0c;我们需要某种方法来存储和操作数据。 通常&#xff0c;我们需要做两件重要的事&#xff1a;&#xff08;1&#xff09;获取数据&#xff1b;&#xff08;2&#xff09;将数据读入计算机后对其进行处理。 如果没有某种方法来存储…...

WIFIAP项目 5G RX二次谐波超标案例分析

一、 问题的现象及描述 采用博通WIFI方案方案的两个项目在做CE高频杂散测试时发现5G RX出现10.359 GHz的高频杂散点&#xff0c;通过更换信道&#xff0c;该杂散点跟着改变&#xff0c;最终确认该频率是5G主信号的二倍频&#xff1b;如下图&#xff1a; 二、 问题分析  由于…...

HarmonyOS(ArkUI框架介绍)

ArkUI框架介绍 ArkUI简介 基本概念 UI&#xff1a; 即用户界面。开发者可以将应用的用户界面设计为多个功能页面&#xff0c;每个页面进行单独的文件管理&#xff0c;并通过页面路由API完成页面间的调度管理如跳转、回退等操作&#xff0c;以实现应用内的功能解耦。 组件&…...

在 Ubuntu 下通过 Docker 部署 MySQL 服务器

引言 Docker 是一个开源的容器化平台&#xff0c;允许开发者将应用及其依赖打包成一个标准化的单元。MySQL 是一个广泛使用的关系型数据库管理系统&#xff0c;因其高性能、可靠性和易用性&#xff0c;成为许多应用的首选数据库。结合 Docker 和 MySQL&#xff0c;可以轻松地创…...

MCU 和 PSK

在加密和认证领域&#xff0c;MCU 和 PSK 是两个不同的概念&#xff0c;分别涉及硬件和密钥管理。下面是它们的含义和相关解释&#xff1a; 1. MCU 全称&#xff1a;Microcontroller Unit&#xff08;微控制单元&#xff09; 用途&#xff1a; MCU 是一种集成了 CPU、内存&am…...

Linux:进程概念(二.查看进程、父进程与子进程、进程状态详解)

目录 1. 查看进程 1.1 准备工作 1.2 指令&#xff1a;ps—显示当前系统中运行的进程信息 1.3 查看进程属性 1.4 通过 /proc 系统文件夹看进程 2. 父进程与子进程 2.1 介绍 2.2 getpid() \getppid() 2.3 fork()函数—通过系统调用创建进程 fork()函数疑问 3. 进程状态…...

苍穹外卖07——来单提醒和客户催单(涉及SpringTask、WebSocket协议、苍穹外卖跳过微信支付同时保证可以收到订单功能)

Spring Task介绍 应用场景&#xff1a; 信用卡每月还款提醒银行贷款每月还款提醒火车票销售系统处理未付款订单入职纪念日为用户发送通知 cron表达式 cron表达式其实就是一个字符串&#xff0c;通过cron表达式可以定义任务触发的时间。 构成规则&#xff1a;分为6或7个域&…...

C语言二级考试

你必须知道的 二级考试不是编写程序&#xff0c;或者说不只是编程的考核&#xff0c;它还会考核计算机C语言相关语言还有内涵等基础知识&#xff0c;比较全面综合&#xff08;说人话&#xff0c;要看最新考纲具备一定的基础知识&#xff09; 考试时间 120 分钟 分值 100 分&…...

IDEA Maven构建时报错:无效的目标发行版17

报错分析 报错原因&#xff1a;Maven 构建时&#xff0c;Java 版本配置不匹配 我安装的JDK版本是1.8&#xff0c;但由于种种原因&#xff0c;Maven构建时指定了 Java 17 作为目标发行版&#xff0c;从而导致错误 解决方案 首先&#xff0c;java -version&#xff0c;查看环…...

javafx 将项目打包为 Windows 的可执行文件exe

要将 JavaFX 项目打包为 .exe 文件&#xff0c;你可以使用一些工具将你的应用程序封装为 Windows 可执行文件。以下是两种常用的方法&#xff1a; 方法 1&#xff1a;使用 jpackage&#xff08;适用于 JDK 14 及更高版本&#xff09; jpackage 是 JDK 内置的工具&#xff0c;…...

Python操作Excel的库openpyxl使用入门

openpyxl 是一个用于读写 Excel 2010 xlsx/xlsm/xltx/xltm 文件的 Python 库。以下是一些 openpyxl 的基本使用方法&#xff1a; 安装 openpyxl 首先&#xff0c;确保已经安装了 openpyxl。如果没有安装&#xff0c;可以使用以下命令进行安装&#xff1a; pip install openp…...

数据通过canal 同步es,存在延迟问题,解决方案

当使用 Canal 同步数据到 Elasticsearch&#xff08;ES&#xff09;时&#xff0c;出现延迟问题通常源于多个因素&#xff0c;如 Canal 配置、网络延迟、ES 的负载和性能瓶颈等。以下是一些解决方案&#xff0c;帮助减少和解决延迟问题&#xff1a; 1. 优化 Canal 配置 Canal…...

了解Node.js

Node.js是一个基于V8引擎的JavaScript运行时环境&#xff0c;它允许JavaScript代码在服务器端运行&#xff0c;从而实现后端开发。Node.js的出现&#xff0c;使得前端开发人员可以利用他们已经掌握的JavaScript技能&#xff0c;扩展技能树并成为全栈开发人员。本文将深入浅出地…...

Android Studio创建新项目并引入第三方jar、aar库驱动NFC读写器读写IC卡

本示例使用设备&#xff1a;https://item.taobao.com/item.htm?spma21dvs.23580594.0.0.52de2c1bbW3AUC&ftt&id615391857885 一、打开Android Studio,点击 File> New>New project 菜单&#xff0c;选择 要创建的项目模版&#xff0c;点击 Next 二、输入项目名称…...

Oracle Dataguard(主库为双节点集群)配置详解(4):配置备库

Oracle Dataguard&#xff08;主库为双节点集群&#xff09;配置详解&#xff08;4&#xff09;&#xff1a;配置备库 目录 Oracle Dataguard&#xff08;主库为双节点集群&#xff09;配置详解&#xff08;4&#xff09;&#xff1a;配置备库一、为备库配置静态监听1、配置 li…...

前端炫酷动画--文字(二)

目录 一、弧形边框选项卡 二、零宽字符 三、目录滚动时自动高亮 四、高亮关键字 五、文字描边 六、按钮边框的旋转动画 七、视频文字特效 八、立体文字特效让文字立起来 九、文字连续光影特效 十、重复渐变的边框 十一、磨砂玻璃效果 十二、FLIP动画 一、弧形边框…...

网站建设报价套餐/外链屏蔽逐步解除

【知识要点】   &#xff08;&#xff11;&#xff09;初识GridView   &#xff08;&#xff12;&#xff09;为GridView加个样式   &#xff08;&#xff13;&#xff09;让GridView自定义表头 【问题提出】   如何把客户以下面列表的形式展示出来呢&#xff1f; 【…...

wordpress ping通告/武汉seo服务外包

IoFilter是MINA核心构造之一&#xff0c;起着非常重要的作用。它过滤IoService和IoHandler之间的所有I / O事件和请求。如果您有Web应用程序编程经验&#xff0c;可以放心地认为它是Servlet过滤器的表兄弟。提供了许多开箱即用的过滤器&#xff0c;通过使用开箱即用的过滤器简化…...

商务网站开发方式/网页设计用什么软件

GPU&#xff1a;Graphics Processing Unit&#xff0c;图像处理器&#xff0c;GPU上有成千上万核&#xff0c;这些核并行运行&#xff1b;CPU&#xff1a;Central Processing Unit&#xff0c;中央处理器&#xff0c;CPU通常有单核、双核、四核和八核&#xff0c;但这些核只能串…...

图片网站怎么做/手机优化大师下载安装

环境&#xff1a; Nacos 1.4.4 Nginx 1.23.1背景&#xff1a; 部署了Nacos集群&#xff0c;同时使用了Nginx进行负载均衡转发&#xff0c;登陆时提示账号密码错误。不通过转发直接去访问Nacos节点发现能够正常登录。去Nacos的github仓库的Issue查找相关问题&#xff0c;发现已…...

邢台移动网站建设费用/seo这个行业怎么样

原题 题目描述 输入一个二叉树的先序串&#xff0c;输出以括号形式表示的而叉树。如果结点的子树为空&#xff0c;先序串的对应位置为空格符。 输入 第1行&#xff1a;先序串 &#xff08;结点数≤26&#xff0c;以单个大写字母表示&#xff09; 输出 第1行&#xff1a;二…...

制作企业网站软件/自媒体有哪些平台

文章目录labelme2voc其它数据集转换easydata2imageneteasydata2voceasydata2cocoeasydata2seglabelme2cocolabelme2segjingling2seglabelme2voc pdx.tools.labelme2voc(image_dir, json_dir, dataset_save_dir)将LabelMe标注的数据集转换为VOC数据集。 参数 image_dir (str)…...