今天,我想和大家聊一个在Oracle数据库领域既强大又神秘的话题——触发器(Trigger)​。在座的各位可能都写过SQL语句,做过表结构设计,甚至用过存储过程,但有很多人对触发器的态度可能是"既爱又怕":爱它的自动化能力,怕它的不可控风险。

  我先问大家一个问题:当你在系统中执行一条UPDATE语句修改用户账户余额时,是否希望同时自动记录这笔操作的审计日志?当你删除一张订单时,是否需要级联删除关联的物流信息?当插入一条不符合业务规则的记录时,能否在数据库层面直接拦截而不是依赖应用程序?

  这些场景,都可以通过Oracle触发器轻松实现。它就像数据库的"隐形守护者",在数据操作的背后默默执行着规则,让业务逻辑更严谨,让系统更安全。

一、触发器是什么?为什么需要它?

1.1 触发器的本质

  Oracle触发器是一种存储在数据库中的PL/SQL程序单元,它会在特定的数据库事件(如DML操作、DDL操作、甚至系统事件)发生时被自动触发执行。简单来说,它是数据库的"事件响应器",就像现实中的烟雾报警器——当检测到"烟雾"(特定事件)时,会自动触发"警报"(执行代码)。

1.2 它解决了什么问题?

  传统的数据约束(如主键、外键、CHECK约束)只能处理简单的逻辑校验,但面对复杂的业务规则(如跨表操作、动态计算、审计追踪),它们往往力不从心。例如:

  当员工离职时,需要同时禁用其关联的系统账号;
当财务人员修改大额订单金额时,需要自动记录修改前后的差异;
当插入一条"已删除"状态的记录时,需要阻止操作并提示原因。
这些需求无法仅通过表约束实现,而触发器可以在数据操作的"现场"(BEFORE/AFTER)实时响应,完成应用程序难以处理的跨表联动、审计追踪等任务。

1.3 触发器 vs 应用程序逻辑

  有人可能会问:“为什么不把这些逻辑写在应用程序里?” 这里需要明确两者的边界:
应用程序​:负责用户交互、业务流程编排,需要考虑界面友好性、响应速度;
数据库触发器​:负责数据一致性的"最后一道防线",确保无论数据通过何种方式(应用程序、SQL Developer、第三方工具)修改,规则都能被严格执行。

  举个例子:如果业务规则是"用户积分必须大于0",应用程序可能在提交时校验,但如果有人直接通过SQL Developer执行UPDATE user SET points = -100 WHERE id=1,这时候只有数据库层面的触发器能拦截这种违规操作。

二、触发器的核心类型:从"何时触发"到"如何触发"

  Oracle触发器的分类可以从多个维度展开,理解这些分类是掌握触发器的第一步。

2.1 按触发事件分类

  触发器的"触发源"是数据库事件,主要分为三类:

事件类型说明典型场景
DML 事件当执行 INSERTUPDATEDELETE 等数据操作语言(DML)语句时触发审计日志记录、级联更新、业务规则实时校验
DDL 事件当执行 CREATEALTERDROP 等数据定义语言(DDL)语句时触发表结构变更审计、数据库权限变更监控
系统事件当数据库启动、关闭、用户登录/登出等系统级行为发生时触发数据库状态监控、用户登录日志记录

2.2 按触发时机分类

  触发器可以在事件发生前(BEFORE)或发生后(AFTER)执行,这直接影响它能访问的数据状态:

​  BEFORE触发器​:在DML/DDL操作执行前触发。此时,新数据(如INSERT的新行)尚未提交到表中,可以修改或阻止操作(通过RAISE_APPLICATION_ERROR)。
示例:员工入职时,自动为其生成工号(BEFORE INSERT触发器填充工号字段)。

  ​AFTER触发器​:在DML/DDL操作执行后触发。此时,数据已写入表中,适合执行后续操作(如审计日志、发送通知)。
​ 示例:订单支付成功后(AFTER UPDATE),触发器自动扣减库存。

2.3 按作用级别分类

  触发器可以作用于整张表(语句级)或单条记录(行级),这决定了它的执行频率:

​  语句级触发器​:无论操作影响多少行,仅执行一次。例如,对表执行DELETE * FROM employees,语句级触发器只会触发1次。
​行级触发器​:每条被影响的记录都会触发一次。例如,上述DELETE操作删除了10条记录,行级触发器会触发10次(需声明FOR EACH ROW)。
注意:行级触发器的性能消耗更高,需谨慎使用——如果一张表有10万行,每次DELETE都触发10万次代码,可能导致数据库锁死!

2.4 特殊类型触发器

  除了上述基础类型,Oracle还提供了更灵活的触发器:

  ​INSTEAD OF触发器​:替代原始的DML操作。例如,视图(View)默认不支持直接INSERT/UPDATE,但可以通过INSTEAD OF触发器将对视图的修改映射到基表。
示例:一个视图关联了员工表和部门表,通过INSTEAD OF INSERT触发器,将视图插入操作拆解为向两张基表插入数据。

  ​复合触发器(Compound Trigger)​​:结合了BEFORE/AFTER语句级和行级触发的特性,允许在一个触发器中按事件阶段(BEFORE STATEMENT、BEFORE EACH ROW、AFTER EACH ROW、AFTER STATEMENT)编写逻辑。它主要用于解决行级和语句级操作的协同问题(如统计批量操作的总影响行数)。

三、触发器的实战场景:从简单到复杂

  现在,我们通过几个真实场景,看看触发器如何解决实际问题。

3.1 场景1:数据审计——谁在什么时候改了什么?

  某金融系统需要记录所有用户账户余额的修改记录,包括修改人、修改前金额、修改后金额、修改时间。

​  实现方案​:创建AFTER UPDATE行级触发器,在余额被修改时,将变更信息写入审计表account_audit。

-- 创建审计表
CREATE TABLE account_audit (audit_id      NUMBER PRIMARY KEY,account_id    NUMBER,old_balance   NUMBER,new_balance   NUMBER,changed_by    VARCHAR2(30),change_time   TIMESTAMP
);-- 创建序列用于审计表主键
CREATE SEQUENCE audit_seq;-- 创建AFTER UPDATE行级触发器
CREATE OR REPLACE TRIGGER trg_account_update_audit
AFTER UPDATE OF balance ON accounts
FOR EACH ROW
BEGIN-- 仅当余额实际发生变化时记录IF :OLD.balance <> :NEW.balance THENINSERT INTO account_audit (audit_id, account_id, old_balance, new_balance, changed_by, change_time)VALUES (audit_seq.NEXTVAL, :OLD.account_id, :OLD.balance, :NEW.balance, USER, SYSTIMESTAMP);END IF;
END;
/

  ​效果​:任何对accounts表的balance字段的修改都会自动生成一条审计记录,无需应用程序干预。

3.2 场景2:业务规则强制——禁止"先款后货"的违规操作

  某电商系统中,订单状态必须遵循"待支付→已支付→已发货→已完成"的流程。业务规则要求:未支付的订单(状态=待支付)不能直接修改为"已发货"。

​  实现方案​:创建BEFORE UPDATE触发器,在更新订单状态前检查是否符合规则。

CREATE OR REPLACE TRIGGER trg_order_status_check
BEFORE UPDATE OF status ON orders
FOR EACH ROW
DECLAREv_valid BOOLEAN := FALSE;
BEGIN-- 允许的状态流转:待支付→已支付;已支付→已发货;已发货→已完成CASE WHEN :OLD.status = '待支付' AND :NEW.status = '已支付' THEN v_valid := TRUE;WHEN :OLD.status = '已支付' AND :NEW.status = '已发货' THEN v_valid := TRUE;WHEN :OLD.status = '已发货' AND :NEW.status = '已完成' THEN v_valid := TRUE;ELSE v_valid := FALSE;END CASE;IF NOT v_valid THENRAISE_APPLICATION_ERROR(-20001, '非法状态变更:当前状态=' || :OLD.status || ',尝试变更为=' || :NEW.status);END IF;
END;
/

​  效果​:如果尝试将待支付订单直接改为已发货,数据库会直接抛出错误,阻止操作。

3.3 场景3:级联操作——删除用户时自动清理关联数据

  某社交系统中,用户表(users)与发帖表(posts)、评论表(comments)存在外键关联。业务要求:删除用户时,自动删除其所有发帖和评论。

​  实现方案​:传统的做法是在应用程序中先删帖子、再删评论、最后删用户,但如果有人直接执行DELETE FROM users WHERE id=100,可能导致关联数据残留。通过触发器可以实现"自动级联"。

-- 创建AFTER DELETE语句级触发器
CREATE OR REPLACE TRIGGER trg_user_delete_cascade
AFTER DELETE ON users
FOR EACH ROW
BEGIN-- 删除该用户的所有发帖DELETE FROM posts WHERE user_id = :OLD.id;-- 删除该用户的所有评论DELETE FROM comments WHERE user_id = :OLD.id;
END;
/

​  注意​:这里使用行级触发器(FOR EACH ROW)是因为每条用户记录的删除都需要触发级联操作。但如果用户表有10万条记录,批量删除时可能触发10万次级联DELETE,导致性能问题。实际场景中,更优方案是通过外键的ON DELETE CASCADE属性实现(但仅适用于简单级联),而复杂级联(如需要额外逻辑)仍需触发器。

四、触发器的"双刃剑":编写规范与风险规避

  触发器虽然强大,但一旦滥用,可能成为系统的"性能杀手"或"逻辑炸弹"。以下是我总结的黄金法则​:

4.1 编写规范

  ​命名清晰​:触发器名称应包含业务含义和触发类型,例如trg_order_status_check(订单状态校验触发器)、trg_account_audit(账户审计触发器)。
​  逻辑简洁​:避免在触发器中编写复杂业务逻辑(如多表关联查询、循环),保持原子性。复杂的逻辑应封装到存储过程,触发器仅调用存储过程。
​  事务一致性​:触发器中的操作应与主事务保持一致——如果主事务回滚,触发器的操作也会回滚(因为触发器在事务上下文中执行)。
​错误处理​:尽量使用RAISE_APPLICATION_ERROR抛出明确错误,避免静默失败;如果需要记录错误日志,可通过自治事务(PRAGMA AUTONOMOUS_TRANSACTION)实现,但需谨慎使用(可能导致数据不一致)。

4.2 性能风险与规避

  ​减少行级触发器的使用​:行级触发器每行执行一次,对大表的DML操作(如批量导入)会导致性能骤降。例如,向10万行的表插入数据,行级触发器会执行10万次,而语句级触发器仅执行1次。
避免递归触发​:如果触发器A在执行过程中修改了表T,导致触发器A再次被触发(递归),可能引发死循环或栈溢出。例如:

CREATE OR REPLACE TRIGGER trg_emp_salary_update
AFTER UPDATE OF salary ON employees
FOR EACH ROW
BEGIN-- 如果涨薪超过10%,触发管理员通知IF (:NEW.salary - :OLD.salary) / :OLD.salary > 0.1 THENUPDATE employees SET manager_id = manager_id WHERE id = :OLD.manager_id; -- 修改管理员记录,再次触发触发器END IF;
END;

  这种情况下,修改管理员记录会再次触发同一触发器,导致无限递归。

​  批量操作的优化​:对于批量DML(如INSERT … SELECT),可通过BULK COLLECT和FORALL减少触发器执行次数,或在触发器中判断是否为批量操作(通过SQL%ROWCOUNT)。

4.3 调试与监控

  触发器的调试比普通PL/SQL更困难,因为它是隐式执行的。建议:

  在触发器中添加DBMS_OUTPUT.PUT_LINE输出调试信息(仅适用于开发环境);
使用Oracle的AWR(自动工作负载仓库)或ASH(活动会话历史)监控触发器的执行计划和耗时;
记录触发器的执行日志到专用表(如trigger_logs),包含触发时间、事件类型、影响的行数等信息。

五、实战案例:银行转账的"隐形审计官"

  让我们通过一个完整的案例,感受触发器的实战价值。

5.1 需求背景

  某银行核心系统需要实现:当客户A向客户B转账时,自动记录转账流水(包括转出账户、转入账户、金额、时间、操作柜员),并确保转账后转出账户余额不低于0。

5.2 技术实现

表结构​:

CREATE TABLE accounts (account_id   NUMBER PRIMARY KEY,balance      NUMBER NOT NULL CHECK (balance >= 0),owner_name   VARCHAR2(100)
);CREATE TABLE transactions (txn_id       NUMBER PRIMARY KEY,from_account NUMBER REFERENCES accounts(account_id),to_account   NUMBER REFERENCES accounts(account_id),amount       NUMBER NOT NULL CHECK (amount > 0),txn_time     TIMESTAMP DEFAULT SYSTIMESTAMP,operator     VARCHAR2(30)
);

​触发器设计​:
我们需要对accounts表的UPDATE操作(转账本质是修改转出和转入账户的余额)进行拦截,但直接修改余额可能涉及两条UPDATE语句(先扣减转出账户,再增加转入账户)。因此,更好的方式是对包含转账逻辑的存储过程添加触发器,或者在应用层调用存储过程时触发。

  这里,我们假设转账操作通过存储过程transfer_funds完成:

CREATE OR REPLACE PROCEDURE transfer_funds(p_from_account IN NUMBER,p_to_account   IN NUMBER,p_amount       IN NUMBER,p_operator     IN VARCHAR2
) ISv_balance NUMBER;
BEGIN-- 检查转出账户余额是否足够SELECT balance INTO v_balanceFROM accountsWHERE account_id = p_from_accountFOR UPDATE; -- 行锁,防止并发修改IF v_balance < p_amount THENRAISE_APPLICATION_ERROR(-20002, '转出账户余额不足');END IF;-- 扣减转出账户余额UPDATE accountsSET balance = balance - p_amountWHERE account_id = p_from_account;-- 增加转入账户余额UPDATE accountsSET balance = balance + p_amountWHERE account_id = p_to_account;-- 插入交易流水(这里可以交给触发器自动完成)-- INSERT INTO transactions (...) VALUES (...);COMMIT;
END;
/

  为了自动记录交易流水,我们创建一个AFTER UPDATE复合触发器,监控accounts表的更新操作,并判断是否为转账(即同一事务中存在两条UPDATE语句,一条扣款、一条入账)。

CREATE OR REPLACE TRIGGER trg_transfer_audit
FOR UPDATE OF balance ON accounts
COMPOUND TRIGGERTYPE t_txn_rec IS RECORD (from_account NUMBER,to_account   NUMBER,amount       NUMBER,operator     VARCHAR2(30));v_txn t_txn_rec;v_count NUMBER := 0; -- 记录本次事务中更新的账户数BEFORE STATEMENT ISBEGIN-- 初始化变量v_count := 0;END BEFORE STATEMENT;BEFORE EACH ROW ISBEGIN-- 每次更新前记录账户ID和旧余额IF v_count = 0 THENv_txn.from_account := :OLD.account_id;v_txn.amount := :OLD.balance - :NEW.balance; -- 扣款金额=旧余额-新余额(应为正数)ELSIF v_count = 1 THENv_txn.to_account := :OLD.account_id;-- 验证入账金额是否等于扣款金额(防止逻辑错误)IF :NEW.balance - :OLD.balance <> v_txn.amount THENRAISE_APPLICATION_ERROR(-20003, '转账金额不一致:扣款=' || v_txn.amount || ',入账=' || (:NEW.balance - :OLD.balance));END IF;-- 插入交易流水INSERT INTO transactions (txn_id, from_account, to_account, amount, operator)VALUES (txn_seq.NEXTVAL, v_txn.from_account, v_txn.to_account, v_txn.amount, p_operator); -- 注意:p_operator需从外部传入,此处简化为示例END IF;v_count := v_count + 1;END BEFORE EACH ROW;AFTER STATEMENT ISBEGIN-- 确保本次事务只处理两笔更新(一笔扣款、一笔入账)IF v_count != 2 THENRAISE_APPLICATION_ERROR(-20004, '非法转账操作:本次事务更新了' || v_count || '个账户');END IF;END AFTER STATEMENT;
END trg_transfer_audit;
/

5.3 效果验证

  当执行transfer_funds(1001, 1002, 5000, ‘柜员001’)时:

  存储过程检查转出账户(1001)余额是否≥5000;
扣减1001账户余额5000元,触发触发器的BEFORE EACH ROW,记录from_account=1001,计算amount=5000;
增加1002账户余额5000元,触发触发器的BEFORE EACH ROW(此时v_count=1),验证入账金额是否等于5000元,并插入交易流水;
事务提交前,AFTER STATEMENT验证本次事务仅更新了2个账户,确保没有遗漏。
如果转账过程中出现错误(如余额不足、入账金额不一致),触发器会直接抛出错误,阻止操作,保证数据一致性。

六、结语:让触发器成为你的"得力助手"而非"麻烦制造者"

  亲爱的朋友们,Oracle触发器不是洪水猛兽,而是一把"双刃剑"。它能让业务逻辑更严谨、数据更安全,但也可能因滥用导致性能问题或逻辑漏洞。

记住以下几点​:
触发器是数据库的"最后一道防线",用于强制执行无法通过应用层约束实现的规则;
优先使用简单触发器(语句级、BEFORE),避免不必要的行级触发;
始终测试触发器的性能影响,尤其是在批量操作场景下;
注释清晰、日志完善,让未来的你(或其他开发者)能快速理解触发器的意图。

  最后,我想用一句话总结:​触发器的价值,在于让数据操作"符合预期"——无论这种预期是来自业务规则、审计需求,还是系统安全。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/89839.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/89839.shtml
英文地址,请注明出处:http://en.pswp.cn/pingmian/89839.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python桌面版数独游戏(三版)-增加难易度模式

数独游戏难度模式解析 在数独游戏中&#xff0c;难度通常由已知数字&#xff08;提示数&#xff09;的数量决定。难度越高&#xff0c;已知数字越少&#xff0c;玩家需要推理的步骤越多。以下是不同模式下的算法区别和核心代码解析。 文章目录数独游戏难度模式解析1. **难度模…

k8s查看某个pod的svc

在 Kubernetes 中&#xff0c;要查看与特定 Pod 相关的 Service&#xff0c;可以通过以下方法&#xff1a;#### 方法一&#xff1a;通过标签匹配1. **获取 Pod 的标签**bashkubectl get pod <pod-name> --show-labels输出示例&#xff1a;NAME READY STATUS RESTARTS AGE…

通俗易懂卷积神经网络(CNN)指南

本文用直观类比和可视化方法&#xff0c;帮你彻底理解CNN的工作原理&#xff0c;无需深厚数学基础也能掌握计算机视觉的核心技术。卷积神经网络&#xff08;CNN&#xff09;是深度学习中革命性的架构&#xff0c;它彻底改变了计算机"看世界"的方式。本文将用最直观的…

AV1平滑缓冲区

对于解码的每一帧视频数据&#xff0c;解码器都必须从缓冲池中找到一个尚未被使用的帧缓冲区插槽来存储解码后的数据。分配的帧缓冲区插槽用于临时保存解码过程中生成的帧数据&#xff0c;直到它们被用于显示或进一步的处理。函数get_free_buffer的作用是在缓冲池中搜索尚未被分…

Python并发编程:突破GIL枷锁,高效利用多核CPU

解密concurrent.futures的双引擎&#xff1a;线程池与进程池的明智选择在Python并发编程领域&#xff0c;concurrent.futures模块堪称利器&#xff0c;但如何正确使用其两大核心组件——ThreadPoolExecutor和ProcessPoolExecutor&#xff0c;却让许多开发者困惑。本文将深入剖析…

在Windows Server 2012 R2中安装与配置IIS服务并部署mssql靶机教程

在Windows Server 2012 R2中安装与配置IIS服务全指南 IIS&#xff08;Internet Information Services&#xff09;作为Windows系统自带的Web服务组件&#xff0c;在企业级Web部署、内网服务搭建等场景中应用广泛。本文将详细介绍在Windows Server 2012 R2中安装IIS服务的完整流…

C#/.NET/.NET Core技术前沿周刊 | 第 47 期(2025年7.14-7.20)

前言 C#/.NET/.NET Core技术前沿周刊&#xff0c;你的每周技术指南针&#xff01;记录、追踪C#/.NET/.NET Core领域、生态的每周最新、最实用、最有价值的技术文章、社区动态、优质项目和学习资源等。让你时刻站在技术前沿&#xff0c;助力技术成长与视野拓宽。 欢迎投稿、推荐…

一.AD域与DFS集群-AD域安装

目录 1.网络规划 2.主域控安装 3.辅助域控安装 1.网络规划 服务器名称IP地址DNS名称主域控192.168.188.2pdc.test.cn辅助域控192.168.188.3bdc.test.cnDFS1192.168.188.4dfs1.test.cnDFS2192.168.188.5dfs2.test.cn 服务器系统版本为windows server 2022 2.主域控安装 第一…

BUUCTF在线评测-练习场-WebCTF习题[BSidesCF 2020]Had a bad day1-flag获取、解析

解题思路打开靶场&#xff0c;作者对我们进行了亲切的关怀老规矩查看源码、抓包并没有发现什么猫腻点下面两个按钮会出现猫猫狗狗的图片&#xff0c;此时我们发现url多了个 参数category那么比较明显就是提示我们是任意文件包含、任意文件读取漏洞了找不到任何信息&#xff0c;…

stm32mp157f-dk2安装镜像并且部署qt全流程

在网上看的关于stm32mp157的开发教程太少了&#xff0c;于是乎写一篇踩坑笔记&#xff0c;仅供学习参考 大概流程&#xff1a;在虚拟机通过stm32cubeprogrammer烧录镜像&#xff0c;然后烧录成功之后&#xff0c;给stm32mp157连接网线&#xff0c;使得开发板有ip地址&#xff…

遗像照片尺寸要求及手机制作打印方法

遗像作为寄托哀思的重要载体&#xff0c;其规格和质量都有严格要求。本文将详细介绍遗像照片的标准尺寸规范&#xff0c;并提供使用手机快速制作合规遗像的完整方案。一、遗像照片的标准尺寸要求遗像照片的尺寸主要分为传统黑白遗像和现代彩色遗像两种规格。传统黑白遗像一般采…

适配器模式 (Adapter Pattern)

适配器模式 (Adapter Pattern) 适配器模式是一种结构型设计模式&#xff0c;用于解决两个不兼容接口之间的兼容性问题&#xff0c;充当两个不同接口之间的桥梁。 &#x1f31f; 核心思想转换接口&#xff1a;将一个类的接口转换成客户端期望的另一个接口&#xff0c;使原本不兼…

03-虚幻引擎蓝图类的各父类作用讲解

虚幻引擎&#xff08;Unreal Engine&#xff09;的蓝图系统提供了多种父类&#xff0c;每种父类都有其特定的用途和生命周期。理解这些父类的作用&#xff0c;是高效使用蓝图开发游戏的基础。以下是虚幻引擎中常见蓝图父类的详细讲解&#xff1a;1. Actor 作用&#xff1a;所有…

141 个 LangChain4j Maven 组件分类解析、多场景实战攻略

141 个 LangChain4j Maven 组件分类解析、多场景实战攻略 文章目录 141 个 LangChain4j Maven 组件分类解析、多场景实战攻略 1. 引言 2. LangChain4j 组件分类 2.1. 核心模块 (Core Modules) 2.2. LLM 集成 (LLM Integrations) 2.3. 向量存储集成 (Embedding Store Integratio…

Python可迭代归约函数深度解析:从all到sorted的进阶指南

在Python中&#xff0c;归约函数&#xff08;Reduction Functions&#xff09;是处理可迭代对象的利器。它们通过遍历元素并逐步收敛为单个结果&#xff0c;广泛应用于数据分析、逻辑判断和数值计算等场景。本文将系统梳理这些函数的核心特性、使用技巧及底层逻辑&#xff0c;助…

大带宽服务器都有哪些应用场景?

大带宽服务器凭借着高速的数据传输能力和强大的网络承载能力&#xff0c;通常被企业应用在需要高流量和高并发处理能力的业务场景当中&#xff0c;下面&#xff0c;就让我们共同了解一下大带宽服务器的应用场景吧&#xff01;首先&#xff0c;随着科学技术的快速发展&#xff0…

爬虫实战指南:从定位数据到解析请求的全流程解析

爬虫的本质是什么&#xff1f; 爬虫的本质就是用代码模拟人类在浏览器里的操作&#xff0c;像点击网页、填写表单、提交数据等行为&#xff0c;自动化地进行网页数据的获取和处理。比如&#xff1a; 发送 GET 请求 来请求网页内容&#xff0c;相当于你在浏览器地址栏输入网址…

Sentinel dashboard 添加context-path后无法信息无法上传问题

Sentinel dashboard 添加context-path后无法加载问题 添加server.servlet.context-path/sentinel后可以正常访问&#xff0c;但是客户端启动后信息上报失败。 transport: dashboard: localhost:8858/sentinel 经查阅文档需要加入api-path&#xff0c;但是我配置提示无api-path所…

iOS —— 3Gshare项目总结与思考

登陆注册及推出主页面这部分有两种写法&#xff1a;一种是在SceneDelegate中推出LoginVC&#xff0c;后在判断登陆成功后退去主要程序。另一种则是先加载主程序&#xff0c;后推出登陆页面。通过同组同学实践证明&#xff0c;后者在推出登陆页面时会闪一下&#xff0c;因此还是…

硅基计划3.0 学习总结 贰 顺序表与链表 初版

文章目录一、顺序表——ArrayList1. 实现自己MyArrayList1. 实现add基础方法2. 实现指定位置加元素add方法3. 完善数组打印方法display4. 完善根据下标找元素get5. 完善判断数字是否在数组中contains6. 根据数字找下标indexOf7. 更新指定下标元素set8. 获取数组有效长度size9. …