文档数据库是一种用于存储、检索和管理文档的数据存储系统。与传统的关系型数据库不同,文档数据库以文档为中心,每个文档可以包含复杂的结构,如嵌套对象、数组等。这种数据库适合存储半结构化或非结构化数据,如JSON、XML等格式的数据。RavenDB是一个开源的文档数据库,它提供了丰富的功能,包括数据索引、分区(sharding)等,以满足不同场景下的数据存储需求。
在没有使用过文档数据库的情况下,最简单的理解方式是将其想象为将对象序列化后存储在硬盘上,应用程序所在的位置上。如果使用键或者任何最常用的查找方法来存储,那么检索整个对象将变得非常简单,无需映射到SQL数据库中的列和行。处理进一步的查找方式、并发等问题会更加困难,因此产生了文档数据库。存储的文档不一定需要是序列化的对象(可以独立于对象存储任意文档),但那可能是最常见的使用方式。请记住,这是一种完全不同的数据存储方式,所以不应该总是像处理SQL数据库那样来处理它。
下面是一个简单的示例,展示了如何在RavenDB中存储两个任意的POCO对象,查询它们并将一些信息打印到屏幕上。在这个示例中,RavenDB服务器和客户端位于同一台机器上,但这不是必须的(接下来会有更多相关内容)。注意,不需要创建表,不需要将列和类映射到表,也不需要创建任何存储过程。Company类甚至没有标记为可序列化的——它就是可以工作。
还请注意,创建DocumentStore对象应该被视为昂贵的操作,类似于在NHibernate中创建会话工厂。目前还不是这样,但有未来的工作计划可能会改变这一点。
启动服务器并运行上述示例时,将看到服务器上的输出与上述类似(使用log4net,因此控制台日志可以关闭或重定向到文件,如果需要的话)。这里有很多有趣的事情。首先,注意它不是提交两个命令,而是将它们批量处理并一次性提交给SaveChanges()调用。其次,在批量操作之后,它开始处理适用于已保存文档的索引,并能够查询并返回这些文档。
除了上面展示的客户端/服务器方法之外,如果不需要分布式架构,还可以将服务器功能直接嵌入到应用程序中。
一旦Raven服务器运行,可以通过浏览器访问它以检查其内容、索引并查看文档。甚至可以使用浏览器编辑文档和索引定义。
可能已经注意到了,在上述简单示例中的查询方法调用了"WaitForNonStaleResults"。当设计使用索引的系统时,可以采取几种方法:
RavenDB出于性能原因采取了第三种选择,但如果想让它等待,可以使用WaitForNonStaleResults方法。如果没有包含该方法,并且在插入和读取之间发生了任何其他操作(因为索引更新时间往往在几十毫秒内),它仍然可以工作。通常,获取陈旧数据,同时索引更新,并在下一次视图或查询中获取更新的数据,这样更足够且成本更低。
可以使用Web UI或以编程方式创建或编辑索引。这里将展示如何使用Web UI添加新索引,并使用该索引进行查询。
首先,使用LINQ语法创建索引:
// 示例代码
var index = new IndexCreation.CreateIndexDefinition<Company>()
{
Map = companies => from company in companies
select new
{
company.Name,
company.Employees
}
};
index.Execute(_documentStore);
然后,使用Lucene语法编写一个使用该索引的查询:
// 示例代码
var companies = _documentStore.DatabaseCommands.Query<Company>("CompanyIndex", new IndexQuery
{
Query = "Employees:5",
PageSize = 10
}).ToList();
服务器将识别索引的存在,并使用Lucene通过它获取更小的结果集,而不是扫描所有项目。
Raven DB还支持分片,即将数据分区到多台服务器上。例如,如果知道许多公司分布在多个区域,并且希望某些区域在一台服务器上,其他区域在另一台服务器上,可以实现这一点。分片的设计基于Hibernate Shards,所以如果熟悉它,会注意到一些相似之处。
下面是一个使用分片的示例(包含在RavenDB源代码中的示例项目):
// 示例代码
public class CompanyShardingStrategy : IShardStrategy
{
public ShardAccessor GetShardAccessor()
{
return new ShardAccessor(new ShardAccessorOptions
{
ShardSelectionStrategy = new CompanyShardSelectionStrategy(),
ShardAccessStrategy = new ParallelShardAccessStrategy()
});
}
}
使用分片时,必须想出规则来按分区划分数据。在这个示例中,将假设有2个分片,区域A的公司去分片1,区域B的公司去分片2。为了实现这一点,将创建一个具体实例,实现IShardStrategy,定义3部分的分片行为:
ParallelShardAccessStrategy使用了.NET 4.0中的新Tasks功能。下面是同时查询所有分片的代码:
// 示例代码
var results = shardAccessor.Query<Company>(q => q
.WaitForNonStaleResults()
.Where(x => x.Name == "Company Name")
).ToList();
还有一个实现expando对象的代码,它允许动态访问JSON对象:
// 示例代码
dynamic company = new ExpandoObject();
company.Name = "New Company";
company.Employees = 50;
_documentStore.Store((object)company);
查看源代码以获取更多示例和详细信息。
要运行这里显示的示例,请下载源代码zip文件,在VS 2010中打开并构建解决方案。运行Raven.Server以启动服务器,然后启动简单的客户端示例,取消注释初始代码,以便最初将数据插入数据库,以便用一些数据填充它。要运行分片示例,需要复制Raven.Server bin目录并更改其配置,以便它在不同的端口上监听,以便可以在同一台机器上同时运行两个服务器(或使用另一台机器)。第一次运行服务器时,如果它检测到没有访问端口的权限,它将授予权限,这将提示进行管理员访问。
产品中的功能远不止在这里展示的——要查看其余部分,请查看代码。源代码存储库在github上,网址为http://github.com/ravendb/ravendb——但当前的源代码和示例代码包含在文章中。如果想贡献,可以使用git获取所有代码,或者使用github在上述链接处提供的"下载源代码"按钮下载所有需要的文件。还会在github上找到一个问题列表,所以如果想跳进去并帮助解决一个小问题以熟悉使用git和VS 2010,那就去做吧。
另外,请参阅Oren的博客,它包括许多与Raven相关的帖子,因为它正在构建,提供了一些设计决策的见解等。
以下是在Windows机器上本地运行git的说明。
// 示例代码
git clone https://github.com/ravendb/ravendb.git
cd ravendb
git checkout develop
到目前为止,使用Git GUI对来说很有用(与命令行相比),即使在使用一些更复杂的场景,如创建和合并分支时也是如此。只是了解一下git分支的命令行指令很有帮助,这样就知道术语了,这与VSS/TFS/SVN非常不同。