Partager via

将弹性数据库客户端库与 Dapper 配合使用

适用于:Azure SQL 数据库

本文档面向依赖于使用 Dapper 生成应用程序,但同时想要运用弹性数据库工具创建应用程序来实现分片,以横向扩展其数据层的开发人员。 本文档说明了与弹性数据库工具集成所需的基于 Dapper 的应用程序发生的更改。 我们将重点介绍如何使用 Dapper 构建弹性数据库分片管理和数据依赖型路由。

示例代码Azure SQL 数据库的弹性数据库工具 - Dapper 集成

集成 DapperDapperExtensions 与 Azure SQL 数据库弹性数据库客户端库非常简单。 将新 SqlConnection 对象的创建和打开方式更改为使用来自客户端库OpenConnectionForKey 调用,应用程序即可使用数据依赖型路由。 这将把应用程序中的更改限制在仅创建和打开新连接的位置。

Dapper 概述

Dapper 是对象关系映射器。 它将应用程序中的 .NET 对象映射到关系型数据库,反之亦然。 示例代码的第一个部分演示了如何将弹性数据库客户端库与基于 Dapper 的应用程序相集成。 示例代码的第二个部分演示了同时使用 Dapper 和 DapperExtensions 时如何集成。

Dapper 中的映射器功能对数据库连接提供扩展方法,可以简化用于执行或查询数据库的 T-SQL 语句的提交。 例如,Dapper 使你可以轻松地在 .NET 对象与 SQL 语句的参数之间进行映射以进行 Execute 调用,或使用来自 Dapper 的调用将 SQL 查询的结果用于 .NET 对象 Query

使用 DapperExtensions 时,不再需要提供 SQL 语句。 扩展方法(例如 GetListInsert 通过数据库连接)在后台创建 SQL 语句。

Dapper 和 DapperExtensions 的另一个优点在于,应用程序可以控制数据库连接的创建。 这有助于与弹性数据库客户端库交互,该库通过将 shardlet 映射到数据库来管理数据库连接。

若要获取 Dapper 程序集,请参阅 Dapper .NET。 有关 Dapper 扩展,请参阅 DapperExtensions

弹性数据库客户端库速览

重要

2027 年 3 月 31 日,使用EXTERNAL DATA SOURCE类型SHARD_MAP_MANAGER的分片映射管理器模式下的弹性查询即将结束支持。 在此日期之后,现有工作负荷将继续运行,但将不再获得支持,并且将不再能够创建新的类型 SHARD_MAP_MANAGER 外部数据源。 有关迁移选项,请参阅 弹性查询分片映射管理器模式的迁移指南

使用弹性数据库客户端库,可以定义应用程序数据的分区(称为 shardlet),将它们映射到数据库,并根据分片键来识别这些分区 。 可以根据需要创建任意数量的数据库,并在这些数据库之间分配碎片数据。 分片键值到数据库的映射存储在由库的 API 提供的分片图中。 此功能称为 分片映射管理。 分片映射还为带有分片键的请求充当数据库连接的代理。 此功能称为数据依赖型路由。

分片映射和数据依赖型路由。

分片映射管理器可防止用户看到对 shardlet 数据的不一致视图,这种情况可能会在数据库上发生并发 shardlet 管理操作时出现。 为此,分片映射会代理使用库生成的应用程序的数据库连接。 当分片管理操作可能会影响子分片时,分片映射功能能够自动终止数据库连接。

需要使用 OpenConnectionForKey 方法,而不是使用传统方法来创建 Dapper 的连接。 这可确保所有验证都会发生,并在分片之间移动任何数据时正确管理连接。

Dapper 集成的要求

在使用弹性数据库客户端库和 Dapper API 时,希望保留以下属性:

  • 横向扩展:我们需要根据应用程序的容量需求,在分片应用程序的数据层中添加或删除数据库。
  • 一致性:由于应用程序是使用分片横向扩展的,因此需要执行数据依赖型路由。 我们需要使用库的数据依赖型路由功能来实现此目的。 特别是,您要保留通过分片映射管理器中转的连接所提供的验证和一致性保证,以避免数据损坏或查询结果错误。 这确保了如果(例如)当前使用 Split/Merge API 将 shardlet 移动到其他分片,则与该 shardlet 的连接将被拒绝或停止。
  • 对象映射:我们需要保留 Dapper 为了在应用程序中的类和基础数据库结构之间进行转换而提供的映射方便性。

以下部分提供基于 DapperDapperExtensions 的应用程序的这些要求的指导。

技术指南

使用 Dapper 的数据依赖路由

使用 Dapper 时,应用程序通常负责创建和打开与基础数据库的连接。 根据应用程序的类型 T ,Dapper 将查询结果作为类型的 T.NET 集合返回。 Dapper 执行从 T-SQL 结果行到类型 T对象的映射。 同样,Dapper 会将 .NET 对象映射到数据作语言 (DML) 语句的 SQL 值或参数中。 Dapper 通过 ADO.NET SQL 客户端库中常规 SqlConnection 对象的扩展方法提供此功能。 DDR 弹性缩放 API 返回的 SQL 连接也是常规 SqlConnection 对象。 这样,我们便可以针对客户端库的 DDR API 返回的类型直接使用 Dapper 扩展,因为它也是一个简单的 SQL 客户端连接。

根据这些观察结果,可以方便地使用通过弹性数据库客户端库代理的 Dapper 连接。

此代码示例(摘自随附的示例)演示了应用程序在库中提供分片键,以将连接中转到正确分片的方案。

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                     key: tenantId1,
                     connectionString: connStrBldr.ConnectionString,
                     options: ConnectionOptions.Validate))
    {
        var blog = new Blog { Name = name };
        sqlconn.Execute(@"
                      INSERT INTO
                            Blog (Name)
                            VALUES (@name)", new { name = blog.Name }
                        );
    }

调用 OpenConnectionForKey API 会替换 SQL 客户端连接的默认创建和打开方法。 OpenConnectionForKey 调用所需参数用于数据依赖型路由:

  • 用于访问数据依赖型路由接口的分片映射
  • 用于识别 shardlet 的分片键
  • 用于连接数据分片的凭据(用户名和密码)

分片映射对象会与保存给定分片键 shardlet 的分片建立连接。 弹性数据库客户端 API 还会标记连接以实现一致性保证。 由于对 OpenConnectionForKey 的调用返回常规 SQL 客户端连接对象,因此从 Dapper 对扩展方法的后续调用 Execute 遵循标准的 Dapper 做法。

查询的工作方式非常类似 - 首先从客户端 API 使用 OpenConnectionForKey 打开连接。 然后,可以使用常规 Dapper 扩展方法将 SQL 查询的结果映射到 .NET 对象:

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                    key: tenantId1,
                    connectionString: connStrBldr.ConnectionString,
                    options: ConnectionOptions.Validate ))
    {
           // Display all Blogs for tenant 1
           IEnumerable<Blog> result = sqlconn.Query<Blog>(@"
                                SELECT *
                                FROM Blog
                                ORDER BY Name");

           Console.WriteLine("All blogs for tenant id {0}:", tenantId1);
           foreach (var item in result)
           {
                Console.WriteLine(item.Name);
            }
    }

将块与 DDR 连接一起使用会将块中的所有数据库操作划归到保存 tenantId1 的一个分片。 该查询仅返回当前分片中存储的博客,而不是任何其他分片中存储的博客。

数据依赖型路由与 Dapper 和 DapperExtensions

Dapper 自带一个生态系统,其中包含额外的扩展,它们可以在开发数据库应用程序时提供更大的便利性和抽象数据库的功能。 DapperExtensions 就是一个示例。

在应用程序中使用 DapperExtensions 不会更改创建和管理数据库连接的方式。 应用程序仍要负责打开连接,并且扩展方法要求使用常规 SQL 客户端连接对象。 我们可以依赖于上述 OpenConnectionForKey。 如以下代码示例所示,唯一的变化是不再需要编写 T-SQL 语句:

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                    key: tenantId2,
                    connectionString: connStrBldr.ConnectionString,
                    options: ConnectionOptions.Validate))
    {
           var blog = new Blog { Name = name2 };
           sqlconn.Insert(blog);
    }

下面是查询的代码示例:

    using (SqlConnection sqlconn = shardingLayer.ShardMap.OpenConnectionForKey(
                    key: tenantId2,
                    connectionString: connStrBldr.ConnectionString,
                    options: ConnectionOptions.Validate))
    {
           // Display all Blogs for tenant 2
           IEnumerable<Blog> result = sqlconn.GetList<Blog>();
           Console.WriteLine("All blogs for tenant id {0}:", tenantId2);
           foreach (var item in result)
           {
               Console.WriteLine(item.Name);
           }
    }

处理临时故障

Microsoft 模式和实践团队发布了暂时性故障处理应用程序块,以帮助应用程序开发人员消除在云中运行应用程序时遇到的常见暂时性故障状态。 有关详细信息,请参阅成功的秘诀在于坚持:使用瞬时故障处理模块

该代码示例依赖于暂时性故障库来防止暂时性故障。

    SqlDatabaseUtils.SqlRetryPolicy.ExecuteAction(() =>
    {
       using (SqlConnection sqlconn =
          shardingLayer.ShardMap.OpenConnectionForKey(tenantId2, connStrBldr.ConnectionString, ConnectionOptions.Validate))
          {
              var blog = new Blog { Name = name2 };
              sqlconn.Insert(blog);
          }
    });

上述代码中的 SqlDatabaseUtils.SqlRetryPolicy 定义为 SqlDatabaseTransientErrorDetectionStrategy,重试计数为 10,每两次重试的等待时间为 5 秒。 如果正在使用事务,请确保在出现暂时性故障的情况下重试范围可以恢复为事务开始时间。

限制

本文档中概述的方法存在一些限制:

  • 本文档示例代码未演示如何管理不同分片的架构。
  • 对于给定的请求,我们假设其所有数据库处理均在由该请求提供的分片键所标识的单个分片内完成。 但是,这种假设并不总是成立,比如当无法提供分片键时。 为了解决此问题,弹性数据库客户端库包含了 MultiShardQuery 类。 该类实现了一个连接抽象用于查询多个分片。 MultiShardQuery 与 Dapper 的结合使用超出了本文档的讨论范围。

结论

使用 Dapper 和 DapperExtensions 的应用程序很容易从 Azure SQL 数据库的弹性数据库工具受益。 通过本文档中所述的步骤,这些应用程序可以使用该工具的功能,通过将新 SqlConnection 对象的创建和打开方式更改为使用弹性数据库客户端库的 OpenConnectionForKey 调用,来实现数据依赖型路由。 这会将应用程序更改限制为创建和打开新连接的地方。

尚未使用弹性数据库工具? 请查看入门指南