65.9K
CodeProject 正在变化。 阅读更多。
Home

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

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.94/5 (13投票s)

2019 年 2 月 4 日

CPOL

4分钟阅读

viewsIcon

26047

一款新发布的开源 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);

第一种方法更快,因为无需解析表达式树。

在大多数关系数据库中,我们使用两个不同的操作:INSERTUPDATE。在 Cachalot DB 中,只提供一个操作:PUT

它将插入新项目(新主键)并更新现有项目。

您对现代数据库的期望可能不仅仅是按主键存储和检索对象。您是对的。

其他类型的索引及其使用方法

需要理解索引的三个特性。

1. 索引数据类型

为了能在 Cachalot DB 中被索引,.NET 属性需要能转换为 Int64string

使用整数类型可以稍微加快搜索速度。

为以下类型提供了自动转换为 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日:初始版本
© . All rights reserved.