谈谈 .NET8 平台中对 LiteDB 的 CRUD 操作
@ 目录1、同步版 LiteDB2、异步版 LiteDB.Async1、.net cli 命令创建项目2、项目添加相关 nuget 包3、改造项目结构4、改造项目代码1、谈谈 sqlite 和 litedb 的 ACID 事务支持?2、谈谈 sqlite 和 litedb 的稳定性和可靠性?3、谈谈 sqlite 和 litedb 的应用场景?LiteDBLiteDB 简介LiteDB - 一个单
@ 目录
1、同步版 LiteDB
2、异步版 LiteDB.Async
1、.net cli 命令创建项目
2、项目添加相关 nuget 包
3、改造项目结构
4、改造项目代码
1、谈谈 sqlite 和 litedb 的 ACID 事务支持?
2、谈谈 sqlite 和 litedb 的稳定性和可靠性?
3、谈谈 sqlite 和 litedb 的应用场景?
LiteDB 简介
LiteDB - 一个单数据文件 .NET NoSQL 文档存储。
LiteDB
是一个小巧、轻量级、快速、简单易用的 NoSQL
嵌入式数据库,它支持文档存储和查询,具有高性能、可嵌入性、跨平台等特点。
LiteDB
是一个 .NET
平台下的开源项目,它可以在 Windows、Linux、MacOS、Android、iOS
等多个平台上运行。LiteDB
的 API
简单易用,支持LINQ
查询,同时还提供了一个可视化的管理工具 LiteDB Studio
,方便用户进行数据库的管理和操作。
以下是 LiteDB
的一些特点和用法介绍:
支持
Serverless NoSQL
文档存储和查询,类似于MongoDB
的简单API
。100% C#
代码,支持.NET 4.5/.NETStandard 1.3/2.0
,单DLL
(小于450 kb
)。支持
线程和进程安全
,多线程访问,提高数据的并发性能
。支持文档/操作级别的
ACID/事务
和索引
,保证数据的一致性和查询效率。支持写失败后的
数据还原 (日志模式)
。支持
多种数据类型
,包括字符串、整型、浮点型、日期时间、二进制数据等。支持
嵌套文档和数组
,方便存储复杂数据结构。支持
LINQ
查询,方便进行数据筛选和排序。支持
数据加密和压缩
,保证数据的安全性和存储效率。可使用
DES (AES)
加密算法进行数据文件加密。可使用特性或
fluent
映射API
将你的POCO
类映射为BsonDocument
。可存储文件与流数据 (类似
MongoDB
的GridFS
)。单数据文件存储 (类似
SQLite
)。支持基于文档字段索引的快速搜索 (每个集合支持多达
16
个索引)。Shell
命令行,在线版本尝试。开源
,对所有人免费
(包括商业应用)。
相关文档:
LiteDB
项目地址,https://github.com/mbdavid/LiteDBLiteDB
在线文档,https://dev.listera.top/docs/litedb/
LiteDB 安装
LiteDB
的安装和使用非常简单,只需要在项目中添加 LiteDB
的引用,就可以使用 LiteDB
的 API
进行数据库的操作。
nuget
地址:
https://www.nuget.org/packages/LiteDB
https://www.nuget.org/packages/LiteDB.Async
1、同步版 LiteDB
2、异步版 LiteDB.Async
此处我们选择 LiteDB.Async
异步版本安装。
1、命令方式安装:
.NET CLI
dotnet add package LiteDB.Async --version 0.1.7
Package Manager
NuGet\Install-Package LiteDB.Async --version 0.1.7
2、项目 Package
包依赖引用:
dotnet add package LiteDB.Async
或者添加
Package
包引用
<PackageReference Include="LiteDB.Async" Version="0.1.7" />
3、还可以从 NuGet
安装:
Install-Package LiteDB.Async
或者使用 vs
可视化窗体界面安装,如下两种方式:
选择 浏览
输入 LiteDB
点击搜索显示信息如下:
LiteDB Studio
同时,LiteDB
还提供了一个可视化的管理工具 LiteDB Studio
,方便用户进行数据库的管理和操作。
原文:A GUI tool for viewing and editing documents for LiteDB v5.
译文:用于查看和编辑
LiteDB v5
文档的GUI
工具。
这里我们选择 Shared
模式连接:
输入 sql
语句执行查询操作,显示如下:
Grid
显示
分组查询,并统计范围内指定字段的最大值和最小值。
Text
显示
执行代码初始化生产的 .db
文件非常的轻量,下图所示只有 16kb
:
LiteDB Studio
项目地址:
https://github.com/mbdavid/LiteDB.Studio
LiteDB CRUD 操作举例
1、.net cli 命令创建项目
这里我们模拟 WeatherForecast(天气预报)
的数据为例,使用 .net cli
创建项目如下:
dotnet new webapi -o WebAppLiteDb --no-https -f net8.0
提示:执行命令前,记得安装
.net8 sdk
。
查看
.net
信息
dotnet --info
2、项目添加相关 nuget 包
创建好模板 “ASP.NET Core Web API”
项目后,使用 Microsoft Visual Studio Community 2022 (64 位) IDE
打开项目,添加如下 nuget
包依赖:
项目 WebAppLiteDb
依赖的 nuget
包文件如下:
LiteDB.Async v0.1.7
(单纯LiteDB
操作只需要该包即可)Serilog.AspNetCore v8.0.0
Serilog.Sinks.LiteDB v1.0.29
Swashbuckle.AspNetCore v6.5.0
项目 WebAppLiteDb
的 Project
文件如下:
<Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<InvariantGlobalization>true</InvariantGlobalization>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="LiteDB.Async" Version="0.1.7" />
<PackageReference Include="Serilog.AspNetCore" Version="8.0.0" />
<PackageReference Include="Serilog.Sinks.LiteDB" Version="1.0.29" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.5.0" />
</ItemGroup>
<ItemGroup>
<Folder Include="Models\" />
<Folder Include="AppData\DataBase\" />
</ItemGroup>
</Project>
3、改造项目结构
查看项目 WebAppLiteDb
结构如下:
4、改造项目代码
文件 Program.cs
改造如下:
using Serilog;
const string OUTPUT_TEMPLATE = "{Timestamp:yyyy-MM-dd HH:mm:ss.fff} <{ThreadId}> [{Level:u3}] {Message:lj}{NewLine}{Exception}";
// creates custom collection `applog`
Log.Logger = new LoggerConfiguration()
.MinimumLevel.Information()
.Enrich.FromLogContext()
.WriteTo.Console(outputTemplate: OUTPUT_TEMPLATE)
.WriteTo.LiteDB(@"WebAppLiteDb\AppData\DataBase\logs.db", logCollectionName: "applog")
.CreateLogger();
var builder = WebApplication.CreateBuilder(args);
builder.Host.ConfigureAppConfiguration((hostingContext, config) => {
char b = Path.DirectorySeparatorChar; // 符号
string rootPath = hostingContext.HostingEnvironment.ContentRootPath;
string configPath = $"{rootPath}{b}AppData{b}Configuration";
config.SetBasePath(configPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{hostingContext.HostingEnvironment.EnvironmentName}.json", optional: true, reloadOnChange: true)
.AddEnvironmentVariables();
}).UseSerilog(Log.Logger, dispose: true);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseAuthorization();
app.MapControllers();
app.Run();
调整模型类 WeatherForecast.cs
文件到 Models
文件夹:
namespace WebAppLiteDb.Models;
public class WeatherForecast
{
public Guid Id { get; set; }
public DateOnly Date { get; set; }
public int TemperatureC { get; set; }
public int TemperatureF => 32 + (int)(TemperatureC / 0.5556);
public string? Summary { get; set; }
}
修改 appsettings.json
和 appsettings.Development.json
配置文件:
appsettings.json
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
appsettings.Development.json
{
"Logging": {
"LogLevel": {
"Default": "Debug",
"Microsoft.AspNetCore": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
}
}
Serilog 日志级别由低到高 (等级越低输出的日志信息越详细):
Verbose -> Debug -> Information -> Warning -> Error -> Fatal。
ILogger
对象用于记录日志,和其他日志框架差不多。
接下来我们改造控制器类文件,WeatherForecastController.cs
信息修改如下:
构造函数
DI
注入日志记录器。
private readonly ILogger<WeatherForecastController> _logger;
/// <summary>
/// 构造函数 DI 注入 ILogger
/// </summary>
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
新建一个字符串集合,模拟天气情况摘要。
/// <summary>
/// 模拟天气情况摘要
/// </summary>
private static readonly string[] Summaries = new[]
{
"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
};
连接 LiteDB
的操作,此处使用的 nuget
包是 LiteDB.Async
:
//打开数据库,如果不存在会自动创建。
var db = new LiteDatabaseAsync(_connectionString);
//打开一个表和 MongoDB 一样的
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
关于 litedb-async
该库允许将异步编程技术与
LiteDb
库一起使用。它适用于需要轻量级NoSQL
数据库或将受益于轻量级NoSQL
数据库的Xamarin
和WPF
应用程序,但也不想在数据库操作发生时打开和管理大量线程或阻止 UI。我们为您管理线程。在nuget
上可用,https://www.nuget.org/packages/LiteDB.Async/
添加关于
LiteDB
的CRUD
操作,代码如下:
#region About LiteDB CRUD
// 此处的连接字符串是临时写法,可以放入 appsetting.json 配置文件
private static readonly string _connectionString = "Filename=AppData/DataBase/LiteDBtest.db;Connection=shared;Password=123456";
// 方便记录下面 crud 方法执行的时间
private static readonly Stopwatch _sw = new();
/// <summary>
/// 单条数据添加
/// </summary>
/// <returns></returns>
[HttpPost(Name = "AddSingle")]
public async Task<Guid> AddSingleAsync()
{
// 模拟数据
var wf = new WeatherForecast
{
Id = Guid.NewGuid(),
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(1)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
};
_sw.Start();
//打开数据库,如果不存在会自动创建。
using var db = new LiteDatabaseAsync(_connectionString);
//打开一个集合和 MongoDB 一样的,类似关系数据库的表。
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
var item = await collection.InsertAsync(wf);
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[AddSingle] ==> 插入一条数据:{item.AsGuid},耗时:{ts.TotalMilliseconds}ms.");
return item.AsGuid;
}
/// <summary>
/// 批量数据添加
/// </summary>
/// <returns></returns>
[HttpPost(Name = "AddBulk")]
public async Task<int> AddBulkAsync(int conut)
{
if (conut <= 0) conut = 1000;
// 模拟数据
var wfs = Enumerable.Range(1, conut).Select(index => new WeatherForecast
{
Id = Guid.NewGuid(),
Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
TemperatureC = Random.Shared.Next(-20, 55),
Summary = Summaries[Random.Shared.Next(Summaries.Length)]
}).ToArray();
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
int rcount = await collection.InsertBulkAsync(wfs);
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[AddBulk] ==> 批量插入数据:{ rcount },耗时:{ ts.TotalMilliseconds }ms.");
return rcount;
}
/// <summary>
/// Id 查询单条数据
/// </summary>
/// <param name="id">Guid</param>
/// <returns></returns>
[HttpGet(Name = "GetSingle")]
public async Task<WeatherForecast> GetSingleAsync(Guid id)
{
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
var item = await collection.FindOneAsync(x => x.Id == id);
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[GetSingle] ==> 查询单条数据:{item.Id},耗时:{ts.TotalMilliseconds}ms.");
return item;
}
/// <summary>
/// 查询所有数据
/// </summary>
/// <returns></returns>
[HttpGet(Name = "GetAll")]
public async Task<IEnumerable<WeatherForecast>> GetAllAsync()
{
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
var list = await collection.FindAllAsync();
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[GetAll] ==> 查询所有数据:{list.Count()},耗时:{ts.TotalMilliseconds}ms.");
return list;
}
/// <summary>
/// 更新数据
/// </summary>
/// <param name="item"></param>
/// <returns></returns>
[HttpPut(Name = "UpdateSingle")]
public async Task<bool> UpdateSingleAsync([FromBody] WeatherForecast item)
{
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
bool isOk = await collection.UpdateAsync(item);
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[UpdateSingle] ==> 更新单条数据:{item.Id},耗时:{ts.TotalMilliseconds}ms.");
return isOk;
}
/// <summary>
/// 批量更新
/// </summary>
/// <param name="list"></param>
/// <returns></returns>
[HttpPut(Name = "UpdateBulk")]
public async Task<int> UpdateBulkAsync([FromBody] List<WeatherForecast> list)
{
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
int rcount = await collection.UpdateAsync(list);
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[UpdateSingle] ==> 批量更新数据:{rcount},耗时:{ts.TotalMilliseconds}ms.");
return rcount;
}
/// <summary>
/// Id 删除单条数据
/// </summary>
/// <param name="id">Guid</param>
/// <returns></returns>
[HttpDelete(Name = "DeleteSingle")]
public async Task<bool> DeleteSingleAsync(Guid id)
{
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
bool isOk = await collection.DeleteAsync(id);
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[DeleteSingle] ==> 删除单条数据:{id},耗时:{ts.TotalMilliseconds}ms.");
return isOk;
}
/// <summary>
/// 删除所有
/// </summary>
/// <returns></returns>
[HttpDelete(Name = "DeleteAll")]
public async Task<int> DeleteAllAsync()
{
_sw.Start();
using var db = new LiteDatabaseAsync(_connectionString);
var collection = db.GetCollection<WeatherForecast>(nameof(WeatherForecast));
int rcount = await collection.DeleteAllAsync();
_sw.Stop();
TimeSpan ts = _sw.Elapsed;
_logger.LogInformation($"[DeleteAll] ==> 删除多条数据:{rcount},耗时:{ts.TotalMilliseconds}ms.");
return rcount;
}
#endregion
关于
LiteDB & LiteDB.Async
的更多操作,请查看官方文档:
https://github.com/mbdavid/LiteDB
https://github.com/mlockett42/litedb-async
到这里项目结构就改造好了,此时我来启动项目运行看看,显示如下页面:
控制台输出日志信息如下:
执行上面的 CRUD
方法,日志信息(这里截取部分)记录执行时间如下:
2023-12-04 15:44:18.898 <> [INF] [AddSingle] ==> 插入一条数据:052816a8-607a-4682-b673-7ad21a588528,耗时:139.1579ms.
2023-12-04 15:44:32.010 <> [INF] [AddBulk] ==> 批量插入数据:1000,耗时:284.2237ms.
2023-12-04 15:45:05.059 <> [INF] [GetSingle] ==> 查询单条数据:000660df-7e70-4c32-9734-4e657e157509,耗时:306.4881ms.
2023-12-04 15:45:13.158 <> [INF] [GetAll] ==> 查询所有数据:2001,耗时:307.4817ms.
2023-12-04 15:45:51.955 <> [INF] [DeleteSingle] ==> 删除单条数据:000660df-7e70-4c32-9734-4e657e157509,耗时:426.993ms.
2023-12-04 15:46:05.279 <> [INF] [DeleteAll] ==> 删除多条数据:2000,耗时:670.6834ms.
注意:
LiteDB
单次批量数据写入是1000
条。
说明:更新方法参数需要拼接实体模型,此处就不在拼接测试,上面的方法执行有效,感兴趣的可以自行拼接实体模型参数测试。
LiteDB vs SQLite 对比
说到 LiteDB
数据库,这里不得不提一个类似的数据库 —— SQLite
,它俩数据库很类似,但是定位又各不相同:
Item | LiteDB | SQLite |
---|---|---|
文件类型 | Single data file | Single data file |
数据库类型 | Serverless NoSQL | Serverless relational database |
事务支持/ACID | 通过 Transaction 类来控制 | 通过 BEGIN、COMMIT 和 ROLLBACK 语句来控制 |
稳定性 & 性能 | 较高 | 高 |
编写语言 | C#/CSharp | C |
跨平台支持 | 是 | 是 |
开源协议 | MIT ,https://github.com/mbdavid/LiteDB/blob/master/LICENSE | https://github.com/sqlite/sqlite/blob/master/LICENSE.md,https://www.sqlite.org/copyright.html |
官方文档:
SQLite
,https://www.sqlite.org/LiteDB
,https://www.litedb.org/
说明:下面几个对比问题均由
CSDN
平台提供的C知道
回答,仅供参考。
1、谈谈 sqlite 和 litedb 的 ACID 事务支持?
SQLite
和 LiteDB
都支持 ACID
事务,其中 ACID
是指原子性(Atomicity
)、一致性(Consistency
)、隔离性(Isolation
)和持久性(Durability
)。
在
SQLite
中,事务是通过BEGIN、COMMIT
和ROLLBACK
语句来控制的。SQLite
默认使用自动提交模式,也就是说,每个SQL
语句都会被立即提交。如果需要使用事务,可以使用BEGIN
语句来开始一个事务,使用COMMIT
语句来提交事务,或者使用ROLLBACK
语句来回滚事务。SQLite
支持四种隔离级别:SERIALIZABLE、REPEATABLE READ、READ COMMITTED和READ UNCOMMITTED
。在
LiteDB
中,事务是通过Transaction
类来控制的。可以使用Transaction
类的Begin
方法来开始一个事务,使用Commit
方法来提交事务,或者使用Rollback
方法来回滚事务。LiteDB
支持两种隔离级别:READ UNCOMMITTED和SNAPSHOT
。
总的来说,SQLite
和 LiteDB
都支持 ACID
事务,但是 SQLite
在大型项目中可能会存在性能问题,而 LiteDB
则更适合单机小游戏等小型项目。
2、谈谈 sqlite 和 litedb 的稳定性和可靠性?
SQLite
和 LiteDB
都是轻量级数据库,它们的稳定性和可靠性都非常高。SQLite
是一个嵌入式数据库,它的数据存储在单个文件中,因此非常适合嵌入式设备和移动应用程序。SQLite
的稳定性和可靠性得到了广泛的认可,它已经被广泛地应用于各种应用程序中,包括谷歌的 Android
操作系统。LiteDB
是一个 .NET
平台上的嵌入式 NoSQL
文档数据库,它的数据存储在单个文件中,非常适合 .NET
应用程序。LiteDB
的稳定性和可靠性也非常高,它已经被广泛地应用于各种 .NET
应用程序中。
3、谈谈 sqlite 和 litedb 的应用场景?
SQLite
和 LiteDB
都是轻量级的嵌入式数据库,适用于一些小型应用场景。其中,SQLite
是一种关系型数据库,支持 SQL
语句,适用于需要高度可靠性和稳定性的应用场景,例如浏览器、操作系统等。而 LiteDB
则是一种文档型数据库,支持类似 MongoDB
的文档查询语法,适用于需要快速开发和部署的小型应用场景,例如单机小游戏、桌面应用等。
LiteDB vs SQLite 性能测试
这里有一个 LiteDB v3
版本和 SQLite
的性能测试对比。
LiteDB-Perf
项目地址:
https://github.com/mbdavid/LiteDB-Perf
A simple actions to compare SQLite and LiteDB v3.
Results
(测试结果):
Low is better
(测试结果,时间越短越好)
参数项对比说明:
Item | LiteDB | SQLite |
---|---|---|
#1 | Default | Default |
#2 | Encrypted | Encrypted |
#3 | Exclusive mode and no journal | No journal |
测试主机说明:
原文:Tested on MacBook Pro 2012 i5, Win10, 8Gb RAM, SSD.
译文:在
MacBook Pro 2012 i5、Win10、8Gb RAM、SSD
上测试。
此处我们使用的是 LiteDB v5.x
版本,对于上面的 sqlite
和 litedb
性能测试,感兴趣的小伙伴可以参照上面测试例子自行测试。
更多推荐
所有评论(0)