Cachalot DB - .NET 应用程序的极速事务数据库 - 第一部分






4.94/5 (13投票s)
一款新发布的开源 NoSQL 数据库,适用于 .NET(经典版或 Core 版)。已在生产环境中投入使用。
什么是 Cachalot DB?
Cachalot DB 是一款极速、开源、No SQL、完全事务性的 .NET 应用程序数据库。它支持分布式部署,并能随节点数量线性扩展。在单个节点上,您可以在一台配置适中的机器上每秒持久化插入五万个对象。它提供了强大的 LINQ 提供程序和管理控制台。此外,它还可以用作功能强大、支持事务、分布式的缓存,并具有独特的功能。
完整的开源代码可在
预编译的二进制文件和完整文档可在以下位置获取:
客户端代码作为 nuget 包在 nuget.org 上可用。
安装:Install-Package Cachalot.Client
接下来的部分将提供更多细节,但…
先看代码
让我们准备好业务对象以供数据库存储。
我们从一个允许个人之间租赁房屋的简易网站开始。
房产的简单描述如下:
public class Home
{
public string CountryCode { get; set; }
public string Town { get; set; }
public string Adress { get; set; }
public string Owner { get; set; }
public string OwnerEmail { get; set; }
public string OwnerPhone { get; set; }
public int Rooms { get; set; }
public int Bathrooms { get; set; }
public int PriceInEuros { get; set; }
}
业务对象的第一个要求是拥有一个主键。在这种情况下没有“自然”主键,因此我们将添加一个数字 Id。
public class Home
{
[PrimaryKey(KeyDataType.IntKey)]
public int Id { get; set; }
°°°
}
现在,该对象可以存储在数据库中了。
第一步是实例化一个 Connector
,它需要一个客户端配置。稍后会详细介绍配置,但目前,它需要包含集群中的服务器列表。为了开始,我们将在本地运行一个。
配置通常从外部文件读取。目前,我们手动构建它。
var config = new ClientConfig
{
Servers = {new ServerConfig {Host = "localhost", Port = 4848}}
};
using (var connector = new Cachalot.Linq.Connector(config))
{
var homes = connector.DataSource<Home>();
// the rest of the code goes here
}
在将对象存储到数据库之前,还有最后一步。我们需要为主键生成一个唯一值。一次调用可以生成多个唯一值。
与其他数据库不同,您不需要显式创建唯一值生成器。第一次调用一个新生成器名称时,它会自动创建。
var ids = connector.GenerateUniqueIds("home_id", 1);
var home = new Home
{
Id = ids[0],
Adress = "14 rue du chien qui fume",
Bathrooms = 1,
CountryCode = "FR",
PriceInEuros = 125,
Rooms = 2,
Town = "Paris"
};
homes.Put(home);
现在,您的第一个对象已安全地存储在数据库中。
目前,您只能通过主键检索它。这可以通过两种等效的方式完成。
var reloaded = homes[home.Id];
或者使用 LINQ 表达式。
var reloaded = homes.First(h => h.Id == home.Id);
第一种方法更快,因为无需解析表达式树。
在大多数关系数据库中,我们使用两个不同的操作:INSERT
和 UPDATE
。在 Cachalot
DB 中,只提供一个操作:PUT
。
它将插入新项目(新主键)并更新现有项目。
您对现代数据库的期望可能不仅仅是按主键存储和检索对象。您是对的。
其他类型的索引及其使用方法
需要理解索引的三个特性。
1. 索引数据类型
为了能在 Cachalot
DB 中被索引,.NET 属性需要能转换为 Int64
或 string
。
使用整数类型可以稍微加快搜索速度。
为以下类型提供了自动转换为 Int64
的功能:
- 所有数字类型
DateTime 和 DateTimeOffset
- 枚举类型
- 布尔值
通过调用属性值的 ToString()
来转换为 string
。
2. 索引类型
有三种类型的索引属性可用:
- 主键(唯一必需的)
- 唯一键:每个类型可以定义零个或多个
- 索引键:每个类型可以定义零个或多个
3. 顺序索引
对于任何索引,我们都可以应用相等运算符。
如果一个索引被声明为“有序”,那么所有比较运算符都可以同样应用:<, <=, >, >=
这种类型的索引对于大多数现代系统至关重要,但请注意,它是有成本的,因为有序索引必须始终排序。
大规模 insert
/update
操作(DataStore.PutMany
方法)经过了良好的优化。达到阈值(默认为 50 个项目)后,操作将被视为“批量插入”。有序索引只在最后排序一次。
更多代码:为房产添加索引
public class Home
{
[PrimaryKey(KeyDataType.IntKey)]
public int Id { get; set; }
[Index(KeyDataType.StringKey)]
public string CountryCode { get; set; }
[Index(KeyDataType.StringKey)]
public string Town { get; set; }
public string Adress { get; set; }
public string Owner { get; set; }
public string OwnerEmail { get; set; }
public string OwnerPhone { get; set; }
[Index(KeyDataType.IntKey, or dered:true)]
public int Rooms { get; set; }
[Index(KeyDataType.IntKey)]
public int Bathrooms { get; set; }
[Index(KeyDataType.IntKey, ordered:true)]
public decimal PriceInEuros { get; set; }
}
使用像这样索引的对象,您现在可以进行一些有用的查询了。
var results = homes.Where(p => p.PriceInEuros <= 200 &&
p.Rooms > 1 &&
p.Town == "Paris").Take(10);
当然,查询是在服务器端执行的,包括 take
运算符。最多,只有十个对象会通过网络传输到客户端。
“Contains
” 扩展方法也受支持。
var towns = new[] {"Paris", "Nice"};
var one = homes.First(p => p.PriceInEuros < 150 && towns.Contains(p.Town));
这相当于 SQL:
SELECT * from HOME where PriceInEuros < 150 and Town IN (“Paris”, “Nice”)
“Contains
” 扩展的另一个用法(在传统 SQL 中没有直接对应)将在下一节中说明。
索引集合属性
让我们丰富我们的业务对象。能够拥有每栋房屋的可用日期列表将会很有用。
添加这个新属性可以实现一些有趣的功能。
这是一个集合属性,可以与标量属性以相同的方式进行索引。
[Index(KeyDataType.IntKey)]
public List<DateTime> AvailableDates { get; set; } = new List<DateTime>();
我们希望能够搜索在特定日期可用的房屋。
var availableNextWeek = homes.Where(
p => p.Town == "Paris" &&
p.AvailableDates.Contains(DateTime.Today.AddDays(7))
).ToList();
这在经典 SQL 数据库中没有直接的对应。它巧妙地取代了经典 JOIN
运算符的大部分用法。
您可能需要动态生成查询。例如,在搜索屏幕中,您会添加条件来限制结果。这可以通过链式调用 Where
方法来实现。
var query = homes.Where(p => p.Town == "Paris");
query = query.Where(p => p.PriceInEuros < 200);
query = query.Where(p => p.Rooms > 1);
query = query.Where(p => p.AvailableDates.Contains(DateTime.Today));
var result = query.ToList();
这相当于一个单一的查询,其中所有条件都用 &&
(AND) 运算符连接。
这只是一个简短的介绍。完整的用户指南,包括管理部分,可在以下网址找到:
该系列的第二部分可在 这里 找到。
历史
- 2019年2月4日:初始版本