Functions 的Azure SQL触发器

Azure SQL触发器使用 SQL change tracking 功能监视 SQL 表的更改,并在创建、更新或删除行时触发函数。 有关用于Azure SQL触发器的change tracking的配置详细信息,请参阅 设置 change tracking。 有关 Azure Functions Azure SQL 扩展的设置详细信息,请参阅 SQL 绑定概述

Azure SQL触发Consumption 和 Premium 计划的缩放决策是通过基于目标的缩放完成的。 有关详细信息,请参阅基于Target 的缩放并查看Azure Functions托管选项

注意

对消耗计划的支持需要 release v3.1.284 或更高版本Azure SQL绑定Azure Functions

功能概述

Azure SQL触发器绑定使用轮询loop来检查更改,在检测到更改时触发用户函数。 概括而言,loop如下所示:

while (true) {
    1. Get list of changes on table - up to a maximum number controlled by the Sql_Trigger_MaxBatchSize setting
    2. Trigger function with list of changes
    3. Wait for delay controlled by Sql_Trigger_PollingIntervalMs setting
}

更改始终按照执行顺序进行处理,首先处理最早的更改。 有关更改处理的几点注意事项:

  1. 如果一次更改多个行,则发送到函数的确切顺序取决于 CHANGETABLE 函数返回的顺序
  2. 一行的更改同时进行“批处理”。 如果对loop每次迭代之间的行进行了多次更改,则该行只存在一个更改条目,该行将显示上次处理状态与当前状态之间的差异
  3. 如果对一组行进行了更改,然后对其中一半相同的行进行了另一组更改,则将首先处理未进行第二次更改的那一半行。 这样的处理逻辑是由于上述说明以及正在批处理的更改 - 触发器只会看到所做的“最后”更改,并根据它们来确定处理顺序

注意

Azure SQL change tracking可以检测使用加密技术(例如Always Encrypted或Transparent Data Encryption(TDE)的表中的行级更改。 但是,Azure SQL触发器不会解密或公开更改有效负载中的加密列值。 触发器可以检测到发生了更改,但无法access这些列的解密数据。

有关change tracking以及如何由应用程序(如Azure SQL触发器)使用的详细信息,请参阅 使用 change tracking

重要

为获得最佳安全性,应将Microsoft Entra ID与托管标识配合使用,以便在 Functions 与 Azure SQL Database 之间建立连接。 托管标识可以让应用更安全,因为不需在应用部署中存储机密,例如连接字符串、服务器名称、所使用端口中的凭据。 可以了解如何在本教程中使用托管标识,连接函数应用以使用托管标识和 SQL 绑定Azure SQL

用法示例

GitHub 存储库提供了有关Azure SQL触发器的更多示例。

这些示例引用 ToDoItem 类和相应的数据库表:

namespace AzureSQL.ToDo
{
    public class ToDoItem
    {
        public Guid Id { get; set; }
        public int? order { get; set; }
        public string title { get; set; }
        public string url { get; set; }
        public bool? completed { get; set; }
    }
}
CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

Change tracking在数据库和表上启用:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

SQL 触发器绑定到 IReadOnlyList<SqlChange<T>>,即 SqlChange 对象列表,每个对象具有 2 个属性:

  • 项:已更改的项。 项的类型应遵循 ToDoItem 类中所示的表架构。
  • 操作:SqlChangeOperation 枚举中的值。 可能的值为 InsertUpdateDelete

以下示例显示了在 表发生更改时调用的 ToDo

using System;
using System.Collections.Generic;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Extensions.Sql;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;


namespace AzureSQL.ToDo
{
    public static class ToDoTrigger
    {
        [Function("ToDoTrigger")]
        public static void Run(
            [SqlTrigger("[dbo].[ToDo]", "SqlConnectionString")]
            IReadOnlyList<SqlChange<ToDoItem>> changes,
            FunctionContext context)
        {
            var logger = context.GetLogger("ToDoTrigger");
            foreach (SqlChange<ToDoItem> change in changes)
            {
                ToDoItem toDoItem = change.Item;
                logger.LogInformation($"Change operation: {change.Operation}");
                logger.LogInformation($"Id: {toDoItem.Id}, Title: {toDoItem.title}, Url: {toDoItem.url}, Completed: {toDoItem.completed}");
            }
        }
    }
}

用法示例

GitHub 存储库提供了有关Azure SQL触发器的更多示例。

该示例引用 ToDoItem 类、SqlChangeToDoItem 类、SqlChangeOperation 枚举和相应的数据库表:

在单独的 ToDoItem.java 文件中:

package com.function;
import java.util.UUID;

public class ToDoItem {
    public UUID Id;
    public int order;
    public String title;
    public String url;
    public boolean completed;

    public ToDoItem() {
    }

    public ToDoItem(UUID Id, int order, String title, String url, boolean completed) {
        this.Id = Id;
        this.order = order;
        this.title = title;
        this.url = url;
        this.completed = completed;
    }
}

在单独的 SqlChangeToDoItem.java 文件中:

package com.function;

public class SqlChangeToDoItem {
    public ToDoItem item;
    public SqlChangeOperation operation;

    public SqlChangeToDoItem() {
    }

    public SqlChangeToDoItem(ToDoItem Item, SqlChangeOperation Operation) {
        this.Item = Item;
        this.Operation = Operation;
    }
}

在单独的 SqlChangeOperation.java 文件中:

package com.function;

import com.google.gson.annotations.SerializedName;

public enum SqlChangeOperation {
    @SerializedName("0")
    Insert,
    @SerializedName("1")
    Update,
    @SerializedName("2")
    Delete;
}
CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

Change tracking在数据库和表上启用:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

SQL 触发器绑定到 SqlChangeToDoItem[],即 SqlChangeToDoItem 对象数组,每个对象具有 2 个属性:

  • 项:已更改的项。 项的类型应遵循 ToDoItem 类中所示的表架构。
  • 操作: 枚举中的值。 可能的值为 InsertUpdateDelete

以下示例显示了在 ToDo 表发生更改时调用的 Java 函数:

package com.function;

import com.microsoft.azure.functions.ExecutionContext;
import com.microsoft.azure.functions.annotation.FunctionName;
import com.microsoft.azure.functions.sql.annotation.SQLTrigger;
import com.function.Common.SqlChangeToDoItem;
import com.google.gson.Gson;

import java.util.logging.Level;

public class ProductsTrigger {
    @FunctionName("ToDoTrigger")
    public void run(
            @SQLTrigger(
                name = "todoItems",
                tableName = "[dbo].[ToDo]",
                connectionStringSetting = "SqlConnectionString")
                SqlChangeToDoItem[] todoItems,
            ExecutionContext context) {

        context.getLogger().log(Level.INFO, "SQL Changes: " + new Gson().toJson(changes));
    }
}

用法示例

GitHub 存储库提供了有关Azure SQL触发器的更多示例。

该示例引用 ToDoItem 数据库表:

CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

Change tracking在数据库和表上启用:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

SQL 触发器绑定到 todoChanges,即对象列表,每个对象具有 2 个属性:

  • 项:已更改的项。 项的结构将遵循表架构。
  • 操作:可能的值为 InsertUpdate

以下示例显示了在 ToDo 表发生更改时调用的 PowerShell 函数。

下面是 function.json 文件中的绑定数据:

{
    "name": "todoChanges",
    "type": "sqlTrigger",
    "direction": "in",
    "tableName": "dbo.ToDo",
    "connectionStringSetting": "SqlConnectionString"
}

配置部分解释了这些属性。

下面是 run.ps1 文件中的函数的示例 PowerShell 代码:

using namespace System.Net

param($todoChanges)
# The output is used to inspect the trigger binding parameter in test methods.
# Use -Compress to remove new lines and spaces for testing purposes.
$changesJson = $todoChanges | ConvertTo-Json -Compress
Write-Host "SQL Changes: $changesJson"

用法示例

GitHub 存储库提供了有关Azure SQL触发器的更多示例。

该示例引用 ToDoItem 数据库表:

CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

Change tracking在数据库和表上启用:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

SQL 触发器绑定到 todoChanges,即对象数组,每个对象具有 2 个属性:

  • 项:已更改的项。 项的结构将遵循表架构。
  • 操作:可能的值为 InsertUpdate

以下示例显示了在 ToDo 表发生更改时调用的 JavaScript 函数。

下面是 function.json 文件中的绑定数据:

{
    "name": "todoChanges",
    "type": "sqlTrigger",
    "direction": "in",
    "tableName": "dbo.ToDo",
    "connectionStringSetting": "SqlConnectionString"
}

配置部分解释了这些属性。

下面是 index.js 文件中的函数的示例 JavaScript 代码:

module.exports = async function (context, todoChanges) {
    context.log(`SQL Changes: ${JSON.stringify(todoChanges)}`)
}

用法示例

GitHub 存储库提供了有关Azure SQL触发器的更多示例。

该示例引用 ToDoItem 数据库表:

CREATE TABLE dbo.ToDo (
    [Id] UNIQUEIDENTIFIER PRIMARY KEY,
    [order] INT NULL,
    [title] NVARCHAR(200) NOT NULL,
    [url] NVARCHAR(200) NOT NULL,
    [completed] BIT NOT NULL
);

Change tracking在数据库和表上启用:

ALTER DATABASE [SampleDatabase]
SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);

ALTER TABLE [dbo].[ToDo]
ENABLE CHANGE_TRACKING;

SQL 触发器绑定到变量 todoChanges,即对象列表,每个对象具有 2 个属性:

  • 项:已更改的项。 项的结构将遵循表架构。
  • 操作:可能的值为 InsertUpdate

以下示例显示了在 ToDo 表发生更改时调用的 Python 函数。

以下是 function_app.py 文件的示例 python 代码:

import json
import logging
import azure.functions as func

app = func.FunctionApp()

@app.function_name(name="ToDoTrigger")
@app.sql_trigger(arg_name="todo",
                        table_name="ToDo",
                        connection_string_setting="SqlConnectionString")
def todo_trigger(todo: str) -> None:
    logging.info("SQL Changes: %s", json.loads(todo))

特性

C# 库使用 SqlTrigger 属性在函数上声明 SQL 触发器,该函数具有以下属性:

Attribute 属性 说明
TableName 必需。 触发器监视的表的名称。
ConnectionStringSetting 必需。 包含数据库connection string的应用设置的名称,该设置包含受监视更改的表。 connection string设置名称对应于包含Azure SQL或SQL Server实例connection string1 的应用程序设置()。
LeasesTableName 可选。 用于存储租约的表的名称。 如果未指定,租约表名称将为 Leases_{FunctionId}_{TableId}。 here找到有关如何生成此信息的详细信息。

批注

Java 函数运行时库中,对值来自Azure SQL的参数使用 @SQLTrigger 注释(com.microsoft.azure.functions.sql.annotation.SQLTrigger)。 此批注支持以下元素:

元素 说明
名字 必需。 触发器绑定到的参数的名称。
tableName 必需。 触发器监视的表的名称。
connectionStringSetting 必需。 包含数据库connection string的应用设置的名称,该设置包含受监视更改的表。 connection string设置名称对应于包含Azure SQL或SQL Server实例connection string1 的应用程序设置()。
LeasesTableName 可选。 用于存储租约的表的名称。 如果未指定,租约表名称将为 Leases_{FunctionId}_{TableId}。 here找到有关如何生成此信息的详细信息。

配置

下表解释了在 function.json 文件中设置的绑定配置属性。

“function.json”属性 说明
名字 必需。 触发器绑定到的参数的名称。
type 必需。 必须设置为 sqlTrigger
方向 必需。 必须设置为 in
tableName 必需。 触发器监视的表的名称。
connectionStringSetting 必需。 包含数据库connection string的应用设置的名称,该设置包含受监视更改的表。 connection string设置名称对应于包含Azure SQL或SQL Server实例connection string1 的应用程序设置()。
LeasesTableName 可选。 用于存储租约的表的名称。 如果未指定,租约表名称将为 Leases_{FunctionId}_{TableId}。 here找到有关如何生成此信息的详细信息。

可选配置

可以为用于本地开发的 SQL 触发器配置以下可选设置。

host.json

本部分介绍版本 2.x 及更高版本中此绑定可用的配置设置。 host.json 文件中的设置将应用于函数应用实例中的所有函数。 有关函数app configuration设置的详细信息,请参阅 host.json 参考Azure Functions

设置 默认值 说明
MaxBatchSize 100 在发送到触发函数之前,在触发器每次迭代loop处理的最大更改数。
PollingIntervalMs 1000 处理每批更改之间的延迟(以毫秒为单位)。 (1000 毫秒为 1 秒)
MaxChangesPerWorker 1000 每个 application-worker 允许的用户表中挂起的更改的数量上限。 如果更改计数超过此限制,则可能会导致横向扩展。此设置仅适用于启用了 runtime 驱动的缩放Azure函数应用

示例 host.json 文件

下面是具有可选设置的 host.json 文件的示例:

{
  "version": "2.0",
  "extensions": {
      "Sql": {
        "MaxBatchSize": 300,
        "PollingIntervalMs": 1000,
        "MaxChangesPerWorker": 100
      }
  },
  "logging": {
    "applicationInsights": {
      "samplingSettings": {
        "isEnabled": true,
        "excludedTypes": "Request"
      }
    },
    "logLevel": {
      "default": "Trace"
    }
  }
}

local.setting.json

local.settings.json 文件存储应用设置和本地开发工具使用的设置。 仅当在本地运行project时,才会使用 local.settings.json 文件中的设置。 将project发布到Azure时,请务必将任何必需的设置添加到函数应用的应用设置中。

重要

因为 local.settings.json 可能包含机密(如连接字符串),因此你绝不能将其存储在远程存储库中。 支持 Functions 的工具提供了将 local.settings.json 文件中的设置与部署project的函数应用中的 app 设置同步的方法。

设置 默认值 说明
Sql_Trigger_BatchSize 100 在发送到触发函数之前,在触发器每次迭代loop处理的最大更改数。
Sql_Trigger_PollingIntervalMs 1000 处理每批更改之间的延迟(以毫秒为单位)。 (1000 毫秒为 1 秒)
Sql_Trigger_MaxChangesPerWorker 1000 每个 application-worker 允许的用户表中挂起的更改的数量上限。 如果更改计数超过此限制,则可能会导致横向扩展。此设置仅适用于启用了 runtime 驱动的缩放Azure函数应用

示例 local.settings.json 文件

下面是具有可选设置的 local.settings.json 文件的示例:

{
  "IsEncrypted": false,
  "Values": {
    "AzureWebJobsStorage": "UseDevelopmentStorage=true",
    "FUNCTIONS_WORKER_RUNTIME": "dotnet",
    "SqlConnectionString": "",
    "Sql_Trigger_MaxBatchSize": 300,
    "Sql_Trigger_PollingIntervalMs": 1000,
    "Sql_Trigger_MaxChangesPerWorker": 100
  }
}

设置change tracking(必需)

设置change tracking以用于Azure SQL触发器需要执行两个步骤。 可以从支持运行查询的任何 SQL 工具完成这些步骤,包括 Visual Studio CodeSQL Server Management Studio

  1. 在 SQL 数据库上启用change tracking,将 your database name替换为要监视的表所在的数据库的名称:

    ALTER DATABASE [your database name]
    SET CHANGE_TRACKING = ON
    (CHANGE_RETENTION = 2 DAYS, AUTO_CLEANUP = ON);
    

    CHANGE_RETENTION 选项指定保留change tracking信息(更改历史记录)的时间段。 SQL 数据库保留更改历史记录可能会影响触发器功能。 例如,如果 Azure 函数已关闭几天,然后恢复,则数据库将包含上述设置示例中过去两天内发生的更改。

    AUTO_CLEANUP 选项用于启用或禁用删除旧change tracking信息的清理任务。 如果出现阻止触发器运行的临时问题,则可以关闭自动清理来暂停删除早于保留期的信息,直到问题得到解决。

    有关change tracking选项的详细信息,请参阅 SQL 文档

  2. 对表启用change tracking,用要监视的表的名称替换 your table name(如果适用)更改架构):

    ALTER TABLE [dbo].[your table name]
    ENABLE CHANGE_TRACKING;
    

    触发器需要对要监视的表进行更改和对change tracking系统表的读取access。 每个函数触发器都有一个关联的change tracking表,并在架构az_func租约表。 如果这些表尚不存在,则由触发器创建。 有关这些数据结构的详细信息,请参阅 Azure SQL 绑定库 documentation

启用运行时驱动的缩放

根据需要,函数可以根据用户表中待处理的更改数自动缩放。 使用 SQL 触发器时,若要允许函数在高级计划上正确缩放,需要启用运行时缩放监视。

  1. 在 Azure portal 中,在函数应用中,选择 Configuration

  2. “函数运行时设置 ”选项卡上,对于 运行时缩放监视,请选择“ 打开”。

     Azure portal 区域的Screenshot,用于启用运行时缩放.

重试支持

GitHub存储库中提供了有关 SQL 触发器 重试支持leases 表的详细信息。

启动重试

如果启动过程中发生异常,则主机运行时会自动尝试采用指数退避策略重启触发器侦听器。 这样的重启会一直进行,直到侦听器成功启动或者启动被取消。

连接断开重试

如果函数成功启动,但发生错误导致连接断开(例如,服务器掉线)则函数会继续尝试和重新打开连接,直到函数停止或连接成功。 如果成功重新建立连接,则会继续处理中断时正在处理的更改。

请注意,这些重试位于 SqlClient 具有的内置空闲连接重试逻辑之外,可以使用 ConnectRetryCountConnectRetryIntervalconnection string 选项进行配置。 会先尝试内置的空闲连接重试,如果未能重新建立连接,然后触发器绑定再尝试自己重新建立连接。

函数异常重试

如果处理更改时用户函数中发生异常,则会在 60 秒内在当前正在处理的行批次进行重试。 重试期间,将其他更改作为正常进行处理,但当超时期限过后,会忽略该批次中导致异常发生的行。

如果给定行的函数执行连续失败 5 次,则会完全忽略未来对该行的所有更改。 由于批处理中的行不是确定性的,因此失败批处理中的行可能会在后续调用中以不同的批结尾。 这意味着,不是一定要忽略失败批次中的所有行。 如果该批次中的其他行导致发生异常,则“没有问题”的行最后会位于另一批次中,其在以后的调用中不会出现异常。

后续步骤