Formato de mensaje JSON: cambio del streaming de eventos

Se aplica a: SQL Server 2025 (17.x) Azure SQL DatabaseAzure SQL Managed Instance

Este artículo describe el formato JSON de un mensaje CloudEvents que transmite desde SQL Server a Azure Event Hubs al utilizar la función de streaming de cambios de eventos (CES) introducida en SQL Server 2025 (17.x), Azure SQL Database, y Azure SQL Managed Instance.

Nota:

El streaming de eventos de cambio se encuentra actualmente en versión preliminar para:

Información general

Los eventos que cambian las emisiones de streaming de eventos siguen la especificación CloudEvents , por lo que puedes integrarlos fácilmente con sistemas orientados a eventos. Todos los eventos en la nube ces contienen 11 atributos (campos). Puedes configurar CES para serializar CloudEvents como JSON (nativo) o como binario Avro. Las siguientes secciones de este artículo describen en detalle el formato del mensaje, incluyendo los atributos CES CloudEvent y la serialización.

Cuando corresponde, las descripciones de esta sección provienen de la especificación CloudEvent, que incluye más detalles.

Atributos

  • specversion:

    • Tipo de datos: String
    • Atributo CloudEvent requerido
    • Versión de la especificación CloudEvents que usa el evento. Esta versión permite la interpretación del contexto.
  • type

    • Tipo de datos: String
    • Atributo CloudEvent requerido
    • Contiene un valor que describe el tipo de evento relacionado con la aparición de origen. El formato de este valor lo define el productor y puede incluir información como la versión del tipo. Para más información, véase Versionado de CloudEvents.
    • Para eventos de Streaming de Eventos de Cambio, el tipo actual es: com.microsoft.SQL.CES.DML.V{n}, donde {n} indica la versión del esquema de eventos DML de Streaming de Cambios de Eventos de Microsoft.
      • La última versión actual del esquema es la 1.
  • source

    • Tipo de datos: String
    • Atributo CloudEvent requerido
    • Identifica el contexto en el que se produjo un evento. La combinación de fuente e ID debe ser única para cada evento. Actualmente, este campo siempre se envía como \/ en eventos transmitidos desde SQL.
  • id

    • Tipo de datos: String
    • Atributo CloudEvent requerido
    • Identifica el evento. Los productores deben asegurarse de que la combinación de origen e ID sea única para cada evento distinto. Si se vuelve a enviar un evento duplicado (por ejemplo, debido a un error de red), podría tener el mismo identificador. Los consumidores pueden suponer que los eventos con un origen y un identificador idénticos son duplicados.
  • logicalid

    • Tipo de datos: String
    • Atributo de extensión
    • Los IDs lógicos compartidos identifican los mensajes divididos (debido a las restricciones de tamaño de los mensajes de los Event Hubs).
  • time

    • Tipo de datos: marca de tiempo
    • Atributo CloudEvent opcional
    • Marca de tiempo UTC de cuándo ocurrió el commit dentro de una transacción SQL que originalmente desencadena un evento transmitido.
  • datacontenttype

    • Tipo de datos: String
    • Atributo CloudEvent opcional
    • Tipo de contenido de valor de datos. Este atributo permite que los datos lleven cualquier tipo de contenido, en el que el formato y la codificación pueden diferir del del formato de evento elegido. Por ejemplo, un evento representado con el formato de sobre JSON podría llevar una carga XML en los datos y este atributo se informa al consumidor en "application/xml". Las reglas sobre cómo se renderiza el contenido de los datos para diferentes datacontenttype valores están definidas en las especificaciones del formato de evento.
  • operation

    • Tipo de datos: String
    • Atributo de extensión
    • Representa el tipo de operación SQL que ocurrió:
      • INS para insertos
      • Actualización para actualizaciones
      • DEL para eliminaciones
  • segmentindex

    • Tipo de datos: entero
    • Atributo de extensión
    • Índice de segmentos, que denota la posición del mensaje dentro de los bloques lógicos del mensaje. El índice de segmento proporciona información sobre dónde se encuentra el mensaje en la secuencia de fragmentos de mensaje lógicos. Este campo siempre está presente. Utiliza logicalid, , y finalsegment campos para ordenar los eventos entrantes que representan una gran distribución de la carga útil SQL según el valor configurado max_message_size_kbsegmentindex.
  • finalsegment

    • Tipo de datos: booleano
    • Atributo de extensión
    • Indica si este segmento es el último de la secuencia. Este campo está siempre presente y ayuda a identificar si un evento SQL se dividió en subeventos según el valor configurado max_message_size_kb .
  • data

    • Tipo de datos: String
    • Atributo CloudEvent opcional
    • Datos de eventos específicos del dominio. Para CES, los datos son cadenas que se pueden analizar como JSON. En este código JSON se describe cómo han cambiado los datos. El formato del atributo de datos está en formato de atributo Data.

Nota:

La división de mensajes es independiente de la truncación de valores de columna. Antes de que CES serialize el data atributo, trunca cada valor de columna transmitido mayor que 1 MB a 1 MB. CES luego divide el evento formado en fragmentos de mensaje según sea necesario según max_message_size_kb.

Ejemplos

Ejemplo de mensaje JSON: inserción

{
  "specversion": "1.0",
  "type": "com.microsoft.SQL.CES.DML.V1",
  "source": "\/",
  "id": "d43f09a6-d13b-4902-86d4-17bdb5edb872",
  "logicalid": "9c8d4ad2-bf54-4f10-a96f-038af496997f:0000002C00000300017C:00000000000000000001",
  "time": "2025-03-14T16:45:20.650Z",
  "datacontenttype": "application\/json",
  "operation": "INS",
  "splitindex": 0,
  "splittotalcnt": 0,
  "data": "{\n  \"eventsource\": {\n    \"db\": \"db1\",\n    \"schema\": \"dbo\",\n    \"tbl\": \"Purchases\",\n    \"cols\": [\n      {\n        \"name\": \"purchase_id\",\n        \"type\": \"int\",\n        \"index\": 0\n      },\n      {\n        \"name\": \"customer_name\",\n        \"type\": \"varchar(100)\",\n        \"index\": 1\n      },\n      {\n        \"name\": \"product_id\",\n        \"type\": \"int\",\n        \"index\": 2\n      },\n      {\n        \"name\": \"product_name\",\n        \"type\": \"varchar(100)\",\n        \"index\": 3\n      },\n      {\n        \"name\": \"price_per_item\",\n        \"type\": \"int\",\n        \"index\": 4\n      },\n      {\n        \"name\": \"quantity\",\n        \"type\": \"int\",\n        \"index\": 5\n      },\n      {\n        \"name\": \"purchase_date\",\n        \"type\": \"datetime\",\n        \"index\": 6\n      },\n      {\n        \"name\": \"payment_method\",\n        \"type\": \"varchar(50)\",\n        \"index\": 7\n      }\n    ],\n    \"pkkey\": [\n      {\n        \"columnname\": \"purchase_id\",\n        \"value\": \"105\"\n      }\n    ]\n  },\n  \"eventrow\": {\n    \"old\": \"{}\",\n    \"current\": \"{\\\"purchase_id\\\": \\\"105\\\", \\\"customer_name\\\": \\\"Anna Doe\\\", \\\"product_id\\\": \\\"101\\\", \\\"product_name\\\": \\\"Game 2077\\\", \\\"price_per_item\\\": \\\"60\\\", \\\"quantity\\\": \\\"1\\\", \\\"purchase_date\\\": \\\"2025-03-14 16:45:01.000\\\", \\\"payment_method\\\": \\\"Credit Card\\\"}\"\n  }\n}"
}

Ejemplo de mensaje JSON - actualizado

{
  "specversion": "1.0",
  "type": "com.microsoft.SQL.CES.DML.V1",
  "source": "\/",
  "id": "c425575f-00bb-45cf-acec-c55fdc7d08cd",
  "logicalid": "9c8d4ad2-bf54-4f10-a96f-038af496997f:0000002C000003500004:00000000000000000001",
  "time": "2025-03-14T16:49:59.567Z",
  "datacontenttype": "application\/json",
  "operation": "UPD",
  "splitindex": 0,
  "splittotalcnt": 0,
  "data": "{\n  \"eventsource\": {\n    \"db\": \"db1\",\n    \"schema\": \"dbo\",\n    \"tbl\": \"Purchases\",\n    \"cols\": [\n      {\n        \"name\": \"purchase_id\",\n        \"type\": \"int\",\n        \"index\": 0\n      },\n      {\n        \"name\": \"customer_name\",\n        \"type\": \"varchar(100)\",\n        \"index\": 1\n      },\n      {\n        \"name\": \"product_id\",\n        \"type\": \"int\",\n        \"index\": 2\n      },\n      {\n        \"name\": \"product_name\",\n        \"type\": \"varchar(100)\",\n        \"index\": 3\n      },\n      {\n        \"name\": \"price_per_item\",\n        \"type\": \"int\",\n        \"index\": 4\n      },\n      {\n        \"name\": \"quantity\",\n        \"type\": \"int\",\n        \"index\": 5\n      },\n      {\n        \"name\": \"purchase_date\",\n        \"type\": \"datetime\",\n        \"index\": 6\n      },\n      {\n        \"name\": \"payment_method\",\n        \"type\": \"varchar(50)\",\n        \"index\": 7\n      }\n    ],\n    \"pkkey\": [\n      {\n        \"columnname\": \"purchase_id\",\n        \"value\": \"105\"\n      }\n    ]\n  },\n  \"eventrow\": {\n    \"old\": \"{}\",\n    \"current\": \"{\\\"purchase_id\\\": \\\"105\\\", \\\"customer_name\\\": \\\"Anna Doe\\\", \\\"product_id\\\": \\\"100\\\", \\\"product_name\\\": \\\"Game 2066\\\", \\\"price_per_item\\\": \\\"50\\\", \\\"quantity\\\": \\\"2\\\", \\\"purchase_date\\\": \\\"2025-03-14 16:45:01.000\\\", \\\"payment_method\\\": \\\"Credit Card\\\"}\"\n  }\n}"
}

Ejemplo de mensaje JSON: eliminación

{
  "specversion": "1.0",
  "type": "com.microsoft.SQL.CES.DML.V1",
  "source": "\/",
  "id": "24fa0c2c-c45d-4abf-9a8d-fba04c29fc86",
  "logicalid": "9c8d4ad2-bf54-4f10-a96f-038af496997f:0000002C000003600019:00000000000000000001",
  "time": "2025-03-14T16:51:39.613Z",
  "datacontenttype": "application\/json",
  "operation": "DEL",
  "splitindex": 0,
  "splittotalcnt": 0,
  "data": "{\n  \"eventsource\": {\n    \"db\": \"db1\",\n    \"schema\": \"dbo\",\n    \"tbl\": \"Purchases\",\n    \"cols\": [\n      {\n        \"name\": \"purchase_id\",\n        \"type\": \"int\",\n        \"index\": 0\n      },\n      {\n        \"name\": \"customer_name\",\n        \"type\": \"varchar(100)\",\n        \"index\": 1\n      },\n      {\n        \"name\": \"product_id\",\n        \"type\": \"int\",\n        \"index\": 2\n      },\n      {\n        \"name\": \"product_name\",\n        \"type\": \"varchar(100)\",\n        \"index\": 3\n      },\n      {\n        \"name\": \"price_per_item\",\n        \"type\": \"int\",\n        \"index\": 4\n      },\n      {\n        \"name\": \"quantity\",\n        \"type\": \"int\",\n        \"index\": 5\n      },\n      {\n        \"name\": \"purchase_date\",\n        \"type\": \"datetime\",\n        \"index\": 6\n      },\n      {\n        \"name\": \"payment_method\",\n        \"type\": \"varchar(50)\",\n        \"index\": 7\n      }\n    ],\n    \"pkkey\": [\n      {\n        \"columnname\": \"purchase_id\",\n        \"value\": \"105\"\n      }\n    ]\n  },\n  \"eventrow\": {\n    \"old\": \"{\\\"purchase_id\\\": \\\"105\\\", \\\"customer_name\\\": \\\"Anna Doe\\\", \\\"product_id\\\": \\\"100\\\", \\\"product_name\\\": \\\"Game 2066\\\", \\\"price_per_item\\\": \\\"50\\\", \\\"quantity\\\": \\\"2\\\", \\\"purchase_date\\\": \\\"2025-03-14 16:45:01.000\\\", \\\"payment_method\\\": \\\"Credit Card\\\"}\",\n    \"current\": \"{}\"\n  }\n}"
}

Formato de atributo de datos

Los datos son un objeto JSON encapsulado en el atributo de cadena que contiene dos atributos:

  • eventSource
  • eventRow
"data": "{ "eventsource": {<eventSource>}, "eventrow": {<eventRow>}}"

Las siguientes secciones explican estos dos atributos con mayor detalle.

eventsource

Describe los metadatos sobre la base de datos y la tabla donde se produjo el evento:

  • db

    • Tipo de datos: String
    • Descripción: nombre de la base de datos donde se encuentra la tabla.
    • Ejemplo: cessqldb001
  • schema

    • Tipo de datos: String
    • Descripción: esquema de base de datos que contiene la tabla.
    • Ejemplo: dbo
  • tbl

    • Tipo de datos: String
    • Descripción: tabla en la que se produjo el evento.
    • Ejemplo: Purchases
  • cols

    • Tipo de datos: Matriz
    • Descripción: matriz que detalla las columnas de la tabla.
      • name (string): nombre de la columna.
      • type (string): tipo de datos de la columna (VARCHAR o INT).
      • index (entero): índice o posición de la columna de la tabla.
  • pkkey

    • Tipo de datos: Matriz
    • Descripción: representa las columnas de clave principal y sus valores para identificar la fila específica.
      • columnname (string): el nombre de la columna usada en la clave principal.
      • value (string/int/etc.): el valor de la columna usada en la clave principal ayuda a identificar de forma única la fila.

eventrow

Describe los cambios de nivel de fila y compara los valores antiguos y actuales de los campos del registro.

  • old (objeto encapsulado en cadena): representa los valores de la fila antes del evento.
    • Cada par clave-valor consta de:
      • <column_name>: (cadena): nombre de la columna.
      • <column_value>: (string/int/etc.): valor anterior de esa columna.
  • current (objeto ajustado en cadena): representa los valores actualizados de la fila después del evento.
    • De forma similar al objeto anterior, con cada par clave-valor estructurado como:
      • <column_name> (cadena): nombre de la columna.
      • <column_value> (string/int/etc.): el valor nuevo o actual de esa columna.

Esquema AVRO de CES CloudEvent

{
  "type": "record",
  "name": "ChangeEvent",
  "fields": [
    {
      "name": "specversion",
      "type": "string"
    },
    {
      "name": "type",
      "type": "string"
    },
    {
      "name": "source",
      "type": "string"
    },
    {
      "name": "id",
      "type": "string"
    },
    {
      "name": "logicalid",
      "type": "string"
    },
    {
      "name": "time",
      "type": "string"
    },
    {
      "name": "datacontenttype",
      "type": "string"
    },
    {
      "name": "operation",
      "type": "string"
    },
    {
      "name": "segmentindex",
      "type": "int"
    },
    {
      "name": "finalsegment",
      "type": "boolean"
    },
    {
      "name": "data",
      "type": "bytes"
    }
  ]
}

Esquema AVRO de atributo de datos CES

{
  "name": "Data",
  "type": "record",
  "fields": [
    {
      "name": "eventsource",
      "type": {
        "name": "EventSource",
        "type": "record",
        "fields": [
          {
            "name": "db",
            "type": "string"
          },
          {
            "name": "schema",
            "type": "string"
          },
          {
            "name": "tbl",
            "type": "string"
          },
          {
            "name": "cols",
            "type": {
              "type": "array",
              "items": {
                "name": "Column",
                "type": "record",
                "fields": [
                  {
                    "name": "name",
                    "type": "string"
                  },
                  {
                    "name": "type",
                    "type": "string"
                  },
                  {
                    "name": "index",
                    "type": "int"
                  }
                ]
              }
            }
          },
          {
            "name": "pkkey",
            "type": {
              "type": "array",
              "items": {
                "name": "PkKey",
                "type": "record",
                "fields": [
                  {
                    "name": "columnname",
                    "type": "string"
                  },
                  {
                    "name": "value",
                    "type": "string"
                  }
                ]
              }
            }
          },
          {
            "name": "transaction",
            "type": {
              "name": "Transaction",
              "type": "record",
              "fields": [
                {
                  "name": "commitlsn",
                  "type": "string"
                },
                {
                  "name": "beginlsn",
                  "type": "string"
                },
                {
                  "name": "sequencenumber",
                  "type": "int"
                },
                {
                  "name": "committime",
                  "type": "string"
                }
              ]
            }
          }
        ]
      }
    },
    {
      "name": "eventrow",
      "type": {
        "name": "EventRow",
        "type": "record",
        "fields": [
          {
            "name": "old",
            "type": "string"
          },
          {
            "name": "current",
            "type": "string"
          }
        ]
      }
    }
  ]
}