DA14695---multi-link简单解析

2024-08-22 00:52
文章标签 简单 解析 link multi da14695

本文主要是介绍DA14695---multi-link简单解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、system_init

        在system_init中创建ble_multi_link_task任务,先是开启了BLE管理器,再注册ble_multi_link_task任务

 /* Initialize BLE Manager */ble_mgr_init();/* Start the Multi-Link application task. */OS_TASK_CREATE("Multi-Link",                    /* The text name assigned to the task, fordebug only; not used by the kernel. */ble_multi_link_task,             /* The function that implements the task. */NULL,                            /* The parameter passed to the task. */200 * OS_STACK_WORD_SIZE,        /* The number of bytes to allocate to thestack of the task. */mainBLE_MULTI_LINK_TASK_PRIORITY,/* The priority assigned to the task. */handle);                         /* The task handle. */OS_ASSERT(handle);
二、ble_multi_link_task

        从上到下依次做了

注册一个看门狗

        wdog_id = sys_watchdog_register(false);

 使能BLE

         status = ble_enable();

设置设备角色为外围设备和中心设备

         ble_gap_role_set(GAP_PERIPHERAL_ROLE | GAP_CENTRAL_ROLE);

注册本任务到BLE框架中,用于后面接收BLE栈的事件通知

        ble_register_app();

设置设备名称,设备名是存储在GATT服务中的一般在设备连接后来读取,与广播数据中的设备名是未连接状态下就可以被扫描看见的也就是手机上扫描BLE时显示的,他们两个可以一样但性质不一样。

         ble_gap_device_name_set("Dialog Multi-link", ATT_PERM_READ);

添加注册一个服务,bd_addr_write_cb后续在讲

         dlg_mls_init(bd_addr_write_cb);

设置广播数据和开始广播

        ble_gap_adv_data_set(sizeof(adv_data), adv_data, 0, NULL);
        ble_gap_adv_start(GAP_CONN_MODE_UNDIRECTED);

主循环,定时通知看门狗,等待BLE发送通知 ,再根据不同的BLE事件进行不同的回调处理

        if (notif & BLE_APP_NOTIFY_MASK)这里是在判断接收到的通知是不是属于BLE发来的,如果是就进行BLE事件的处理。

 完整代码

/******************************************************************************************** @file ble_multi_link_task.c** @brief Multi-Link Demo task** Copyright (C) 2015-2019 Dialog Semiconductor.* This computer program includes Confidential, Proprietary Information* of Dialog Semiconductor. All Rights Reserved.******************************************************************************************/#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <stdio.h>
#include "sdk_queue.h"
#include "osal.h"
#include "timers.h"
#include "osal.h"
#include "sys_watchdog.h"
#include "ble_att.h"
#include "ble_common.h"
#include "ble_gap.h"
#include "ble_gatts.h"
#include "ble_service.h"
#include "dlg_mls.h"/** Multi-link demo advertising data*/
static const uint8_t adv_data[] = {0x12, GAP_DATA_TYPE_LOCAL_NAME,'D', 'i', 'a', 'l', 'o', 'g', ' ', 'M', 'u', 'l', 't', 'i', '-', 'l', 'i', 'n', 'l'
};static const gap_conn_params_t cp = {.interval_min  = BLE_CONN_INTERVAL_FROM_MS(50),     // 50.00 ms.interval_max  = BLE_CONN_INTERVAL_FROM_MS(70),     // 70.00 ms.slave_latency = 0,.sup_timeout   = BLE_SUPERVISION_TMO_FROM_MS(420),  // 420.00 ms
};typedef struct {void            *next;bd_address_t    addr;uint16_t        conn_idx;
} conn_dev_t;__RETAINED static enum conn_cancel_reason {CONN_CANCEL_REASON_ADV_ERR,CONN_CANCEL_REASON_DEV_NOT_RESPONDING,
} conn_canceled_reason;__RETAINED static queue_t connections;__RETAINED_RW static uint16_t master_dev_conn_idx = BLE_CONN_IDX_INVALID;__RETAINED static bool connecting;__RETAINED static bd_address_t new_dev_addr;/** Debug functions*/static const char *format_bd_address(const bd_address_t *addr)
{static char buf[19];int i;for (i = 0; i < sizeof(addr->addr); i++) {int idx;// for printout, address should be reversedidx = sizeof(addr->addr) - i - 1;sprintf(&buf[i * 3], "%02X:", addr->addr[idx]);}buf[sizeof(buf) - 2] = '\0';return buf;
}static void print_connection_func(void *data, void *user_data)
{const conn_dev_t *conn_dev = data;int *num = user_data;(*num)++;printf("%2d | %5d | %s\r\n", *num, conn_dev->conn_idx,format_bd_address(&conn_dev->addr));
}static void print_connections(void)
{int num = 0;printf("\r\n");printf("Nr | Index | Address\r\n");queue_foreach(&connections, print_connection_func, &num);if (!num) {printf("(no active connections)\r\n");}printf("\r\n");
}bool list_elem_match(const void *elem, const void *ud)
{conn_dev_t *conn_dev = (conn_dev_t *) elem;uint16_t *conn_idx = (uint16_t *) ud;return conn_dev->conn_idx == *conn_idx;
}static void bd_addr_write_cb(ble_service_t *svc, uint16_t conn_idx, const bd_address_t *addr)
{
//    printf("bd_addr_write_cb,addr_type_t:%d",addr->addr_type);
//    // 以十六进制格式打印地址
//       printf("Address (Hex): ");
//       for(int i = 0; i < 6; i++) {
//           printf("%02X", addr->addr[i]);
//           if (i < 5) {
//               printf(":");
//           }
//       }ble_error_t status;status = ble_gap_connect(addr, &cp);if (status != BLE_STATUS_OK && status != BLE_ERROR_BUSY) {printf("%s: failed. Status=%d\r\n", __func__, status);}if (status == BLE_ERROR_BUSY) {new_dev_addr = *addr;conn_canceled_reason = CONN_CANCEL_REASON_DEV_NOT_RESPONDING;/** ble_gap_connect() will return a BLE_ERROR_BUSY status when another connection* procedure is already ongoing. To be able to connect to another device, cancel* the last connection request to retry connecting with the new device.*/ble_gap_connect_cancel();}connecting = (status == BLE_STATUS_OK);
}static void handle_evt_gap_connected(ble_evt_gap_connected_t *evt)
{conn_dev_t *conn_dev;printf("Device connected\r\n");printf("\tConnection index: %u\r\n", evt->conn_idx);printf("\tAddress: %s %s\r\n",evt->peer_address.addr_type == PUBLIC_ADDRESS ? "public" : "private",ble_address_to_string(&evt->peer_address));conn_dev = OS_MALLOC(sizeof(conn_dev_t));conn_dev->addr.addr_type = evt->peer_address.addr_type;memcpy(conn_dev->addr.addr, evt->peer_address.addr, sizeof(conn_dev->addr.addr));conn_dev->conn_idx = evt->conn_idx;queue_push_front(&connections, (void *)conn_dev);if (master_dev_conn_idx == BLE_CONN_IDX_INVALID) {master_dev_conn_idx = evt->conn_idx;}connecting = false;print_connections();
}static void handle_evt_gap_conn_completed(ble_evt_gap_connection_completed_t *evt)
{if (master_dev_conn_idx != BLE_CONN_IDX_INVALID &&conn_canceled_reason != CONN_CANCEL_REASON_DEV_NOT_RESPONDING) {return;}/* Process only then if the connection was completed not by intended cancellation then  */if (evt->status != BLE_ERROR_CANCELED) {return;}if (conn_canceled_reason == CONN_CANCEL_REASON_DEV_NOT_RESPONDING) {ble_error_t status;printf("%s: Last connection request was canceled. Connecting to new device...\r\n",__func__);status = ble_gap_connect(&new_dev_addr, &cp);printf("%s: Status=%d\r\n", __func__, status);} else if (conn_canceled_reason == CONN_CANCEL_REASON_ADV_ERR) {printf("%s: cancel the connect\r\n", __func__);ble_gap_adv_start(GAP_CONN_MODE_UNDIRECTED);printf("Advertising is on again after error\r\n");} else {printf("Undefined cancellation reason\r\n");}
}static void handle_evt_gap_disconnected(ble_evt_gap_disconnected_t *evt)
{printf("Device disconnected\r\n");printf("\tConnection index: %u\r\n", evt->conn_idx);printf("\tBD address of disconnected device: %s, %s\r\n",evt->address.addr_type == PUBLIC_ADDRESS ? "public" : "private",ble_address_to_string(&evt->address));printf("\tReason of disconnection: 0x%02x\r\n", evt->reason);conn_dev_t *conn_dev = queue_remove(&connections, list_elem_match, &evt->conn_idx);if (conn_dev) {OS_FREE(conn_dev);}print_connections();if (master_dev_conn_idx == evt->conn_idx) {master_dev_conn_idx = BLE_CONN_IDX_INVALID;ble_gap_adv_start(GAP_CONN_MODE_UNDIRECTED);printf("Advertising is on again\r\n");}
}static void handle_evt_gap_adv_completed(ble_evt_gap_adv_completed_t *evt)
{printf("Advertising completed\r\n");printf("\tAdvertising type: %d\r\n", evt->adv_type);printf("\tCompletion status: 0x%02x\r\n", evt->status);if (connecting && (evt->status == BLE_ERROR_NOT_ALLOWED)) {connecting = false;conn_canceled_reason = CONN_CANCEL_REASON_ADV_ERR;ble_gap_connect_cancel();}
}static void handle_evt_gap_pair_req(ble_evt_gap_pair_req_t *evt)
{printf("Pair request\r\n");printf("\tConnection index: %d\r\n", evt->conn_idx);printf("\tBond: %s\r\n", evt->bond ? "true" : "false");ble_gap_pair_reply(evt->conn_idx, true, evt->bond);
}static void handle_evt_gap_security_request(ble_evt_gap_security_request_t *evt)
{ble_error_t status;status = ble_gap_pair(evt->conn_idx, evt->bond);if (status != BLE_STATUS_OK) {printf("%s: failed. Status=%d\r\n", __func__, status);}
}void ble_multi_link_task(void *params)
{ble_error_t status;int8_t wdog_id;/* Register ble_multi_link task to be monitored by watchdog */wdog_id = sys_watchdog_register(false);/* Enable BLE */status = ble_enable();if (status == BLE_STATUS_OK) {/* Set all roles */ble_gap_role_set(GAP_PERIPHERAL_ROLE | GAP_CENTRAL_ROLE);} else {printf("%s: failed. Status=%d\r\n", __func__, status);}/* Register task to BLE framework to receive BLE event notifications */ble_register_app();/* Set device name */ble_gap_device_name_set("Dialog Multi-link", ATT_PERM_READ);/* Add Multi-Link Service */dlg_mls_init(bd_addr_write_cb);/* Set advertising data and start advertising */ble_gap_adv_data_set(sizeof(adv_data), adv_data, 0, NULL);ble_gap_adv_start(GAP_CONN_MODE_UNDIRECTED);printf("Advertising is on\r\n");for (;;) {OS_BASE_TYPE ret;uint32_t notif;/* Notify watchdog on each loop */sys_watchdog_notify(wdog_id);/* Suspend watchdog while blocking on OS_TASK_NOTIFY_WAIT() */sys_watchdog_suspend(wdog_id);/** Wait on any of the notification bits, then clear them all*/ret = OS_TASK_NOTIFY_WAIT(0, OS_TASK_NOTIFY_ALL_BITS, &notif, OS_TASK_NOTIFY_FOREVER);/* This must block forever, until a task notification is received. So, thereturn value must be OS_TASK_NOTIFY_SUCCESS */OS_ASSERT(ret == OS_TASK_NOTIFY_SUCCESS);/* Resume watchdog */sys_watchdog_notify_and_resume(wdog_id);/* Notified from BLE Manager? */if (notif & BLE_APP_NOTIFY_MASK) {ble_evt_hdr_t *hdr;hdr = ble_get_event(false);     //有没有事件if (!hdr) {goto no_event;          //没有事件}if (!ble_service_handle_event(hdr)) {       //有事件但没有被处理switch (hdr->evt_code) {case BLE_EVT_GAP_CONNECTED:handle_evt_gap_connected((ble_evt_gap_connected_t *) hdr);break;case BLE_EVT_GAP_CONNECTION_COMPLETED:handle_evt_gap_conn_completed((ble_evt_gap_connection_completed_t *) hdr);break;case BLE_EVT_GAP_DISCONNECTED:handle_evt_gap_disconnected((ble_evt_gap_disconnected_t *) hdr);break;case BLE_EVT_GAP_ADV_COMPLETED:handle_evt_gap_adv_completed((ble_evt_gap_adv_completed_t *) hdr);break;case BLE_EVT_GAP_PAIR_REQ:handle_evt_gap_pair_req((ble_evt_gap_pair_req_t *) hdr);break;case BLE_EVT_GAP_SECURITY_REQUEST:handle_evt_gap_security_request((ble_evt_gap_security_request_t *) hdr);break;default:ble_handle_event_default(hdr);break;}}OS_FREE(hdr);no_event:               //处理没有事件的情况/* Notify again if there are more events to process in queue */if (ble_has_event()) {  //检查是否还有其他事件待处理//如果还有事件,重新通知当前任务,确保任务会再次被唤醒来处理这些事件OS_TASK_NOTIFY(OS_GET_CURRENT_TASK(), BLE_APP_NOTIFY_MASK,OS_NOTIFY_SET_BITS);}}}
}
三、dlg_mls_init

        从上到下依次做了 

申请并清空了一个自定义的服务结构体

        ml_service_t *dlg_mls;

        dlg_mls = OS_MALLOC(sizeof(ml_service_t));
        memset(dlg_mls, 0, sizeof(ml_service_t));

ml_service_t 结构体如下

typedef struct {

ble_service_t svc;                                      //BLE 服务的基本结构体

bd_addr_write_cb_t addr_write_cb;          //指向外设地址写回调函数的指针

uint16_t periph_addr_val_h;                      //服务的特征句柄,用于后面处理写请求

} ml_service_t;

 计算获得服务的属性数量

        num_attr = ble_gatts_get_num_attr(0, 1, 0);

3个参数分别为

  • 0: 服务中的包含数。
  • 1: 特征数。
  • 0: 特征描述符的数量。

将服务的 UUID 字符串(UUID_DLG_MLS)转换为 att_uuid_t 类型的 UUID,并存储在 uuid 变量中。 

        ble_uuid_from_string(UUID_DLG_MLS, &uuid);

添加一个新的 BLE 服务:

        ble_gatts_add_service(&uuid, GATT_SERVICE_PRIMARY, num_attr);

  • &uuid: 指向服务的 UUID。
  • GATT_SERVICE_PRIMARY: 表示这是一个主服务。
  • num_attr: 服务的属性数量(包括特征、描述符等)。

将特征的 UUID 字符串(UUID_DLG_MLS_PERIPHERAL_ADDR)转换为 att_uuid_t 类型的 UUID,并存储在 uuid 变量中。

        ble_uuid_from_string(UUID_DLG_MLS_PERIPHERAL_ADDR, &uuid);

添加一个新的特征到刚刚创建的服务中:

        ble_gatts_add_characteristic(&uuid, GATT_PROP_WRITE_NO_RESP, ATT_PERM_WRITE, 7, 0, NULL, &dlg_mls->periph_addr_val_h);

  • &uuid: 指向特征的 UUID。
  • GATT_PROP_WRITE_NO_RESP: 特征属性,表示特征支持无应答的写操作。
  • ATT_PERM_WRITE: 特征的权限,表示该特征可以被写入。
  • 7: 特征值的最大长度(字节数)。
  • 0: 不使用额外的安全权限。
  • NULL: 初始值为空。
  • &dlg_mls->periph_addr_val_h: 存储特征的句柄,稍后会用于标识这个特征。

注册服务及其所有特征:

        ble_gatts_register_service(&dlg_mls->svc.start_h, &dlg_mls->periph_addr_val_h, 0);

  • &dlg_mls->svc.start_h: 存储服务的起始句柄。
  • &dlg_mls->periph_addr_val_h: 存储特征的句柄(已在上一步中设置)。
  • 0: 表示无更多的特征需要注册。

计算并设置服务的结束句柄。服务的结束句柄等于起始句柄加上属性数量。

        dlg_mls->svc.end_h = dlg_mls->svc.start_h + num_attr;

设置服务的写请求处理函数,将 handle_write_req 函数指针赋值给服务的 write_req 字段,以处理特征的写请求。

        dlg_mls->svc.write_req = handle_write_req;

将传入的回调函数 addr_write_cb 赋值给 dlg_mls 结构体的 addr_write_cb 字段。这个回调将在写请求处理过程中被调用。这里就是前面的dlg_mls_init(bd_addr_write_cb);参数

        dlg_mls->addr_write_cb = addr_write_cb;

将刚刚创建并初始化好的服务添加到 BLE 框架中,使其可以被外部设备访问。

        ble_service_add(&dlg_mls->svc);

完整代码

/******************************************************************************************** @file dlg_mls.c** @brief Dialog Multi-Link Service sample implementation** Copyright (C) 2015-2017 Dialog Semiconductor.* This computer program includes Confidential, Proprietary Information* of Dialog Semiconductor. All Rights Reserved.******************************************************************************************/#include <stdbool.h>
#include <stddef.h>
#include <string.h>
#include "osal.h"
#include "ble_gatts.h"
#include "ble_uuid.h"
#include "svc_defines.h"
#include "dlg_mls.h"#define UUID_DLG_MLS                        "3292546e-0a42-4348-aa38-33aab6f9af93"
#define UUID_DLG_MLS_PERIPHERAL_ADDR        "3292546e-0a42-4348-aa38-33aab6f9af94"typedef struct {ble_service_t svc;bd_addr_write_cb_t addr_write_cb;uint16_t periph_addr_val_h;
} ml_service_t;static att_error_t handle_peripheral_address_write(ml_service_t *dlg_mls, uint16_t conn_idx,uint16_t offset, uint16_t length, const uint8_t *value)
{
//        printf("handle_peripheral_address_write\r\n");if (!dlg_mls->addr_write_cb) {return ATT_ERROR_WRITE_NOT_PERMITTED;}if (length != sizeof(bd_address_t) || !value) {return ATT_ERROR_INVALID_VALUE_LENGTH;}if (value[0] != PUBLIC_ADDRESS && value[0] != PRIVATE_ADDRESS) {return ATT_ERROR_APPLICATION_ERROR;}dlg_mls->addr_write_cb(&dlg_mls->svc, conn_idx, (bd_address_t *) value);return ATT_ERROR_OK;
}static void handle_write_req(ble_service_t *svc, const ble_evt_gatts_write_req_t *evt)
{
//    printf("handle_write_req\r\n");ml_service_t *dlg_mls = (ml_service_t *) svc;att_error_t status = ATT_ERROR_ATTRIBUTE_NOT_FOUND;if (evt->handle == dlg_mls->periph_addr_val_h) {status = handle_peripheral_address_write(dlg_mls, evt->conn_idx, evt->offset,evt->length, evt->value);}ble_gatts_write_cfm(evt->conn_idx, evt->handle, status);
}ble_service_t *dlg_mls_init(bd_addr_write_cb_t addr_write_cb)
{uint16_t num_attr;ml_service_t *dlg_mls;att_uuid_t uuid;dlg_mls = OS_MALLOC(sizeof(ml_service_t));memset(dlg_mls, 0, sizeof(ml_service_t));num_attr = ble_gatts_get_num_attr(0, 1, 0);ble_uuid_from_string(UUID_DLG_MLS, &uuid);ble_gatts_add_service(&uuid, GATT_SERVICE_PRIMARY, num_attr);ble_uuid_from_string(UUID_DLG_MLS_PERIPHERAL_ADDR, &uuid);ble_gatts_add_characteristic(&uuid, GATT_PROP_WRITE_NO_RESP, ATT_PERM_WRITE,7, 0, NULL, &dlg_mls->periph_addr_val_h);ble_gatts_register_service(&dlg_mls->svc.start_h, &dlg_mls->periph_addr_val_h, 0);dlg_mls->svc.end_h = dlg_mls->svc.start_h + num_attr;dlg_mls->svc.write_req = handle_write_req;dlg_mls->addr_write_cb = addr_write_cb;ble_service_add(&dlg_mls->svc);return &dlg_mls->svc;
}

创建完后生成的服务,其服务的UUID与一个特征值的UUID一一对应

四、向上写数据的流程
  • 当手机端向 BLE 设备写入数据时,设备会触发 handle_write_req 函数,该函数负责处理所有写入请求。
  • handle_write_req 检查写请求的 handle 是否与 dlg_mls->periph_addr_val_h 匹配,这意味着客户端请求写入的是设备的外设地址特性。如果匹配,则调用 handle_peripheral_address_write 函数来处理写入操作,并将结果返回到 status
  • 在handle_peripheral_address_write做数据检查,检查都通过了,调用 addr_write_cb 回调函数,将写入的地址数据传递给回调函数进行进一步处理。
  • addr_write_cb(&dlg_mls->svc, conn_idx, (bd_address_t *) value);回调函数
    • &dlg_mls->svc:

      • 这是一个指向 BLE 服务 (ble_service_t) 的指针,表示当前正在处理的 BLE 服务实例。在回调函数中,这个指针可以用于获取或操作服务的相关信息。
    • conn_idx:

      • 这是一个 uint16_t 类型的值,表示当前连接的索引。它唯一标识了设备与客户端之间的连接。在回调函数中,可以用它来区分来自不同连接的请求。
    • (bd_address_t *) value:

      • 这是一个指向 bd_address_t 类型的指针,bd_address_t 结构体表示一个蓝牙设备的地址(包含地址类型和实际地址)。
      • value 是一个指向原始数据的 uint8_t 指针,在这里被强制转换为 bd_address_t 类型。在回调函数中,可以通过这个指针来访问写入的设备地址。
  • 写入操作完成后,设备将结果通过 ble_gatts_write_cfm 函数反馈给手机端,告知操作是否成功。

 

 

 

这篇关于DA14695---multi-link简单解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1094770

相关文章

SQL 外键Foreign Key全解析

《SQL外键ForeignKey全解析》外键是数据库表中的一列(或一组列),用于​​建立两个表之间的关联关系​​,外键的值必须匹配另一个表的主键(PrimaryKey)或唯一约束(UniqueCo... 目录1. 什么是外键?​​ ​​​​2. 外键的语法​​​​3. 外键的约束行为​​​​4. 多列外键​

Java进行日期解析与格式化的实现代码

《Java进行日期解析与格式化的实现代码》使用Java搭配ApacheCommonsLang3和Natty库,可以实现灵活高效的日期解析与格式化,本文将通过相关示例为大家讲讲具体的实践操作,需要的可以... 目录一、背景二、依赖介绍1. Apache Commons Lang32. Natty三、核心实现代

使用Python自动化生成PPT并结合LLM生成内容的代码解析

《使用Python自动化生成PPT并结合LLM生成内容的代码解析》PowerPoint是常用的文档工具,但手动设计和排版耗时耗力,本文将展示如何通过Python自动化提取PPT样式并生成新PPT,同时... 目录核心代码解析1. 提取 PPT 样式到 jsON关键步骤:代码片段:2. 应用 JSON 样式到

Maven 插件配置分层架构深度解析

《Maven插件配置分层架构深度解析》:本文主要介绍Maven插件配置分层架构深度解析,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录Maven 插件配置分层架构深度解析引言:当构建逻辑遇上复杂配置第一章 Maven插件配置的三重境界1.1 插件配置的拓扑

全解析CSS Grid 的 auto-fill 和 auto-fit 内容自适应

《全解析CSSGrid的auto-fill和auto-fit内容自适应》:本文主要介绍了全解析CSSGrid的auto-fill和auto-fit内容自适应的相关资料,详细内容请阅读本文,希望能对你有所帮助... css  Grid 的 auto-fill 和 auto-fit/* 父元素 */.gri

Maven 依赖发布与仓库治理的过程解析

《Maven依赖发布与仓库治理的过程解析》:本文主要介绍Maven依赖发布与仓库治理的过程解析,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下... 目录Maven 依赖发布与仓库治理引言第一章:distributionManagement配置的工程化实践1

MySQL复合查询从基础到多表关联与高级技巧全解析

《MySQL复合查询从基础到多表关联与高级技巧全解析》本文主要讲解了在MySQL中的复合查询,下面是关于本文章所需要数据的建表语句,感兴趣的朋友跟随小编一起看看吧... 目录前言:1.基本查询回顾:1.1.查询工资高于500或岗位为MANAGER的雇员,同时还要满足他们的姓名首字母为大写的J1.2.按照部门

Spring三级缓存解决循环依赖的解析过程

《Spring三级缓存解决循环依赖的解析过程》:本文主要介绍Spring三级缓存解决循环依赖的解析过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、循环依赖场景二、三级缓存定义三、解决流程(以ServiceA和ServiceB为例)四、关键机制详解五、设计约

Redis实现分布式锁全解析之从原理到实践过程

《Redis实现分布式锁全解析之从原理到实践过程》:本文主要介绍Redis实现分布式锁全解析之从原理到实践过程,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、背景介绍二、解决方案(一)使用 SETNX 命令(二)设置锁的过期时间(三)解决锁的误删问题(四)Re

Qt实现网络数据解析的方法总结

《Qt实现网络数据解析的方法总结》在Qt中解析网络数据通常涉及接收原始字节流,并将其转换为有意义的应用层数据,这篇文章为大家介绍了详细步骤和示例,感兴趣的小伙伴可以了解下... 目录1. 网络数据接收2. 缓冲区管理(处理粘包/拆包)3. 常见数据格式解析3.1 jsON解析3.2 XML解析3.3 自定义