七、数据库的完整性
七、数据库的完整性
主要内容
7.1 数据库的完整性概述
7.2 实体完整性
7.3 参照完整性
7.4 用户定义的完整性
7.5 触发器
7.6 SQL Server中数据库完整性的实现
7.7 小结
7.1 数据库的完整性概述
-
数据库完整性的含义
-
正确性
指数据的合法性 -
有效性
指数据是否属于所定义的有效范围 -
相容性
表示同一事实的两个数据应相同
-
-
保持完整性的目的
-
防止数据库中存在不符合语义的数据,也就是防止数据库中存在不正确的数据 (防止不合语义的、不正确的数据)
-
保证数据库的数据质量
-
为维护数据的完整性,需要对数据库中的数据施加一些语义约束条件(完整性约束条件或完整性规则),对数据库进行完整性控制。
-
数据库的完整性控制是 DBMS 的基本功能之一,由 完整性子系统 负责,其功能包括:
- 提供定义完整性约束条件的机制
- 提供检查完整性的方法
- 提供违约处理
- 拒绝执行
- 按照完整性控制策略处理
-
完整性约束条件
- 一种语义概念;
- 是对数据库中数据本身的 某种语义限制、数据间的逻辑约束、数据变化时所遵循的规则 等。
- 关系数据库对数据的各种限制是以完整性约束条件的形式 在关系数据库模式中指定的。
- SQL 标准 使用了一系列概念来描述完整性,包括关系模型的实体完整性、参照完整性和用户定义完整性。
-
完整性检查
- DBMS 检查数据库中的数据是否满足完整性约束条件
-
关系数据库的完整性约束条件分类:
- 实体完整性约束
- 参照完整性约束
- 其他(用户定义的)完整性约束
-
完整性约束条件的作用对象:
- 关系(关系约束)
- 元组(元组约束)
- 属性列(列级约束)
-
列级约束
主要是对属性的数据类型、数据格式和取值范围、精度等的约束。具体包括:
-
对 数据类型 的约束,包括数据类型、长度、精度等的约束。例如:学生姓名的数据类型是字符串,长度是 8。
-
对 数据格式 的约束例如规定日期的格式为 YYYY/MM/DD
-
对取 值域 的约束,例如:学生成绩的取值范围必须是 0~100
-
对 空值 的约束
-
-
元组约束
元组中各个属性之间的约束关系
例如:订货关系中发货日期不能小于订货日期,发货量不得超过订货量
-
关系约束
一个关系的各个元组之间,或者多个关系之间存在的各种联系或约束。常见的关系约束有:
- 实体完整性约束
- 参照完整性约束
- 函数依赖约束
- 统计约束等
-
在关系数据库系统中,完整性控制策略包括:默认值,约束,规则,触发器和存储过程
-
默认值(Default)
- 如果在插入行中没有指定列的值,那么默认值指定列中所使用的值。
例如:自动增长值、内置函数、数学表达式等。
- 如果在插入行中没有指定列的值,那么默认值指定列中所使用的值。
-
约束(Check)(检查、校验)
- 是自动强制数据完整性的方法。
- 定义关系列中允许值的规则,是通用的强制完整性的标准机制。
- 使用 Check 可用于触发器、规则和默认值。
-
规则(Rule)
-
规则是大多数数据库系统中一个向后兼容的功能,用于执行一些与 Check 约束相同的功能。
-
规则以单独的对象创建,然后绑定到列上。
-
早期 SQL Server 中特有的功能,后来基本被 Check 所取代。
可以把一些检查条件单独定义成一个“规则对象”,再绑定到字段上。
举例:
CREATE RULE PosInt AS @value > 0; EXEC sp_bindrule PosInt, 'Student.Age';
-
-
触发器(Trigger)
- 一种数据库事件响应机制。
- 当表的内容发生变化(如插入/删除/修改)时自动执行的存储程序。
-
触发器是数据库系统中强制业务规则和数据完整性的主要机制。
-
用编程的方法实现复杂的业务规则和约束。
-
常用于强制“复杂业务逻辑”或“级联更新/验证”。
-
例如:
CREATE TRIGGER CheckSalary ON Employee FOR INSERT, UPDATE AS BEGINIF EXISTS (SELECT * FROM inserted WHERE salary < 0)ROLLBACK TRANSACTION; END;
-
存储过程(Procedure)
- 与触发器类似。
- 是一组预先写好、存储在数据库中的SQL语句集合。
- 可以像函数一样调用。
- 虽然不直接用于完整性约束,但能实现更复杂的控制逻辑。
-
断言(Assertion)
- 是 SQL 标准中定义的一种“表级约束”机制。作用于整个数据库,而不仅限于某个表字段。
- 例如:
create assertion <name> check(predicate)
- 注意:大多数商用数据库(如 MySQL、SQL Server)并不支持断言。
-
-
数据完整性的另一种分类
-
声明式数据完整性(非编程的方式,解释的方式)
- 作为对象定义的一部分来定义数据必须达到的标准
- DBMS 自动强制完整性
- 通过使用 约束、默认值 和 规则 来实现
说明:声明式数据完整性也称为静态约束、结构性控制
-
用语法声明约束:你只需用数据库语言(如SQL)声明某列/某表的约束,DBMS 会自动检查。
-
定义在数据库对象中(如表结构内),是数据定义的一部分。
-
自动由 DBMS 强制,程序员无需再手动检查。
-
实现方式:
- 使用
CHECK
约束 - 使用
DEFAULT
默认值 - 使用
RULE
规则(已被废弃,但仍有文献提及)
- 使用
举例:
CREATE TABLE Student (Age INT CHECK (Age >= 0 AND Age <= 150),Gender CHAR(1) DEFAULT 'M' );
-
过程式数据完整性(编程方式)
- 在脚本中定义数据必须达到的标准
- 在脚本中强制完整性
- 通过使用 触发器 和 存储过程 来实现
- 可在客户端或服务器用其他编程语言和工具来实现
进一步解释,过程式数据完整性(编程方式)也称为动态约束、程序性控制,特点是:
- 在脚本中通过代码逻辑来控制数据是否符合完整性要求。
- 通常适用于复杂逻辑、跨表或跨库的约束。
- 程序员手动实现完整性控制,可以写在:
- 存储过程(Procedure)
- 触发器(Trigger)
- 外部应用代码(Python、Java 等)
举例(触发器实现)
CREATE TRIGGER trg_CheckSalary BEFORE INSERT ON Employee FOR EACH ROW BEGINIF NEW.Salary < 0 THENSIGNAL SQLSTATE '45000'SET MESSAGE_TEXT = 'Salary cannot be negative';END IF; END;
-
7.2 实体完整性
- 实体完整性规则规定:
- 主键的值唯一
- 主键的值不能取空值
- 实现方法:通过对主键值的约束实现实体完整性
- 关系模型的实体完整性定义:
- 用
PRIMARY KEY
定义:- 定义为列级约束条件
- 定义为表级约束条件
- 单属性构成的主键有两种定义方式
- 对多个属性构成的主键只能定义为表级约束条件
- 用
【例】实体完整性约束定义
CREATE TABLE Student
(Sno CHAR(9) PRIMARY KEY,Sname CHAR(20) NOT NULL,Ssex CHAR(2),Sage SMALLINT,Sdept CHAR(20)
);
CREATE TABLE Student
(Sno CHAR(9),Sname CHAR(20) NOT NULL,Ssex CHAR(2),Sage SMALLINT,Sdept CHAR(20),PRIMARY KEY (Sno)
);
CREATE TABLE SC
(Sno CHAR(9) NOT NULL,Cno CHAR(4) NOT NULL,Grade SMALLINT,PRIMARY KEY (Sno, Cno) -- 只能在表级定义主键
);
-
PRIMARY KEY 约束可以作为表定义的一部分在创建表时定义,也可以在表创建之后再添加。
-
为了实施实体完整性,系统一般会在主键属性上自动创建唯一的索引来强制唯一性约束。
-
实体完整性检查和违约处理
定义表的主键后,每当对该表插入一条记录或者对主键进行更新操作时,DBMS 自动进行是实体完整性的检查
- 检查主键是否唯一,
- 如果不唯一,则拒绝进行插入或修改
- 检查主键的各个属性(字段)值是否为空
- 如果有空的字段值,则拒绝操作,从而保证实体完整性。
- 检查方法:全表扫描法,索引扫描法。
-
使用全表扫描法检查记录中主键值是否唯一
-
使用索引判断主键是否存在
7.3 参照完整性
- 参照完整性
- 刻画不同关系之间的联系
- 约束同一关系内部不同属性之间的联系
- 参照完整性约束规则
- 不允许引用不存在的元组
- 在关系模型中,外键字段的值要么为空值,要么是被引用关系中元组的对应值
- 关系模型的参照完整性定义
- 用
FOREIGN KEY
短语定义哪些列为外键 - 用
REFERENCES
短语指明外键参照哪些表的主键
- 用
【例】定义 SC 中的参照完整性
CREATE TABLE SC (Sno CHAR(9) NOT NULL,Cno CHAR(4) NOT NULL,Grade SMALLINT,PRIMARY KEY (Sno, Cno),FOREIGN KEY (Sno) REFERENCES Student(Sno),FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
参照完整性检查和违约处理
-
外键将两个表之间的元组联系起来,建立了参照与被参照的联系,需要维护参照完整性
-
破话参照完整性的情况及其处理
-
维护参照完整性的策略
- 参照关系中外键空值的问题
- 需要定义外键是否允许为空值
- 如果,外键是其主键的组成部分,外键值不允许为空
- 如果,外键不是其主键的组成部分,可以根据具体的语义确定外键值是否允许为空
- 允许空值的存在使得 SQL 中参照完整性约束的语义变得更加复杂
- 在参照关系中插入元组的情况
-
受限插入(RESTRICTED):
- 向
titles
中插入新元组,但该元组的pub_id
属性值在表publishers
中不存在,则系统拒绝插入
- 向
-
递归插入【级联 (CASCADE) 插入】:
- 首先向被参照关系插入相应的元组,其主键值等于参照关系插入元组的外键值,然后再向参照关系插入该元组
-
- 在参照关系中修改元组的方式
- 先删除、再插入
- 在 被参照关系 中删除元组的情况
-
级联删除(CASCADE)
- 将参照关系中所有外键值与被参照关系中要删除元组之间值相同的元组一起删除。
- 如果参照关系同时又是另一个关系的被参照关系,这种删除操作会继续级联下去。
-
受限制删除(RESTRICTED)
- 仅当参照关系中没有任何元组的外键值与被参照关系中要删除元组的主键值相同时,系统才执行删除操作,否则拒绝删除操作。
-
置空值删除
- 删除被参照关系的元组,并将参照关系中相应元组的外键值置为空值。
-
- 在 被参照关系 中修改主键值的方式
- 先删除、再插入
- 参照关系中外键空值的问题
-
违反参照完整性,系统一般选用默认策略,即拒绝执行。如果想让系统采用其他策略则必须在创建表时加以说明。
显式说明参照完整性的违约处理示例
CREATE TABLE SC (Sno CHAR(9) NOT NULL,Cno CHAR(4) NOT NULL,Grade SMALLINT,PRIMARY KEY (Sno, Cno),FOREIGN KEY (Sno) REFERENCES Student(Sno)ON DELETE CASCADE -- 级联删除 SC 表中相应的元组ON UPDATE CASCADE, -- 级联更新 SC 表中相应的元组FOREIGN KEY (Cno) REFERENCES Course(Cno)ON DELETE NO ACTION -- 删除 Course 表中元组造成与 SC 不一致时拒绝删除ON UPDATE CASCADE -- 更新 Course 表中的 Cno 时,级联更新 SC 表中相应的元组
);
7.4 用户定义的完整性
- 用户定义的完整性是限定某一具体应用的数据必须满足的语义要求:
- 列值不能为空
- 列值唯一
- 一定的数据格式
- …
- RDBMS 提供定义和检验用户定义的完整性的机制,不必由应用程序承担这部分功能。
- 用户定义的完整性的定义
-
属性上的约束条件的定义:
- 唯一(UNIQUE)
- 非空(NOT NULL)
- CHECK 约束
- 默认值 DEFAULT 等
-
元组上的约束条件的定义:
- 用 CHECK 短语定义元组上的约束条件
- 元组级的限制可以设置不同属性之间的相互约束条件
-
【例】创建选课表并添加属性约束条件
CREATE TABLE SC(Sno CHAR(9) NOT NULL,Cno CHAR(4) NOT NULL,GRADE SMALLINT CHECK(Grade >= 0 AND Grade <= 100),PRIMARY KEY(Sno,Cno),FOREIGN KEY (Sno) REFERENCES Student(Sno),FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
SMALLINT
:- 类型:整数类型
- 范围
- 有符号(默认):
-32768
到32767
- 无符号(
UNSIGNED
):0
到65,535
- 有符号(默认):
- 用途:适合用于存储不太大的整数值,比如年龄、成绩、评分等。
【例】创建 Students 表,其中 age
值必须在 10 到 25 之间,score
值必须在 0 到 100 之间
CREATE TABLE Student(Sno CHAR(9) NOT NULL,Name VARCHAR(50),age INT ,score DECIMAL(5,2),CHECK(age BETWEEN 10 AND 25 AND score BETWEEN 0 AND 100)
);
-
VARCHAR(n)
:- 类型:可变长度字符串。
n
表示最大长度,单位是字符(不是字节)。- 用途:适合用于存储长度不固定的文本,比如姓名、地址、邮箱等。
- 示例:
VARCHAR(50)
表示最多可以存储 50 个字符。
-
DECIMAL(m, d)
:-
类型:定点数(用于存储精确小数,不会有浮点数误差)。
-
m
:总位数(包括小数点前后) -
d
:小数点后的位数 -
示例:
DECIMAL(5, 2)
- 最大值为
999.99
,因为最多 5 位数,其中 2 位在小数点后。
- 用途:适合存储对精度要求高的数值,如金额、评分等。
- 最大值为
-
【例】创建 table1
,指定 c1
字段不能包含重复值,c2
字段只能取特定值
CREATE TABLE table1(c1 CHAR(2) UNIQUE,c2 CHAR(4) CHECK (c2 IN ('0000','0001','0002','0003')),c3 INT DEFAULT 1
);
-
用户定义完整性的检查与违约处理
-
插入元组或修改属性的值时,RDBMS 检查元组上的约束条件是否被满足,如果不满足则拒绝执行。
-
例:
(1) INSERT INTO table1 (c1, c2)VALUES ('10', '0000');(2) INSERT INTO table1VALUES ('10', '0001', 2);
-
报错:
服务器:消息 2627,级别 14,状态 2,行 1 违反了 UNIQUE KEY 约束 'UQ_table1_4222D4EF'。不能在 table1 中插入重复键。 语句已终止。
-
-
定义
CONSTRAINT
约束的完整格式CONSTRAINT <完整性约束条件名>[ PRIMARY KEY 短语 |FOREIGN KEY 短语 |CHECK 短语 ]
示例:
CREATE TABLE Student (Sno NUMERIC(6) CONSTRAINT C1CHECK (Sno BETWEEN 90000 AND 99999),Sname CHAR(20) CONSTRAINT C2 NOT NULL,Sage NUMERIC(3)CONSTRAINT C3 CHECK (Sage < 30),Ssex CHAR(2) CONSTRAINT C4CHECK (Ssex IN ('男', '女')),CONSTRAINT StudentKey PRIMARY KEY(Sno) );
-
修改表中的完整性限制
-
使用
ALTER TABLE
语句修改表中的完整性限制。 -
注意:需要先删除原来的约束条件,再增加新的约束条件。
-
示例: 修改表
Student
中的约束条件,将年龄由小于 -+ -
30 改为小于 40
ALTER TABLE StudentDROP CONSTRAINT C3;ALTER TABLE StudentADD CONSTRAINT C3CHECK (Sage < 40);
-
7.5触发器
-
数据库系统一般提供两种主要机制来实现业务规则和数据完整性:
-
约束(constraint)(声明式,静态的)
- 完整性约束机制在检测出违反约束条件的操作后,只能作简单的动作,例如:拒绝操作。
-
触发器(trigger)(过程式,动态的)
- 触发器是用户定义在关系数据表上的一种由事件驱动的特殊过程,用编程的方法实现复杂的业务规则。
- 触发器比约束更加灵活,可以实现一般的数据完整性约束实现不了的复杂的完整性约束,具有更精细和更强大的数据控制能力。
- 触发器常常用于强制业务规则和数据完整性。
-
-
触发器是一种特殊类型的存储过程,在对表或视图发出 UPDATE、INSERT 或 DELETE 语句时自动执行。
-
可用触发器完成很多数据库完整性保护的功能:
- 实现复杂的业务规则
- 实现比声明式约束更复杂的数据完整性
- 比较数据修改前后的状态
- 维护非规范化数据
定义触发器
-
SQL 使用 CREATE TRIGGER 命令创建触发器,其一般格式为:
CREATE TRIGGER <触发器名>{BEFORE|AFTER} <触发事件> ON <表名>REFERENCESNEW|OLD ROW|TABLE AS <变量>FOR EACH{ROW|STATEMENT}[WHEN <触发条件>]<触发动作体>
发器也叫事件-条件-动作(event-condition-action)规则
各组成部分解释:
CREATE TRIGGER <触发器名>
:定义一个触发器并命名。{ BEFORE | AFTER }
:触发时间,表示是在事件执行前还是后触发。<触发事件>
:如INSERT
、UPDATE
、DELETE
,即触发条件。ON <表名>
:指定要监视的表。REFERENCING ... AS ...
:为旧值和新值指定别名,通常在行级触发器中使用。FOR EACH ROW
:表示这是行级触发器,每一行变更都会触发;STATEMENT
表示语句级触发器。[WHEN <条件>]
:可选,指定进一步的触发条件。<触发动作体>
:触发后自动执行的 SQL 语句块。
示例:
CREATE TRIGGER SC_TAFTER UPDATE OF Grade ON SCREFERENCESOLD row AS OldTuple,NEW row AS NewTupleFOR EACH ROWWHEN (NewTuple.Grade >= 1.1* OldTuple.Grade)INSERT INTO SC_U(Sno,Cno,OldGrade,NewGrade)VALUES (OldTuple.Sno,OldTuple.Cno,OldeTuple.Grade,NewTuple.Grade);
含义解析:
- 触发器名:
SC_T
- 触发时机:当对
SC
表的Grade
字段进行UPDATE
操作之后(AFTER UPDATE OF Grade
) - 作用范围:行级触发器(
FOR EACH ROW
) - 条件:仅当新成绩大于原成绩的 1.1 倍时(即涨幅超过 10%),才触发(
WHEN
子句) - 操作内容:将旧值和新值插入到
SC_U
表中用于日志记录或审计
-
MySQL版本
-
MySQL 中的
CREATE TRIGGER
基本语法:CREATE TRIGGER trigger_name{BEFORE | AFTER} {INSERT | UPDATE | DELETE}ON table_nameFOR EACH ROW BEGIN-- 触发器主体 SQL 语句块 END;
-
示例,MySQL 等价写法如下(MySQL 不支持
WHEN
)CREATE TRIGGER SC_T AFTER UPDATE ON SC FOR EACH ROW BEGINIF NEW.Grade >= 1.1 * OLD.Grade THENINSERT INTO SC_U(Sno, Cno, OldGrade, NewGrade)VALUES (OLD.Sno, OLD.Cno, OLD.Grade, NEW.Grade);END IF; END;
-
MySQL 中需要注意的差异点:
项目 PostgreSQL/Oracle 风格 MySQL WHEN
子句支持 不支持,需要用 IF
包裹REFERENCING
支持 NEW
/OLD
重命名不支持,固定用 NEW
和OLD
多事件触发 可以指定 UPDATE OF Grade
不支持 UPDATE OF
,只能AFTER UPDATE
多语句体 PL/SQL
或PL/pgSQL
块用 BEGIN...END
包裹,需配合DELIMITER
- MySQL 中创建触发器非常常见,但功能稍弱,需用
IF
判断代替WHEN
。 - 不支持在同一个表上为同一事件类型(如
AFTER UPDATE
)创建多个触发器(每个表每种事件最多一个触发器)。
- MySQL 中创建触发器非常常见,但功能稍弱,需用
-
-
定义触发器的语法说明
-
触发器的创建者
- 表拥有者或创建表的用户才可以在表上创建触发器
- 一个表上可以创建多个触发器
-
表名
- 触发器的目标表
- 当目标表被更新时,触发器才被激活
-
触发事件
- 定义激活触发器的 SQL 语句的类别
- INSERT、DELETE、UPDATE,或三者组合
-
触发时间
- 指明触发器何时执行
- BEFORE
- 在触发事件执行之前,判断触发条件是否满足。
- 若满足条件则先执行触发动作部分的操作,然后再执行触发事件的操作。
- AFTER
- 在触发事件完成之后,判断触发条件是否满足。
- 若满足条件则执行触发动作部分的操作。
- 如果触发事件因错误(如违反约束或语法错误)而失败,触发器将不会执行<触发动作>,<触发事件>依然执行。
-
触发器类型
按照触发动作的间隔尺度,触发器可分为:- 行级触发器(FOR EACH ROW):
对每一个修改的元组都会触发触发器的检查和执行。 - 语句级触发器(FOR EACH STATEMENT):
只在 SQL 语句执行时执行触发器的检查和触发器的执行。
例:Teacher 表上创建一个 AFTER UPDATE 触发器。如果表 Teacher 有1000行,执行如下语句:
UPDATE Teacher SET Deptno=5;
-
语句级触发器,触发动作将执行1次。
通常用于:
- 日志记录操作(不关心每一行的修改)
- 批量处理:如果需要进行一些与整个SQL语句相关的操作,而不需要对每一行进行细致的处理,语句级触发器会更高效。比如,执行批量更新时,可能只关心整个操作的时间或其他统计信息。
- 数据库级别操作:例如,生成某个表的总更新计数,或者在数据更新时触发清理缓存等操作。
-
行级触发器,触发动作只发生1000次;
通常用于:
- 逐行记录详细变化:当我们需要对表中每一行的数据变化进行处理或记录时,使用行级触发器。它可以针对每一行执行,记录每一行的修改前后状态。
- 审计和追踪:
- 当我们需要对数据进行审计时,逐行记录每一行的变化是非常重要的。行级触发器可以帮助你记录所有数据变动的历史记录,保证数据变动的可追溯性。
- 例子:对表中的每一行进行审核或记录其变更,确保每个更新都有明确的记录和责任追溯。
- 逐行计算或验证:
- 需要对每一行的数据进行单独的验证或计算时,行级触发器是最合适的选择。例如,更新某个表时,需要根据每行数据执行复杂的验证或计算逻辑。
- 例子:每当更新
Employee
表时,检查每个员工的薪资是否满足一定条件,如果不满足,则阻止更新。
- 行级触发器(FOR EACH ROW):
-
触发条件
- 由WHEN子句指定(MySQL使用
IF
)
只有当触发条件为真,触发操作才会执行。 - 省略WHEN触发条件,触发操作体在触发器激活后立即执行。
-
触发动作体
触发动作体是满足触发器条件后,执行的一系列数据库操作。
- 如果触发操作体执行失败,激活触发器的事件就会终止执行,触发器的目标表或触发器可能影响的其他对象不会发生任何变化。这就是rollback
-
引用(MySQL不支持)
REFERENCING NEW | OLD ROW AS <变量>
通常用于:
- 行级触发器
- 在触发器体中使用
NEW
和OLD
引用事件之后的新值和事件之前的旧值。
REFERENCING NEW | OLD TABLE AS <变量>
通常用于
- 语句级触发器
- 仅适用于AFTER触发器。
【例】将每次对表 Student
的插入操作所增加的学生个数记录到表 StudentInsertLog
中。
CREATE TRIGGER Student_Count
AFTER INSERT ON Student
FOR EACH STATEMENT
BEGINDECLARE before_count INT;DECLARE after_count INT;-- 获取插入前的学生数量SELECT COUNT(*) INTO before_count FROM OLD;-- 获取插入后的学生数量SELECT COUNT(*) INTO after_count FROM NEW;-- 计算新增的学生数量,并记录到StudentInsertLog表INSERT INTO StudentInsertLog (Numbers)VALUES (after_count - before_count);
END;
DECLARE
是用来声明局部变量的关键字。通常,DECLARE
在 存储过程、触发器、函数 或 块语句 中使用,用来声明在代码块内部使用的变量。
【例】定义一个 BEFORE 行级触发器,为教师表 Teacher 定义完整性规则 “教师的工资不得低于 4000 元,如果低于 4000,自动改为 4000 元”。
CREATE TRIGGER Insert_Or_Update_Sal
BEFORE INSERT OR UPDATE ON Teacher
FOR EACH ROW
BEGINIF (NEW.Job = '教师') AND (NEW.Sal < 4000)THENNEW.Sal := 4000;-- MySQL: SET NEW.Sal = 4000END IF;
END;
【例】创建触发器 credits_earned
,当 takes
表中的 grade
被更新后触发,引用新行作为 nrow
,引用旧行作为 orow
,并在每一行执行时更新学生的学分。
CREATE TRIGGER credit_earned
AFTER UPDATE OF Grade ON takes
REFERENCES NEW ROW AS nrow
REFERENCES OLD ROW AS orow
FOR EACH ROW
WHEN (nrow.grade != 'F' AND nrow.Grade IS NOT NULLAND (orow.grade = 'F' OR orow.grade IS NULL))
BEGINUPDATE StudentSET tot_cred = tot_cred +(SELECT creditsFROM courseWHERE course.course_id = nrow.course_id)WHERE student.id = nrow.id;
END;
使用触发器
-
触发器的执行,是由触发事件激活的,并由数据库服务器自动执行。
-
一个数据表上可能定义了多个触发器,同一个表上的多个触发器,激活时遵循如下的执行顺序:
- 执行该表上的 BEFORE 触发器;
- 激活触发器的 SQL 语句(触发事件);
- 执行该表上的 AFTER 触发器。
-
注意:如果激活触发器的 SQL 语句违反了约束条件,则不会执行 AFTER 触发器。
-
存在级联触发问题
删除触发器
DROP TRIGGER <触发器名> ON <表名>
- 触发器的删除不影响数据表和数据
- 删除表会自动删除其上的所有触发器
- 表的所有者拥有删除权限
7.6 SQL Server 完整性的实现
- 实际的数据库产品对完整性的支持不尽相同
- SQL Server 提供了对实体完整性、参照完整性和用户定义的完整性的支持
-
实体完整性的实现
- 索引
- UNIQUE 约束
- PRIMARY KEY 约束
- IDENTITY 属性
-
参照完整性的实现
- FOREIGN KEY 约束
- CHECK 约束
- 触发器
-
用户定义的完整性的实现
CREATE TABLE
中的列级和表级约束:- CHECK 约束
- DEFAULT 约束
- NOT NULL 约束
- 规则
- 存储过程
- 触发器
-
SQL Server 用于维护数据完整性的对象:
- 约束
- 规则
- 默认值
- 触发器
-
默认值和规则对象:
- 是可以绑定到一个或多个列或用户定义数据类型的对象
- 可以一次定义,多次使用
- 非标准内容
- 可以用 DEFAULT 约束和 CHECK 约束代替
-
创建默认值和规则的示例:
-
创建一个大于 0 的规则,并绑定到产品表的单价字段上:
CREATE RULE R_jg AS @jg > 0; sp_bindrule 'R_jg', '产品.单价';
其中的
@jg
是 变量名,在 SQL Server 中用于定义 规则(Rule) 时,必须使用一个以@
开头的占位符变量,它代表将来要绑定的列值。sp_bindrule
的语法与解释sp_bindrule [ @rulename = ] 'rule_name',[ @objname = ] 'object_or_uddt_name'
参数名 说明 @rulename
要绑定的规则名称(你定义的 RULE
名)@objname
要绑定的列名(格式为 '表名.列名'
)或用户自定义数据类型名 -
创建一个默认值为 100081 的对象,并将其绑定到 Student 表的 Zipcode 字段上:
CREATE DEFAULT DF_zip_code AS 100081; sp_binddefault 'DF_zip_code', 'Student.zipcode';
-
SQL Server 的数据完整性对象 —— 约束
-
Constraints:定义关于列中允许值的规则
-
是强制完整性的标准机制
-
使用约束(Constraints)优于使用触发器、规则和默认值
-
SQL Server 提供多种强制列中数据完整性的机制:
PRIMARY KEY
约束FOREIGN KEY
约束UNIQUE
约束CHECK
约束DEFAULT
约束NOT NULL
约束
-
各种完整性类型与约束类型对照表

CHECK 约束
- 可以将列的取值限定在指定范围内;
- 可以引用同一表中的其他列,约束同一个表中多个列之间的取值关系;
- 当执行
INSERT
语句或者UPDATE
语句时,CHECK
约束将验证数据值; - CHECK 约束中不能包含子查询。
示例:
ALTER TABLE Employees
ADD CONSTRAINT CK_birthdate
CHECK (BirthDate > '01-01-1900' AND BirthDate < getdate());
PRIMARY KEY 约束
- 表示唯一标识表中的行的列或列集;
- 可以在创建表时创建,也可以在随后添加、修改或删除;
- 必须非空且没有重复值;
- SQL Server 自动创建唯一的索引来强制
PRIMARY KEY
约束所要求的唯一性;
示例
ALTER TABLE Customers
ADD CONSTRAINT PK_Customers
PRIMARY KEY (CustomerID);
【例】使用 SQL 语句建立主键约束
CREATE TABLE publishers (pub_id char(4) NOT NULLPRIMARY KEYCHECK (pub_id IN ('1389', '0736', '0877', '1622', '1756') OR pub_id LIKE '99[0-9][0-9]'),pub_name varchar(40),city varchar(20),state char(2) NULL,country varchar(30)
);
FOREIGN KEY 约束
- 外键所引用的列必须是有
PRIMARY KEY
约束或UNIQUE
约束的列 - 列的取值范围只能是被引用列的取值或空值
FOREIGN KEY
约束可以引用其他表FOREIGN KEY
可以是单列键或者是多列键
示例
ALTER TABLE Orders
ADD CONSTRAINT FK_Orders_Customers
FOREIGN KEY (CustomerID)
REFERENCES Customers(CustomerID);
-
使用 FOREIGN KEY 约束时,应该考虑以下几个因素:
-
主键和外键的数据类型必须严格匹配;
-
外键约束不能自动创建索引,需要用户手动创建;
- 外键字段默认不会被自动索引;
- 如果需要提高性能(如加速连接、更新、删除操作),应当手动为外键字段创建索引。
会自动创建索引的约束:
PRIMARY KEY
、UNIQUE
不会自动创建索引的约束:
FOREIGN KEY
、CHECK
、NOT NULL
-
用户想要修改外键约束的数据,必须有对外键约束所参考表的
SELECT
权限或者REFERENCES
权限; -
一个表可以有多个
FOREIGN KEY
约束,最多可以有 31 个外键约束; -
在临时表中,不能使用外键约束。
-
DEFAULT 约束
- 用于提供列的默认值;
- 默认值可以是任何取值为常数的表达式,如:常量、
NULL
、系统函数、数学表达式等; - 默认值必须符合此列上的任何
CHECK
约束; - 在使用
INSERT
语句时,如果没有提供值,则DEFAULT
约束会指定该列中使用的值; - 只有在表中插入数据时,系统才检查
DEFAULT
约束。
示例
ALTER TABLE Customers
ADD CONSTRAINT DF_contactname
DEFAULT 'UNKNOWN'
FOR ContactName;
UNIQUE 约束
-
用于限制一个列中不能有非空的重复值
-
SQL Server 自动创建
UNIQUE
索引来强制UNIQUE
约束的唯一性要求 -
不能对现有的包含重复值的列添加
UNIQUE
约束 -
注意
UNIQUE
约束与PRIMARY KEY
约束的区别约束类型 唯一性要求 是否允许 NULL 每表允许个数 PRIMARY KEY 必须唯一 不允许 NULL 每表仅允许 1 个 UNIQUE 必须唯一 允许 NULL 每表可多个
示例:
ALTER TABLE Suppliers
ADD CONSTRAINT U_CompanyName
UNIQUE (CompanyName);
- 当使用唯一性约束时,需要考虑以下几个因素:
- 使用唯一性约束的字段允许为空值
- 一个表中可以允许有多个唯一性约束
- 可以把唯一性约束定义在多个字段上
- 唯一性约束用于强制在指定字段上创建一个唯一性索引
- 缺省情况下,创建的索引类型为非聚集索引
NOT NULL 约束
- 指定一列不允许空值
NULL
的存在表明值未知或未定义
示例:
CREATE TABLE SC (Sno CHAR(9) NOT NULL,Cno CHAR(4) NOT NULL,Grade SMALLINT CHECK (Grade >= 0 AND Grade <= 100),PRIMARY KEY (Sno, Cno),FOREIGN KEY (Sno) REFERENCES Student(Sno),FOREIGN KEY (Cno) REFERENCES Course(Cno)
);
使用约束的注意事项
CREATE TABLE
:在创建表时创建约束ALTER TABLE
:在一个已有的表上创建约束- 可添加单列或多列约束:
- 若约束应用于单列,称为列级约束;
- 若约束引用了多列,称为表级约束。
- 可直接在表上创建、修改和删除约束,而不必删除并重建表
- 当给一个表添加约束的时候,SQL Server 将检查现有数据是否违反约束
- 建议创建约束时指定名称,否则系统将为约束自动产生一个复杂的名称
SQL Server 的触发器
-
用途
-
定义用户定制的错误信息
- 通过使用触发器,可以在特定条件出现时调用预定义或动态定义的定制错误信息
- 约束、规则和默认只能通过标准系统错误信息来表达错误。若需要定制信息或更复杂的错误处理,需使用触发器
-
实现用户定义的完整性
-
在数据库中的相关表上实现级联更改
-
实现比声明式约束更复杂的业务规则
-
维护非标准数据,特别是处理较为复杂的逻辑
-
-
SQL Server 的触发器定义
CREATE TRIGGER <触发器名>
ON <表名> | <视图名>
{FOR | AFTER | INSTEAD OF} <触发事件>
AS
<触发动作体>
【例1】创建限制更新数据的触发器,限制将 SC
表中不及格学生的成绩改为及格。
【例2】创建删除触发器,当删除一本书时,先检查这本书是否已经被卖过,即是否和订单关联,如果已经有关联则该书的信息不能被删除,删除动作需回滚。
【例1】
CREATE TRIGGER tri_grade
ON SC FOR UPDATE
ASIF UPDATE (Grade)IF EXISTS (SELECT * FROM INSERTED JOIN DELETED ON INSERTED.Sno = DELETED.SnoWHERE INSERTED.Grade >= 60 AND DELETED.Grade < 60)BEGINRAISERROR ('不许将不及格的成绩改为及格!', 16, 1)ROLLBACKEND
-
INSERTED 表和 DELETED 表
SQL Server 触发器专用的临时虚拟表,由 SQL Server 自动管理
- NSERTED 表
- 保存
INSERT
操作中新插入的数据,或UPDATE
操作中更新后的数据,即:插入到触发表的新数据行的副本。
- 保存
- DELETED 表
- 存放
DELETE
操作中删除的数据,或UPDATE
操作中更新前的数据,即:从触发表中删除的旧数据行的副本。
- 存放
- 触发操作完成后,与触发器相关的临时表会自动删除。
- NSERTED 表
-
对带触发器的表的操作
- INSERT 操作时,新插入的数据被记录在
INSERTED
表中。 - DELETE 操作时,删除的数据被记录在
DELETED
表中。 - UPDATE 操作时,相当于先执行删除操作,再执行插入操作,即:
- 先在触发表中删除将被更新的行,并将这些行复制到
DELETED
表中; - 然后将更新后的新行复制到触发表和
INSERTED
表中。
- 先在触发表中删除将被更新的行,并将这些行复制到
- 触发器中对
INSERTED
表和DELETED
表的使用同普通表一样。 - 可以通过
INSERTED
表和DELETED
表所记录的数据,判断对数据的修改是否正确。
- INSERT 操作时,新插入的数据被记录在
-
ROLLBACK
ROLLBACK
的作用是:一旦触发某个错误或业务规则被违反,就放弃整个操作,数据不作任何修改。
【例2】
CREATE TRIGGER Products_Delete
ON Products FOR DELETE
ASIF (SELECT COUNT(*)FROM [Order Details]INNER JOIN deletedON [Order Details].ProductID = deleted.ProductID) > 0BEGINRAISERROR('该产品有定购历史,事务无法进行!', 10, 1)ROLLBACK TRANSACTIONEND
Oracle触发器示例
阻止用户把工资从高调为低(防止降薪),否则抛出自定义错误 -20003
。
create trigger teacher_sal -- 触发器名字
before update of salary on teacher -- 作用表
referencing new x, old y -- 定义更新前后的值
for each row
when (x.salary < y.salary) -- 对每一条记录都检查
begin-- 如果违反则执行,提示无效更新raise_application_error(-20003, 'invalid salary on update');
end;
PostgreSQL示例
-- 创建一个触发器函数
CREATE OR REPLACE FUNCTION check_salary()
RETURNS TRIGGER AS $$
BEGIN-- 检查工资是否为正数IF NEW.salary <= 0 THENRAISE EXCEPTION 'Salary must be a positive number';END IF;-- 返回 NEW 表示继续执行插入操作RETURN NEW;
END;
$$ LANGUAGE plpgsql;-- 创建 BEFORE INSERT 触发器
CREATE TRIGGER before_insert_employees
BEFORE INSERT ON employees
FOR EACH ROW
EXECUTE FUNCTION check_salary();
- 在 PostgreSQL 中,
$$
是一种 字符串定界符(delimiter),用于包裹函数体的代码块,避免和里面的单引号冲突。
## 触发器与 CHECK 约束
CHECK
约束只能根据逻辑表达式或同一表中的另一列来验证列值。- 如果应用程序要求根据另一个表中的列验证列值,则必须使用触发器(看实际系统的情况)。
- 约束只能通过标准的系统错误提示传递错误信息。
- 如果应用程序要求使用(或能从中获益)自定义信息和较为复杂的错误处理,则必须使用触发器。
- 触发器可以引用其它表中的列。
- 触发器可以支持约束的所有功能;但并不总是最好的方法,因为触发器的系统开销更大。
使用何种完整性强制方法?
-
应综合考虑功能和性能开销,来决定使用何种强制数据完整性的方法:
-
对于基本的完整性逻辑,例如有效值和维护表间的联系,最好使用声明式完整性约束;
-
如果要维护复杂的、大量的、非主键或外键关系的部分数据,使用触发器或存储过程;
-
约束比较简单,开销低,适合于完整性逻辑比较简单的场合;
-
触发器比较复杂,开销大,适合于完整性逻辑比较复杂的场合。
-
本章小结
- 数据库的完整性是为了保证数据库中存储的数据的正确性、有效性和相容性。
- RDBMS完整性实现的机制
- 完整性约束定义机制
- 完整性检查机制
- 违背完整性条件时RDBMS应采取的额动作
- 实体完整性
- 参照完整性
- 用户定义的完整性
- 实现数据库完整性的一个重要方法——触发器
PostgreSQL示例
-- 创建一个触发器函数
CREATE OR REPLACE FUNCTION check_salary()
RETURNS TRIGGER AS $$
BEGIN-- 检查工资是否为正数IF NEW.salary <= 0 THENRAISE EXCEPTION 'Salary must be a positive number';END IF;-- 返回 NEW 表示继续执行插入操作RETURN NEW;
END;
$$ LANGUAGE plpgsql;-- 创建 BEFORE INSERT 触发器
CREATE TRIGGER before_insert_employees
BEFORE INSERT ON employees
FOR EACH ROW
EXECUTE FUNCTION check_salary();
- 在 PostgreSQL 中,
$$
是一种 字符串定界符(delimiter),用于包裹函数体的代码块,避免和里面的单引号冲突。
## 触发器与 CHECK 约束
CHECK
约束只能根据逻辑表达式或同一表中的另一列来验证列值。- 如果应用程序要求根据另一个表中的列验证列值,则必须使用触发器(看实际系统的情况)。
- 约束只能通过标准的系统错误提示传递错误信息。
- 如果应用程序要求使用(或能从中获益)自定义信息和较为复杂的错误处理,则必须使用触发器。
- 触发器可以引用其它表中的列。
- 触发器可以支持约束的所有功能;但并不总是最好的方法,因为触发器的系统开销更大。
使用何种完整性强制方法?
-
应综合考虑功能和性能开销,来决定使用何种强制数据完整性的方法:
-
对于基本的完整性逻辑,例如有效值和维护表间的联系,最好使用声明式完整性约束;
-
如果要维护复杂的、大量的、非主键或外键关系的部分数据,使用触发器或存储过程;
-
约束比较简单,开销低,适合于完整性逻辑比较简单的场合;
-
触发器比较复杂,开销大,适合于完整性逻辑比较复杂的场合。
-
本章小结
- 数据库的完整性是为了保证数据库中存储的数据的正确性、有效性和相容性。
- RDBMS完整性实现的机制
- 完整性约束定义机制
- 完整性检查机制
- 违背完整性条件时RDBMS应采取的额动作
- 实体完整性
- 参照完整性
- 用户定义的完整性
- 实现数据库完整性的一个重要方法——触发器
相关文章:

七、数据库的完整性
七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

人工智能(大型语言模型 LLMs)对不同学科的影响以及由此产生的新学习方式
今天是关于AI如何在教学中增强学生的学习体验,我把重要信息标红了。人文学科的价值被低估了 ⬇️ 转型与必要性 人工智能正在深刻地改变教育,这并非炒作,而是已经发生的巨大变革。教育机构和教育者不能忽视它,试图简单地禁止学生使…...

安全突围:重塑内生安全体系:齐向东在2025年BCS大会的演讲
文章目录 前言第一部分:体系力量是突围之钥第一重困境是体系思想落地不畅。第二重困境是大小体系融合瓶颈。第三重困境是“小体系”运营梗阻。 第二部分:体系矛盾是突围之障一是数据孤岛的障碍。二是投入不足的障碍。三是新旧兼容难的障碍。 第三部分&am…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...

排序算法总结(C++)
目录 一、稳定性二、排序算法选择、冒泡、插入排序归并排序随机快速排序堆排序基数排序计数排序 三、总结 一、稳定性 排序算法的稳定性是指:同样大小的样本 **(同样大小的数据)**在排序之后不会改变原始的相对次序。 稳定性对基础类型对象…...

GruntJS-前端自动化任务运行器从入门到实战
Grunt 完全指南:从入门到实战 一、Grunt 是什么? Grunt是一个基于 Node.js 的前端自动化任务运行器,主要用于自动化执行项目开发中重复性高的任务,例如文件压缩、代码编译、语法检查、单元测试、文件合并等。通过配置简洁的任务…...
LangChain知识库管理后端接口:数据库操作详解—— 构建本地知识库系统的基础《二》
这段 Python 代码是一个完整的 知识库数据库操作模块,用于对本地知识库系统中的知识库进行增删改查(CRUD)操作。它基于 SQLAlchemy ORM 框架 和一个自定义的装饰器 with_session 实现数据库会话管理。 📘 一、整体功能概述 该模块…...

20个超级好用的 CSS 动画库
分享 20 个最佳 CSS 动画库。 它们中的大多数将生成纯 CSS 代码,而不需要任何外部库。 1.Animate.css 一个开箱即用型的跨浏览器动画库,可供你在项目中使用。 2.Magic Animations CSS3 一组简单的动画,可以包含在你的网页或应用项目中。 3.An…...

【电力电子】基于STM32F103C8T6单片机双极性SPWM逆变(硬件篇)
本项目是基于 STM32F103C8T6 微控制器的 SPWM(正弦脉宽调制)电源模块,能够生成可调频率和幅值的正弦波交流电源输出。该项目适用于逆变器、UPS电源、变频器等应用场景。 供电电源 输入电压采集 上图为本设计的电源电路,图中 D1 为二极管, 其目的是防止正负极电源反接, …...
动态 Web 开发技术入门篇
一、HTTP 协议核心 1.1 HTTP 基础 协议全称 :HyperText Transfer Protocol(超文本传输协议) 默认端口 :HTTP 使用 80 端口,HTTPS 使用 443 端口。 请求方法 : GET :用于获取资源,…...

Python Ovito统计金刚石结构数量
大家好,我是小马老师。 本文介绍python ovito方法统计金刚石结构的方法。 Ovito Identify diamond structure命令可以识别和统计金刚石结构,但是无法直接输出结构的变化情况。 本文使用python调用ovito包的方法,可以持续统计各步的金刚石结构,具体代码如下: from ovito…...

招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...

基于SpringBoot在线拍卖系统的设计和实现
摘 要 随着社会的发展,社会的各行各业都在利用信息化时代的优势。计算机的优势和普及使得各种信息系统的开发成为必需。 在线拍卖系统,主要的模块包括管理员;首页、个人中心、用户管理、商品类型管理、拍卖商品管理、历史竞拍管理、竞拍订单…...

【笔记】WSL 中 Rust 安装与测试完整记录
#工作记录 WSL 中 Rust 安装与测试完整记录 1. 运行环境 系统:Ubuntu 24.04 LTS (WSL2)架构:x86_64 (GNU/Linux)Rust 版本:rustc 1.87.0 (2025-05-09)Cargo 版本:cargo 1.87.0 (2025-05-06) 2. 安装 Rust 2.1 使用 Rust 官方安…...
JavaScript基础-API 和 Web API
在学习JavaScript的过程中,理解API(应用程序接口)和Web API的概念及其应用是非常重要的。这些工具极大地扩展了JavaScript的功能,使得开发者能够创建出功能丰富、交互性强的Web应用程序。本文将深入探讨JavaScript中的API与Web AP…...

Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...

深入浅出深度学习基础:从感知机到全连接神经网络的核心原理与应用
文章目录 前言一、感知机 (Perceptron)1.1 基础介绍1.1.1 感知机是什么?1.1.2 感知机的工作原理 1.2 感知机的简单应用:基本逻辑门1.2.1 逻辑与 (Logic AND)1.2.2 逻辑或 (Logic OR)1.2.3 逻辑与非 (Logic NAND) 1.3 感知机的实现1.3.1 简单实现 (基于阈…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...

使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...

MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...

无人机侦测与反制技术的进展与应用
国家电网无人机侦测与反制技术的进展与应用 引言 随着无人机(无人驾驶飞行器,UAV)技术的快速发展,其在商业、娱乐和军事领域的广泛应用带来了新的安全挑战。特别是对于关键基础设施如电力系统,无人机的“黑飞”&…...
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的“no matching...“系列算法协商失败问题
【SSH疑难排查】轻松解决新版OpenSSH连接旧服务器的"no matching..."系列算法协商失败问题 摘要: 近期,在使用较新版本的OpenSSH客户端连接老旧SSH服务器时,会遇到 "no matching key exchange method found", "n…...
【无标题】路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论
路径问题的革命性重构:基于二维拓扑收缩色动力学模型的零点隧穿理论 一、传统路径模型的根本缺陷 在经典正方形路径问题中(图1): mermaid graph LR A((A)) --- B((B)) B --- C((C)) C --- D((D)) D --- A A -.- C[无直接路径] B -…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

免费PDF转图片工具
免费PDF转图片工具 一款简单易用的PDF转图片工具,可以将PDF文件快速转换为高质量PNG图片。无需安装复杂的软件,也不需要在线上传文件,保护您的隐私。 工具截图 主要特点 🚀 快速转换:本地转换,无需等待上…...

Kafka入门-生产者
生产者 生产者发送流程: 延迟时间为0ms时,也就意味着每当有数据就会直接发送 异步发送API 异步发送和同步发送的不同在于:异步发送不需要等待结果,同步发送必须等待结果才能进行下一步发送。 普通异步发送 首先导入所需的k…...

深度学习水论文:mamba+图像增强
🧀当前视觉领域对高效长序列建模需求激增,对Mamba图像增强这方向的研究自然也逐渐火热。原因在于其高效长程建模,以及动态计算优势,在图像质量提升和细节恢复方面有难以替代的作用。 🧀因此短时间内,就有不…...

AirSim/Cosys-AirSim 游戏开发(四)外部固定位置监控相机
这个博客介绍了如何通过 settings.json 文件添加一个无人机外的 固定位置监控相机,因为在使用过程中发现 Airsim 对外部监控相机的描述模糊,而 Cosys-Airsim 在官方文档中没有提供外部监控相机设置,最后在源码示例中找到了,所以感…...
现有的 Redis 分布式锁库(如 Redisson)提供了哪些便利?
现有的 Redis 分布式锁库(如 Redisson)相比于开发者自己基于 Redis 命令(如 SETNX, EXPIRE, DEL)手动实现分布式锁,提供了巨大的便利性和健壮性。主要体现在以下几个方面: 原子性保证 (Atomicity)ÿ…...