SQLite轻量级会话扩展(三十四)

返回:SQLite—系列文章目录   

上一篇:SQLite R*Tree 模块(三十三)

下一篇:SQLite—系列文章目录   

1. 引言

会话扩展提供了一种方便记录的机制 对 SQLite 数据库中某些表的部分或全部更改,以及 将这些更改打包到“变更集”或“补丁集”文件中,可以 稍后用于将同一组更改应用于另一个数据库 相同的架构和兼容的起始数据。“变更集”可能 也可以倒置并用于“撤消”会话。

本文档是对会话扩展的介绍。 该接口的详细信息位于单独的会话扩展 C 语言接口文档中。

1.1. 典型用例

假设 SQLite 被用作应用程序文件格式 特定的设计应用。两个用户 Alice 和 Bob 分别启动 基线设计大小约为 1 GB。他们工作 一整天,并行,每个人都在进行自己的定制和调整 到设计。归根结底,他们想合并他们的 一起改变成一个统一的设计。

会话扩展通过记录对 Alice 和 Bob 的数据库,并将这些更改写入 变更集或补丁集文件。在一天结束时,爱丽丝可以送她 changeset 到 Bob,Bob 可以将其“应用”到他的数据库中。结果(假设 没有冲突)是 Bob 的数据库包含他的 变化和爱丽丝的变化。同样,Bob 可以发送 他的工作交给了爱丽丝,她可以将他的更改应用到她的数据库中。

换言之,会话扩展提供了以下工具: 类似于 unix 补丁实用程序的 SQLite 数据库文件, 或版本控制系统的“合并”功能,例如 饰演 Fossil, Git, 或Mercurial。

1.2. 获取会话扩展

自 3.13.0 版(2016-05-18)起, 会话扩展已包含在 SQLite 合并源分发中。默认情况下,会话扩展为 禁用。若要启用它,请使用以下编译器开关进行生成:

-DSQLITE_ENABLE_SESSION -DSQLITE_ENABLE_PREUPDATE_HOOK

或者,如果使用 autoconf 构建系统, 将 --enable-session 选项传递给 configure 脚本。

1.3. 限制

  • 在 SQLite 版本 3.17.0 之前,会话扩展仅适用于 rowid 表,而不适用于 ROWID 表。从 3.17.0 开始,两者都 支持 rowid 和 WITHOUT ROWID 表。但是,额外的步骤是 需要记录 WITHOUT ROWID 表更改的主键。

  • 不支持虚拟表。对虚拟表的更改包括 未捕获。

  • 会话扩展仅适用于声明了 主键。表的 PRIMARY KEY 可以是 INTEGER PRIMARY KEY (rowid 别名)或外部 PRIMARY KEY。

  • SQLite 允许将 NULL 值存储在 PRIMARY KEY 列。但是,会话扩展会忽略所有 这样的行。不会影响具有一个或多个 NULL 值的行的更改 在 PRIMARY KEY 中,列由 sessions 模块记录。

2. 概念

2.1. 变更集和补丁集

会话模块围绕创建和操作展开 变更集。变更集是编码一系列 对数据库的更改。变更集中的每个更改都是 以后:

  • 一个 INSERT。INSERT 更改包含要添加到的单行 数据库表。INSERT 更改的有效负载包括 新行的每个字段的值。

  • A 删除。DELETE 更改表示一行,由 其主键值,要从数据库表中删除。有效载荷 的 DELETE 更改由 已删除的行。

  • 更新。UPDATE 更改表示对 数据库中单行的一个或多个非 PRIMARY KEY 字段 表,由其 PRIMARY KEY 字段标识。UPDATE 的有效负载 更改包括:

    • 标识修改后的行的 PRIMARY KEY 值,
    • 行中每个已修改字段的新值,以及
    • 行中每个已修改字段的原始值。

    UPDATE 更改不包含有关以下方面的任何信息 未被更改修改的非 PRIMARY KEY 字段。事实并非如此 UPDATE 更改可以指定对 PRIMARY 的修改 KEY 字段。

单个变更集可能包含适用于多个变更集的变更 数据库表。对于变更集至少包含一个更改的每个表 因为,它还对以下数据进行编码:

  • 数据库表的名称,
  • 表的列数,以及
  • 这些列中哪一列是 PRIMARY KEY 列。

变更集只能应用于包含表的数据库 匹配变更集中存储的上述三个条件。

补丁集类似于变更集。它比 变更集,但提供更有限的冲突检测和解决 选项(有关详细信息,请参阅下一节)。之间的区别 patchset 和 changeset 是:

  • 对于 DELETE 更改,有效负载由 PRIMARY KEY 组成 仅限字段。其他字段的原始值不存储为 补丁集的一部分。

  • 对于 UPDATE 更改,有效负载由 PRIMARY KEY 组成 字段和仅修改字段的新值。原文 已修改字段的值不会存储为补丁集的一部分。

2.2. 冲突

当变更集或补丁集应用于数据库时,尝试是 为每个 INSERT 更改插入一个新行,为每个更改删除一行 DELETE 更改并修改每个 UPDATE 更改的一行。如果目标 数据库与变更集的原始数据库处于相同的状态 被记录下来,这是一件简单的事情。但是,如果 目标数据库并不完全处于此状态,当以下情况下可能会发生冲突 应用变更集或补丁集。

处理 INSERT 更改时,以下冲突可能 发生:

  • 目标数据库可能已包含具有相同 PRIMARY 的行 由 INSERT 更改指定的 KEY 值。
  • 其他一些数据库约束,例如 UNIQUE 或 CHECK 约束,在插入新行时可能会被违反。

处理 DELETE 更改时,可能会出现以下冲突: 检测:

  • 目标数据库可能不包含具有指定 PRIMARY 的行 要删除的 KEY 值。
  • 目标数据库可能包含具有指定 PRIMARY 的行 KEY 值,但其他字段可能包含不 匹配存储为变更集一部分的那些。这种类型的冲突 使用补丁集时未检测到。

处理 UPDATE 更改时,可能会出现以下冲突: 检测:

  • 目标数据库可能不包含具有指定 PRIMARY 的行 要修改的 KEY 值。
  • 目标数据库可能包含具有指定 PRIMARY 的行 KEY 值,但要修改的字段的当前值 通过更改可能与存储在 变更集。使用修补程序集时,不会检测到此类冲突。
  • 其他一些数据库约束,例如 UNIQUE 或 CHECK 约束,更新行时可能会被违反。

根据冲突的类型,会话应用程序具有多种 用于处理冲突的可配置选项,范围从省略 冲突的更改、中止整个变更集应用程序或应用 尽管存在冲突,但变化。有关详细信息,请参阅文档 sqlite3changeset_apply() API。

2.3. 变更集构造

配置会话对象后,它将开始监视 对其配置表的更改。但是,它不会记录整个 每次修改数据库中的行时进行更改。相反,它会记录 仅插入每个行的 PRIMARY KEY 字段,以及 PRIMARY KEY 以及任何更新或删除的行的所有原始行值。如果一行是 单个会话多次修改,不会记录新信息。

创建变更集或补丁集所需的其他信息包括 调用 sqlite3session_changeset() 或 sqlite3session_patchset() 时从数据库文件中读取。具体说来

  • 对于作为 INSERT 操作结果记录的每个主键, 会话模块检查是否存在具有匹配主节点的行 键仍在表中。如果是这样,则将 INSERT 更改添加到 变更集。

  • 对于作为 UPDATE 或 DELETE 结果记录的每个主键 操作中,会话模块还会检查具有匹配的行 表中的主键。如果可以找到一个,但一个或多个 非 PRIMARY KEY 字段与原始记录不匹配 值,则 UPDATE 将添加到变更集中。或者,如果没有行 使用指定的主键时,DELETE 将添加到 变更集。如果该行确实存在,但没有非主键 字段已修改,变更集不会添加任何更改。

上述的一个含义是,如果进行了更改,然后 在单个会话中取消(例如,如果插入了一行,然后 再次删除),会话模块根本不会报告任何更改。或 如果同一会话中同一行多次更新,则所有更新 合并到任何变更集或修补程序集 blob 中的单个更新中。

3. 使用会话扩展

本节提供的示例演示了如何使用会话 外延。

3.1. 捕获变更集

下面的示例代码演示了捕获 执行 SQL 命令时的变更集。综上所述:

  1. 会话对象(类型 sqlite3_session*)是通过创建 调用 sqlite3session_create() API 函数。

    单个会话对象监视对单个数据库所做的更改 (即“main”、“temp”或附加数据库)通过单个 sqlite3* 数据库句柄。

  2. 会话对象配置了一组要监视的表 更改。

    默认情况下,会话对象不会监视任何 数据库表。在执行此操作之前,必须对其进行配置。那里 是配置表集以监视更改的三种方法 上:

    • 通过对每个表使用一次对 sqlite3session_attach() 的调用显式指定表,或者
    • 通过指定应监视数据库中的所有表 对于使用对 sqlite3session_attach() 的调用进行更改,带有 NULL 参数,或者
    • 通过配置每个表首次调用的回调 写入该会话模块,指示会话模块是否或 不应监视表上的更改。

    下面的示例代码使用枚举的第二个方法 上面 - 它监视所有数据库表上的更改。

  3. 通过执行 SQL 语句对数据库进行更改。这 会话对象记录这些更改。

  4. 使用调用从会话对象中提取变更集 Blob to sqlite3session_changeset() (或者,如果使用补丁集,则调用 sqlite3session_patchset() 函数)。

  5. 使用对 sqlite3session_delete() API 函数的调用删除会话对象。

    解压后无需删除会话对象 来自它的变更集或补丁集。它可以留在 数据库句柄,并将继续监视 像以前一样配置了表。但是,如果 sqlite3session_changeset() 或 sqlite3session_patchset() 是 对会话对象、变更集或补丁集进行第二次调用 将包含连接上发生的所有更改 自会话创建以来。换言之, 会话对象未重置或 通过调用 sqlite3session_changeset()或 sqlite3session_patchset()。

/*
** Argument zSql points to a buffer containing an SQL script to execute
** against the database handle passed as the first argument. As well as
** executing the SQL script, this function collects a changeset recording
** all changes made to the "main" database file. Assuming no error occurs,
** output variables (*ppChangeset) and (*pnChangeset) are set to point
** to a buffer containing the changeset and the size of the changeset in
** bytes before returning SQLITE_OK. In this case it is the responsibility
** of the caller to eventually free the changeset blob by passing it to
** the sqlite3_free function.
**
** Or, if an error does occur, return an SQLite error code. The final
** value of (*pChangeset) and (*pnChangeset) are undefined in this case.
*/
int sql_exec_changeset(
  sqlite3 *db,                  /* Database handle */
  const char *zSql,             /* SQL script to execute */
  int *pnChangeset,             /* OUT: Size of changeset blob in bytes */
  void **ppChangeset            /* OUT: Pointer to changeset blob */
){
  sqlite3_session *pSession = 0;
  int rc;

  /* Create a new session object */
  rc = sqlite3session_create(db, "main", &pSession);

  /* Configure the session object to record changes to all tables */
  if( rc==SQLITE_OK ) rc = sqlite3session_attach(pSession, NULL);

  /* Execute the SQL script */
  if( rc==SQLITE_OK ) rc = sqlite3_exec(db, zSql, 0, 0, 0);

  /* Collect the changeset */
  if( rc==SQLITE_OK ){
    rc = sqlite3session_changeset(pSession, pnChangeset, ppChangeset);
  }

  /* Delete the session object */
  sqlite3session_delete(pSession);

  return rc;
}

3.2. 将变更集应用于数据库

将变更集应用于数据库比捕获变更集更简单。 通常,对 sqlite3changeset_apply() 的单个调用,如 下面的示例代码就足够了。

在复杂的情况下,应用 变更集在于解决冲突。请参阅链接的 API 文档 以上了解详情。

/*
** Conflict handler callback used by apply_changeset(). See below.
*/
static int xConflict(void *pCtx, int eConflict, sqlite3_changset_iter *pIter){
  int ret = (int)pCtx;
  return ret;
}

/*
** Apply the changeset contained in blob pChangeset, size nChangeset bytes,
** to the main database of the database handle passed as the first argument.
** Return SQLITE_OK if successful, or an SQLite error code if an error
** occurs.
**
** If parameter bIgnoreConflicts is true, then any conflicting changes
** within the changeset are simply ignored. Or, if bIgnoreConflicts is
** false, then this call fails with an SQLTIE_ABORT error if a changeset
** conflict is encountered.
*/
int apply_changeset(
  sqlite3 *db,                  /* Database handle */
  int bIgnoreConflicts,         /* True to ignore conflicting changes */
  int nChangeset,               /* Size of changeset in bytes */
  void *pChangeset              /* Pointer to changeset blob */
){
  return sqlite3changeset_apply(
      db,
      nChangeset, pChangeset,
      0, xConflict,
      (void*)bIgnoreConflicts
  );
}

3.3. 检查变更集的内容

下面的示例代码演示了用于迭代的技术 通过并提取与变更集中的所有更改相关的数据。自 总结:

  1. 调用 sqlite3changeset_start() API 来创建和 初始化迭代器以遍历 变更集。最初,迭代器根本不指向任何元素。

  2. 在迭代器上对 sqlite3changeset_next() 的第一次调用会移动 它指向变更集中的第一个更改(或指向 EOF,如果 变更集完全为空)。sqlite3changeset_next() 返回 SQLITE_ROW 如果它移动迭代器以指向有效条目, SQLITE_DONE是否将迭代器移动到 EOF,或者出现 SQLite 错误 如果发生错误,则进行代码。

  3. 如果迭代器指向有效条目,则 sqlite3changeset_op() API 可用于确定更改类型(INSERT、UPDATE 或 DELETE),迭代器指向。此外,相同的 API 可用于获取更改所适用的表的名称 以及其预期的列数和主键列数。

  4. 如果迭代器指向有效的 INSERT 或 UPDATE 条目,则可以使用 sqlite3changeset_new() API 来获取新的 .* 值 在更改有效负载中。

  5. 如果迭代器指向有效的 DELETE 或 UPDATE 条目,则可以使用 sqlite3changeset_old() API 获取旧的 .* 值 在更改有效负载中。

  6. 使用对 sqlite3changeset_finalize() API 的调用删除迭代器。如果在 迭代时,返回 SQLite 错误代码(即使相同的错误 代码已由 sqlite3changeset_next()) 返回。或 如果未发生错误,则返回SQLITE_OK。

/*
** Print the contents of the changeset to stdout.
*/
static int print_changeset(void *pChangeset, int nChangeset){
  int rc;
  sqlite3_changeset_iter *pIter = 0;

  /* Create an iterator to iterate through the changeset */
  rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset);
  if( rc!=SQLITE_OK ) return rc;

  /* This loop runs once for each change in the changeset */
  while( SQLITE_ROW==sqlite3changeset_next(pIter) ){
    const char *zTab;           /* Table change applies to */
    int nCol;                   /* Number of columns in table zTab */
    int op;                     /* SQLITE_INSERT, UPDATE or DELETE */
    sqlite3_value *pVal;

    /* Print the type of operation and the table it is on */
    rc = sqlite3changeset_op(pIter, &zTab, &nCol, &op, 0);
    if( rc!=SQLITE_OK ) goto exit_print_changeset;
    printf("%s on table %s\n",
      op==SQLITE_INSERT?"INSERT" : op==SQLITE_UPDATE?"UPDATE" : "DELETE",
      zTab
    );

    /* If this is an UPDATE or DELETE, print the old.* values */
    if( op==SQLITE_UPDATE || op==SQLITE_DELETE ){
      printf("Old values:");
      for(i=0; i<nCol; i++){
        rc = sqlite3changeset_old(pIter, i, &pVal);
        if( rc!=SQLITE_OK ) goto exit_print_changeset;
        printf(" %s", pVal ? sqlite3_value_text(pVal) : "-");
      }
      printf("\n");
    }

    /* If this is an UPDATE or INSERT, print the new.* values */
    if( op==SQLITE_UPDATE || op==SQLITE_INSERT ){
      printf("New values:");
      for(i=0; i<nCol; i++){
        rc = sqlite3changeset_new(pIter, i, &pVal);
        if( rc!=SQLITE_OK ) goto exit_print_changeset;
        printf(" %s", pVal ? sqlite3_value_text(pVal) : "-");
      }
      printf("\n");
    }
  }

  /* Clean up the changeset and return an error code (or SQLITE_OK) */
 exit_print_changeset:
  rc2 = sqlite3changeset_finalize(pIter);
  if( rc==SQLITE_OK ) rc = rc2;
  return rc;
}

4. 扩展功能

大多数应用程序将仅使用所描述的会话模块功能 在上一节中。但是,以下附加功能是 可用于使用和操作变更集和修补程序集 Blob:Available for the use and manipulation of changeset and patchset blob:

  • 可以使用 sqlite3changeset_concat() 或 sqlite3_changegroup 接口组合两个或多个变更集/补丁集。

  • 可以使用 sqlite3changeset_invert() API 函数“反转”变更集。反向变更集撤消了 源语言。如果变更集 C+ 是变更集 C 的逆,则 将 C 和 C+ 应用于数据库应该会离开 数据库未更改。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/561437.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

视频质量评价 SSIM 算法详细介绍

SSIM SSIM(Structural Similarity Index Measure)是一种用于衡量两幅图像之间相似度的指标,是属于全参考视频质量评价算法范畴;它在图像质量评估领域得到了广泛的应用。SSIM是基于人类视觉系统的特性设计的,它考虑了图像的亮度、对比度和结构信息。SSIM的值范围在-1到1之…

xilinx 7系列FPGA时钟布线资源

7系列FPGA拥有多种时钟路由资源&#xff0c;以支持各种时钟方案和需求&#xff0c;包括高扇出、短传播延迟以及极低的偏斜。为了最佳地利用时钟路由资源&#xff0c;需要了解如何将用户时钟从PCB传递到FPGA&#xff0c;确定哪种时钟路由资源最优&#xff0c;然后通过利用适当的…

【数据结构|C语言版】单链表

前言1. 单链表的概念和结构1.1 单链表的概念1.2 单链表的结构 2. 单链表的分类3.单链表的实现3.1 新节点创建3.2 单链表头插3.3 单链表头删3.4 单链表尾插3.5 单链表尾删3.6 链表销毁 4. 代码总结4.1 SLT.h4.2 SLT.c4.3 test.c 后言 前言 各位小伙伴大家好&#xff01;时隔不久…

百科不全书之 docker记录

docker记录 1.参考文件2. Docker简介与虚拟机的区别 3. 安装Docker注意 Windows家庭版的要额外设置 4.使用5.docker与ROS 1.参考文件 参考视频&#xff1a;B站【GeekHour】Docker入门教程: 【GeekHour】30分钟Docker入门教程 2. Docker简介 Docker是一个用于构建运行 传送…

The C programming language (second edition,KR) exercise(CHAPTER 4)

E x c e r c i s e 4 − 1 Excercise\quad 4-1 Excercise4−1&#xff1a; #include <stdlib.h> #include <stdio.h> #include <string.h> int strindex(char s[],char t[]); int strrindex(char s[],char t[]);int main(void) {char s[100]"qwoulddf…

Java | Leetcode Java题解之第41题缺失的第一个正数

题目&#xff1a; 题解&#xff1a; class Solution {public int firstMissingPositive(int[] nums) {int n nums.length;for (int i 0; i < n; i) {while (nums[i] > 0 && nums[i] < n && nums[nums[i] - 1] ! nums[i]) {int temp nums[nums[i] …

yolov8实战第七天——pyqt5-yolov8实现车牌识别系统(参考论文(约7000字)+环境配置+完整部署代码+代码使用说明+训练好的模型)

基于 pyqt5-yolov8实现车牌识别系统,包括图片车牌识别,视频车牌识别,视频流车牌识别。 效果展示(图片检测,检测到的内容添加到历史记录): 效果展示(视频检测,视频车辆只会添加一条记录,下文更多实际应用中的优化策略): 基于YOLOv8和PyQt5的车牌识别系统设计与…

存储竞赛,角逐未来

随着人工智能&#xff08;AI&#xff09;和大数据驱动的海量数据需求&#xff0c;对存储技术的要求也在不断提高。在此背景下&#xff0c;各大存储芯片巨头之间的技术竞赛日益激烈。 在NAND闪存领域&#xff0c;企业关注的重点在于层数的突破。近日&#xff0c;《韩国经济日报》…

linux下编译c++程序报错“undefined reference to `std::allocator<char>::allocator()‘”

问题 linux下编译c程序报错“undefined reference to std::allocator::allocator()”。 原因 找不到c标准库文件。 解决办法 开始尝试给gcc指令添加-L和-l选项指定库路径和库文件名&#xff0c;但是一直不成功&#xff0c;后来把gcc改为g就可以了。

Stylus精讲:网页设计新境界【写作AI一键生成】

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

SWCTF

easy_php 源码 <?php// flag is in flag.php highlight_file(__FILE__); ini_set(display_errors, 0); error_reporting(0);if (isset($_GET[myon1]) && isset($_GET[myon2]) && isset($_GET[myon3])) {$myon1 $_GET[myon1];$myon2 $_GET[myon2];$myon…

# Win10 打不开【本地组策略编辑器】解决方案

Win10 打不开【本地组策略编辑器】解决方案 段子手168 问题描述&#xff1a; 当在 WIN R 打开【运行】输入&#xff1a;gpedit.msc 打开【本地组策略编辑器】时&#xff0c;出现错误时&#xff0c; 或者在【计算机管理】中 没有【本地用户和组】这一项。 可以试一下以下方…

Go 之 sync.Mutex 加锁失效现象

我先声明一下&#xff0c;并不是真的加锁失效&#xff0c;而是我之前的理解有误&#xff0c;导致看起来像是加锁失效一样。于是乎记录一下&#xff0c;加深一下印象。 我之前有个理解误区&#xff08;不知道大家有没有&#xff0c;有的话赶紧纠正一下——其实也是因为我这块的…

Spec-Gaussian:3D高斯溅射的各向异性视图相关外观

Spec-Gaussian: Anisotropic View-Dependent Appearance for 3D Gaussian Splatting Spec-Gaussian&#xff1a;3D高斯溅射的各向异性视图相关外观 Ziyi Yang1,3  Xinyu Gao1  Yangtian Sun2  Yihua Huang2  Xiaoyang Lyu2 杨子怡 1,3 高新宇 1 太阳扬天 2 黄宜华 2 吕晓阳…

【github主页】优化简历

【github主页】优化简历 写在最前面一、新建秘密仓库二、插件卡片配置1、仓库状态统计2、Most used languages&#xff08;GitHub 常用语言统计&#xff09;使用细则 3、Visitor Badge&#xff08;GitHub 访客徽章&#xff09;4、社交统计5、打字特效6、省略展示小猫 &#x1f…

Java+springboot开发的医院智能导诊服务系统源码 自动兼容小程序与H5版本

智能导诊系统 一、什么是智慧导诊系统&#xff1f; 智慧导诊系统是一种医院使用的引导患者自助就诊挂号、精准推荐科室、引导患者挂号就诊的系统。该系统结合医院挂号及就诊的HIS系统&#xff0c;为患者带来全流程的信息指引提醒&#xff0c;可以在全院区构建一个精细化、移动…

react 项目路由配置(react-router-dom 版本 v6.3、v6.4)

根据 react-router-dom 的版本&#xff0c;有不同的方式 一、react-router-dom v6.3 用到的主要 api: BrowserRouteruseRoutesOutlet 下面是详细步骤&#xff1a; 1、index.js BrowserRouter 用来实现 单页的客户端路由使用 BrowserRouter 包裹 App放在 顶级 位置&#x…

MATLAB初学者入门(7)—— 参数估计

参数估计是利用实验数据来推断模型参数的过程&#xff0c;这在科学和工程领域中非常常见。MATLAB提供了多种工具来进行参数估计&#xff0c;尤其是当模型表现为非线性时。以下是使用MATLAB进行参数估计的一种常见方法&#xff0c;我们将通过一个具体的案例——化学动力学模型的…

EI级 | Matlab实现VMD-TCN-LSTM-MATT变分模态分解卷积长短期记忆神经网络多头注意力多变量时间序列预测

EI级 | Matlab实现VMD-TCN-LSTM-MATT变分模态分解卷积长短期记忆神经网络多头注意力多变量时间序列预测 目录 EI级 | Matlab实现VMD-TCN-LSTM-MATT变分模态分解卷积长短期记忆神经网络多头注意力多变量时间序列预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 1.Matl…

手写一个Spring IOC框架

目录 一&#xff0c;Spring IOC 二&#xff0c;流程图设计 三&#xff0c;设计思路解析 三&#xff0c;开始写代码 1.准备工作: 2.扫描并加载类信息 3.初始化bean 4.测试一下 一&#xff0c;Spring IOC Spring IoC容器是Spring框架的核心&#xff0c;它通过读取配置信息…