【MySQL全面教学】MySQL视图与触发器Day12(2026年)


写在前面

大家好,欢迎来到MySQL全面教学系列的第12天。经过前面11天的学习,我们已经掌握了MySQL的基础知识、SQL语句、索引、事务、锁机制等核心内容。今天,我们将学习两个非常实用的数据库对象:视图(View)触发器(Trigger)

视图可以帮助我们简化复杂的查询,提供数据安全性;触发器则可以实现自动化的业务逻辑,比如审计日志、数据同步等。这两个特性在实际开发中使用频率很高,也是面试中的常考知识点。

让我们一起深入学习吧!


目录

一、什么是视图

1.1 视图的概念

**视图(View)**是一种虚拟存在的表,其内容由查询定义。视图并不在数据库中以存储的数据值集形式存在,行和列数据来自由定义视图的查询所引用的表,并且在引用视图时动态生成。

简单来说:视图就是一条SELECT语句的执行结果集

sql 复制代码
-- 视图的本质
视图 = 存储的SQL查询语句

1.2 为什么需要视图

场景 说明
简化复杂查询 将多表JOIN、子查询等复杂SQL封装成视图
数据安全性 限制用户只能访问视图中的特定列或行
逻辑独立性 底层表结构变化时,只需修改视图定义
数据抽象 为不同用户呈现不同的数据视角

1.3 视图 vs 表

对比项 视图(View) 表(Table)
数据存储 不存储实际数据,只存储定义 存储实际数据
占用空间 几乎不占用 占用磁盘空间
数据更新 不一定能更新 可以更新
创建语法 CREATE VIEW CREATE TABLE
查询性能 可能有性能开销 直接查询
数据安全 可以限制访问范围 需要额外权限控制

二、创建和管理视图

2.1 创建视图

基本语法:

sql 复制代码
CREATE [OR REPLACE] VIEW view_name [(column_list)]
AS select_statement
[WITH [CASCADED | LOCAL] CHECK OPTION];
示例1:简单视图
sql 复制代码
-- 创建一个只包含在职员工信息的视图
CREATE VIEW v_active_employees AS
SELECT 
    employee_id,
    first_name,
    last_name,
    department_id,
    salary
FROM employees
WHERE status = 'ACTIVE';

-- 使用视图
SELECT * FROM v_active_employees WHERE department_id = 10;
示例2:复杂视图(多表JOIN)
sql 复制代码
-- 创建员工部门信息视图
CREATE VIEW v_employee_details AS
SELECT 
    e.employee_id,
    CONCAT(e.first_name, ' ', e.last_name) AS full_name,
    e.email,
    e.phone_number,
    d.department_name,
    l.city,
    e.salary
FROM employees e
INNER JOIN departments d ON e.department_id = d.department_id
INNER JOIN locations l ON d.location_id = l.location_id;

-- 查询视图
SELECT * FROM v_employee_details WHERE department_name = 'Sales';
示例3:带聚合函数的视图
sql 复制代码
-- 创建部门薪资统计视图
CREATE VIEW v_department_salary_stats AS
SELECT 
    d.department_name,
    COUNT(e.employee_id) AS employee_count,
    AVG(e.salary) AS avg_salary,
    MIN(e.salary) AS min_salary,
    MAX(e.salary) AS max_salary,
    SUM(e.salary) AS total_salary
FROM departments d
LEFT JOIN employees e ON d.department_id = e.department_id
GROUP BY d.department_id, d.department_name;

2.2 修改视图

sql 复制代码
-- 方式1:使用ALTER VIEW
ALTER VIEW v_active_employees AS
SELECT 
    employee_id,
    first_name,
    last_name,
    department_id,
    salary,
    hire_date  -- 新增字段
FROM employees
WHERE status = 'ACTIVE';

-- 方式2:使用CREATE OR REPLACE VIEW
CREATE OR REPLACE VIEW v_active_employees AS
SELECT 
    employee_id,
    first_name,
    last_name,
    department_id,
    salary,
    hire_date
FROM employees
WHERE status = 'ACTIVE';

2.3 删除视图

sql 复制代码
-- 删除单个视图
DROP VIEW IF EXISTS v_active_employees;

-- 删除多个视图
DROP VIEW IF EXISTS v_employee_details, v_department_salary_stats;

2.4 查看视图定义

sql 复制代码
-- 查看视图创建语句
SHOW CREATE VIEW v_employee_details;

-- 查看视图结构
DESCRIBE v_employee_details;

-- 查看所有视图
SHOW FULL TABLES WHERE Table_type = 'VIEW';

-- 从information_schema查询
SELECT * FROM information_schema.views 
WHERE table_schema = 'your_database_name';

三、可更新视图

3.1 什么是可更新视图

可更新视图是指可以通过视图对底层基表进行INSERT、UPDATE、DELETE操作的视图。

但不是所有视图都可以更新,需要满足以下条件:

  1. 视图定义中不包含以下元素:

    • 聚合函数(SUM、COUNT、AVG等)
    • DISTINCT关键字
    • GROUP BY / HAVING
    • UNION / UNION ALL
    • 子查询
    • JOIN(MySQL中部分情况支持)
    • 某些系统函数
  2. 视图必须包含基表中所有NOT NULL且没有默认值的列

3.2 可更新视图示例

sql 复制代码
-- 创建可更新视图
CREATE VIEW v_employees_it AS
SELECT 
    employee_id,
    first_name,
    last_name,
    email,
    salary
FROM employees
WHERE department_id = 60;  -- IT部门

-- 通过视图插入数据
INSERT INTO v_employees_it (first_name, last_name, email, salary)
VALUES ('John', 'Doe', 'john.doe@example.com', 8000);

-- 通过视图更新数据
UPDATE v_employees_it 
SET salary = 9000 
WHERE employee_id = 101;

-- 通过视图删除数据
DELETE FROM v_employees_it WHERE employee_id = 102;

3.3 WITH CHECK OPTION

WITH CHECK OPTION用于确保通过视图进行的INSERT和UPDATE操作,结果仍然满足视图的WHERE条件。

sql 复制代码
-- 创建带CHECK OPTION的视图
CREATE VIEW v_employees_high_salary AS
SELECT 
    employee_id,
    first_name,
    last_name,
    salary
FROM employees
WHERE salary >= 10000
WITH CHECK OPTION;  -- 关键:确保数据符合视图条件

-- 以下操作会成功(salary >= 10000)
UPDATE v_employees_high_salary 
SET salary = 12000 
WHERE employee_id = 101;

-- 以下操作会失败(违反CHECK OPTION)
UPDATE v_employees_high_salary 
SET salary = 5000   -- 小于10000,违反视图条件
WHERE employee_id = 101;
-- ERROR 1369 (HY000): CHECK OPTION failed 'db.v_employees_high_salary'
LOCAL vs CASCADED
sql 复制代码
-- CASCADED(默认):检查当前视图及底层所有视图的条件
CREATE VIEW v_view1 AS
SELECT * FROM employees WHERE salary > 5000
WITH CASCADED CHECK OPTION;

-- LOCAL:只检查当前视图的条件
CREATE VIEW v_view2 AS
SELECT * FROM employees WHERE salary > 5000
WITH LOCAL CHECK OPTION;

四、视图的优缺点

4.1 优点

优点 详细说明
简化复杂查询 将复杂的JOIN、子查询封装成简单的视图查询
数据安全性 可以限制用户只能访问特定的行和列
逻辑独立性 应用程序使用视图,底层表结构变化时只需修改视图
数据抽象 为不同角色提供不同的数据视图

4.2 缺点

缺点 详细说明
性能开销 每次查询视图都需要执行定义视图的SQL
更新限制 复杂视图无法更新
调试困难 视图嵌套时,问题定位较复杂

4.3 使用建议

sql 复制代码
-- 经验之谈:视图的最佳实践

-- 1. 视图命名规范:以v_或view_开头
CREATE VIEW v_user_order_summary AS ...

-- 2. 避免视图嵌套过深(建议不超过3层)
-- 不推荐:view_a -> view_b -> view_c -> view_d

-- 3. 对于频繁查询的复杂视图,考虑使用物化视图(MySQL 8.0.13+)
-- 或使用汇总表代替

-- 4. 为视图添加注释
CREATE VIEW v_employee_stats AS
SELECT ...
COMMENT '员工统计信息视图,每日凌晨更新';

五、触发器详解

5.1 什么是触发器

**触发器(Trigger)**是一种特殊的存储过程,它在特定的表上执行特定的操作时自动触发执行。触发器可以在INSERT、UPDATE、DELETE操作之前(BEFORE)或之后(AFTER)执行。

5.2 触发器的应用场景

  • 审计日志:记录数据变更历史
  • 数据同步:一个表变更时同步更新其他表
  • 数据校验:在数据写入前进行复杂校验
  • 自动计算:自动更新统计字段
  • 级联操作:实现外键约束无法完成的级联逻辑

5.3 创建触发器

基本语法:

sql 复制代码
CREATE TRIGGER trigger_name
{BEFORE | AFTER} {INSERT | UPDATE | DELETE}
ON table_name
FOR EACH ROW
[trigger_body];

5.4 NEW和OLD关键字

操作类型 NEW OLD
INSERT 新插入的行数据 NULL(不存在)
UPDATE 更新后的新值 更新前的旧值
DELETE NULL(不存在) 被删除的行数据

5.5 触发器示例

示例1:BEFORE INSERT触发器(数据校验)
sql 复制代码
-- 创建员工表
CREATE TABLE employees (
    employee_id INT PRIMARY KEY AUTO_INCREMENT,
    first_name VARCHAR(50) NOT NULL,
    last_name VARCHAR(50) NOT NULL,
    email VARCHAR(100) UNIQUE NOT NULL,
    salary DECIMAL(10, 2),
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

-- 创建触发器:确保薪资不为负数
DELIMITER //

CREATE TRIGGER trg_before_employee_insert
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
    IF NEW.salary < 0 THEN
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Error: Salary cannot be negative';
    END IF;
    
    -- 自动转换邮箱为小写
    SET NEW.email = LOWER(NEW.email);
END //

DELIMITER ;

-- 测试触发器
INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('John', 'Doe', 'JOHN.DOE@EXAMPLE.COM', 5000);
-- 成功:email自动转为小写

INSERT INTO employees (first_name, last_name, email, salary)
VALUES ('Jane', 'Doe', 'jane.doe@example.com', -1000);
-- 失败:触发器抛出错误
示例2:AFTER UPDATE触发器(记录变更)
sql 复制代码
-- 创建薪资变更历史表
CREATE TABLE salary_history (
    history_id INT PRIMARY KEY AUTO_INCREMENT,
    employee_id INT NOT NULL,
    old_salary DECIMAL(10, 2),
    new_salary DECIMAL(10, 2),
    changed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    changed_by VARCHAR(100)
);

-- 创建触发器:记录薪资变更
DELIMITER //

CREATE TRIGGER trg_after_salary_update
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
    -- 只在薪资变化时记录
    IF OLD.salary <> NEW.salary THEN
        INSERT INTO salary_history (employee_id, old_salary, new_salary, changed_by)
        VALUES (NEW.employee_id, OLD.salary, NEW.salary, CURRENT_USER());
    END IF;
END //

DELIMITER ;

-- 测试触发器
UPDATE employees SET salary = 8000 WHERE employee_id = 1;
-- 自动在salary_history表中插入记录
示例3:BEFORE DELETE触发器(防止误删)
sql 复制代码
-- 创建触发器:防止删除重要员工
DELIMITER //

CREATE TRIGGER trg_before_employee_delete
BEFORE DELETE ON employees
FOR EACH ROW
BEGIN
    IF OLD.employee_id = 1 THEN  -- 假设ID=1是CEO
        SIGNAL SQLSTATE '45000'
        SET MESSAGE_TEXT = 'Error: Cannot delete the CEO record';
    END IF;
END //

DELIMITER ;
示例4:多个触发器(MySQL 5.7.2+)
sql 复制代码
-- MySQL 5.7.2+ 支持同一事件多个触发器,使用FOLLOWS/PRECEDES控制顺序

DELIMITER //

CREATE TRIGGER trg_after_insert_audit
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
    INSERT INTO audit_log (action, table_name, record_id, action_time)
    VALUES ('INSERT', 'employees', NEW.employee_id, NOW());
END //

CREATE TRIGGER trg_after_insert_notify
AFTER INSERT ON employees
FOR EACH ROW
FOLLOWS trg_after_insert_audit  -- 在audit触发器之后执行
BEGIN
    INSERT INTO notifications (message, created_at)
    VALUES (CONCAT('New employee added: ', NEW.first_name, ' ', NEW.last_name), NOW());
END //

DELIMITER ;

5.6 管理触发器

sql 复制代码
-- 查看所有触发器
SHOW TRIGGERS;

-- 查看指定表的触发器
SHOW TRIGGERS FROM your_database WHERE `Table` = 'employees';

-- 从information_schema查询
SELECT * FROM information_schema.triggers 
WHERE trigger_schema = 'your_database';

-- 查看触发器创建语句
SHOW CREATE TRIGGER trg_before_employee_insert;

-- 删除触发器
DROP TRIGGER IF EXISTS trg_before_employee_insert;

-- 禁用/启用触发器(MySQL 8.0)
-- 注意:MySQL不支持直接禁用触发器,需要删除重建或使用变量控制

六、实战:用触发器实现审计日志

6.1 需求分析

我们需要实现一个完整的审计日志系统,记录所有对employees表的变更操作。

6.2 表结构设计

sql 复制代码
-- 审计日志表
CREATE TABLE audit_log (
    log_id BIGINT PRIMARY KEY AUTO_INCREMENT,
    table_name VARCHAR(64) NOT NULL,
    operation VARCHAR(10) NOT NULL COMMENT 'INSERT/UPDATE/DELETE',
    record_id VARCHAR(50) NOT NULL,
    old_values JSON,
    new_values JSON,
    executed_by VARCHAR(100) DEFAULT CURRENT_USER(),
    executed_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    client_host VARCHAR(100),
    INDEX idx_table_time (table_name, executed_at),
    INDEX idx_record (table_name, record_id)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

6.3 创建审计触发器

sql 复制代码
DELIMITER //

-- INSERT审计触发器
CREATE TRIGGER trg_audit_employees_insert
AFTER INSERT ON employees
FOR EACH ROW
BEGIN
    INSERT INTO audit_log (table_name, operation, record_id, new_values, client_host)
    VALUES (
        'employees',
        'INSERT',
        NEW.employee_id,
        JSON_OBJECT(
            'employee_id', NEW.employee_id,
            'first_name', NEW.first_name,
            'last_name', NEW.last_name,
            'email', NEW.email,
            'salary', NEW.salary
        ),
        CONNECTION_ID()
    );
END //

-- UPDATE审计触发器
CREATE TRIGGER trg_audit_employees_update
AFTER UPDATE ON employees
FOR EACH ROW
BEGIN
    INSERT INTO audit_log (table_name, operation, record_id, old_values, new_values, client_host)
    VALUES (
        'employees',
        'UPDATE',
        NEW.employee_id,
        JSON_OBJECT(
            'first_name', OLD.first_name,
            'last_name', OLD.last_name,
            'email', OLD.email,
            'salary', OLD.salary
        ),
        JSON_OBJECT(
            'first_name', NEW.first_name,
            'last_name', NEW.last_name,
            'email', NEW.email,
            'salary', NEW.salary
        ),
        CONNECTION_ID()
    );
END //

-- DELETE审计触发器
CREATE TRIGGER trg_audit_employees_delete
AFTER DELETE ON employees
FOR EACH ROW
BEGIN
    INSERT INTO audit_log (table_name, operation, record_id, old_values, client_host)
    VALUES (
        'employees',
        'DELETE',
        OLD.employee_id,
        JSON_OBJECT(
            'employee_id', OLD.employee_id,
            'first_name', OLD.first_name,
            'last_name', OLD.last_name,
            'email', OLD.email,
            'salary', OLD.salary
        ),
        CONNECTION_ID()
    );
END //

DELIMITER ;

6.4 查询审计日志

sql 复制代码
-- 查看最近的操作记录
SELECT 
    log_id,
    operation,
    record_id,
    old_values,
    new_values,
    executed_by,
    executed_at
FROM audit_log
WHERE table_name = 'employees'
ORDER BY executed_at DESC
LIMIT 10;

-- 查看特定员工的变更历史
SELECT * FROM audit_log
WHERE table_name = 'employees' AND record_id = '101'
ORDER BY executed_at;

-- 统计每日操作次数
SELECT 
    DATE(executed_at) as operation_date,
    operation,
    COUNT(*) as count
FROM audit_log
GROUP BY DATE(executed_at), operation
ORDER BY operation_date DESC;

七、踩坑提醒

7.1 视图相关坑

坑1:视图性能问题
sql 复制代码
-- 问题:视图嵌套导致性能急剧下降
-- 不推荐:
CREATE VIEW v_level1 AS SELECT * FROM huge_table WHERE ...;
CREATE VIEW v_level2 AS SELECT * FROM v_level1 WHERE ...;
CREATE VIEW v_level3 AS SELECT * FROM v_level2 WHERE ...;
-- 查询v_level3时,会逐层展开,性能极差

-- 解决:尽量扁平化,或直接使用原始表
坑2:视图与索引
sql 复制代码
-- 视图本身不能创建索引
-- 但可以在基表上创建索引来优化视图查询

-- 推荐:为视图中常用的WHERE条件列创建索引
CREATE INDEX idx_employees_dept ON employees(department_id);
CREATE INDEX idx_employees_status ON employees(status);

7.2 触发器相关坑

坑1:触发器隐藏逻辑
sql 复制代码
-- 问题:触发器中的逻辑是"隐藏"的,容易导致意外行为
-- 比如:开发人员不知道有触发器,对表进行批量更新

-- 解决:
-- 1. 良好的文档和命名规范
-- 2. 在触发器中添加注释说明
-- 3. 批量操作前考虑临时禁用触发器(MySQL需删除重建)
坑2:递归触发器
sql 复制代码
-- 问题:触发器A修改表B,表B的触发器又修改表A,导致死循环

-- 示例:危险代码
DELIMITER //
CREATE TRIGGER trg_a AFTER UPDATE ON table_a
FOR EACH ROW
BEGIN
    UPDATE table_b SET ...;  -- 触发table_b的触发器
END //

CREATE TRIGGER trg_b AFTER UPDATE ON table_b
FOR EACH ROW
BEGIN
    UPDATE table_a SET ...;  -- 又触发table_a的触发器,死循环!
END //
DELIMITER ;

-- 解决:
-- 1. 仔细设计触发器逻辑,避免循环依赖
-- 2. 使用变量控制,防止递归
坑3:触发器中的错误处理
sql 复制代码
-- 问题:触发器中的错误会导致整个操作失败

-- 推荐:使用条件判断和错误处理
DELIMITER //
CREATE TRIGGER trg_safe_example
BEFORE INSERT ON employees
FOR EACH ROW
BEGIN
    DECLARE CONTINUE HANDLER FOR SQLEXCEPTION
    BEGIN
        -- 记录错误日志,但不阻止主操作
        INSERT INTO error_log (error_message, created_at)
        VALUES ('Trigger error occurred', NOW());
    END;
    
    -- 主逻辑
    SET NEW.email = LOWER(NEW.email);
END //
DELIMITER ;
坑4:大数据量下的触发器性能
sql 复制代码
-- 问题:对千万级表进行批量更新时,触发器会逐行执行,极慢

-- 解决:
-- 1. 大批量操作时,考虑先删除触发器,操作完成后再重建
-- 2. 或者使用存储过程批量处理,绕过触发器
-- 3. 考虑使用binlog解析代替触发器做审计

八、面试高频考点

8.1 视图和表的区别是什么?

答案要点:

区别点 视图
本质 虚拟表,存储的是SQL定义 实际存储数据的结构
数据存储 不存储数据,查询时动态生成 物理存储数据
占用空间 极小(仅存储定义) 较大
更新 受限制,复杂视图不可更新 可以自由增删改
性能 可能有性能开销 直接访问
用途 简化查询、安全控制 数据存储

8.2 什么情况下视图不能更新?

答案:

  1. 包含聚合函数(SUM、COUNT、AVG等)
  2. 包含DISTINCT关键字
  3. 包含GROUP BY或HAVING
  4. 包含UNION或UNION ALL
  5. 包含子查询
  6. 包含JOIN(部分情况)
  7. 包含计算列且该列未在基表中定义

8.3 触发器有哪些类型?

答案:

  • 按时机分:BEFORE(操作前)、AFTER(操作后)
  • 按事件分:INSERT、UPDATE、DELETE
  • 按粒度分:FOR EACH ROW(行级)、FOR EACH STATEMENT(语句级,MySQL不支持)

组合起来有6种:BEFORE INSERT、AFTER INSERT、BEFORE UPDATE、AFTER UPDATE、BEFORE DELETE、AFTER DELETE

8.4 NEW和OLD在触发器中有什么区别?

答案:

  • INSERT操作:NEW表示新插入的行数据,OLD为NULL
  • UPDATE操作:NEW表示更新后的新值,OLD表示更新前的旧值
  • DELETE操作:OLD表示被删除的行数据,NEW为NULL

8.5 触发器有什么性能影响?

答案:

  1. 增加写操作开销:每次DML操作都要执行触发器逻辑
  2. 事务影响:触发器失败会导致整个事务回滚
  3. 递归风险:不当设计可能导致死循环
  4. 调试困难:触发器中的错误难以定位
  5. 批量操作性能下降:逐行触发在大数据量时性能极差

优化建议:

  • 触发器逻辑尽量简单
  • 避免在触发器中进行复杂计算
  • 大数据量操作考虑临时禁用触发器
  • 考虑使用应用层逻辑代替触发器

8.6 WITH CHECK OPTION的作用是什么?

答案:

WITH CHECK OPTION用于确保通过视图进行的INSERT和UPDATE操作,其结果仍然满足视图的WHERE条件。

  • CASCADED(默认):检查当前视图及所有底层视图的条件
  • LOCAL:只检查当前视图的条件

九、总结

今天我们学习了MySQL中的两个重要特性:视图触发器

核心知识点回顾

  1. 视图:虚拟表,简化复杂查询,提供数据安全性

    • 创建:CREATE VIEW
    • 可更新视图需要满足特定条件
    • WITH CHECK OPTION保证数据一致性
  2. 触发器:自动执行的存储过程,实现业务自动化

    • BEFORE/AFTER + INSERT/UPDATE/DELETE
    • NEW和OLD关键字访问数据
    • 适合审计日志、数据校验等场景

使用建议

场景 推荐方案
简化复杂查询 视图
数据安全控制 视图 + 权限管理
审计日志 触发器 或 binlog解析
数据校验 触发器 或 CHECK约束
级联更新 外键约束 或 应用层处理

十、下一步预告

Day13 - MySQL性能优化实战

在下一篇文章中,我们将学习:

  • 性能优化的完整方法论
  • 慢查询日志分析
  • SQL优化技巧
  • 索引优化策略
  • 实战:从10秒到10毫秒的优化过程

性能优化是MySQL面试的重中之重,也是实际工作中最常遇到的问题,敬请期待!


参考资料

  1. MySQL 8.0 Reference Manual - Views
  2. MySQL 8.0 Reference Manual - Triggers

互动话题

  1. 你在实际项目中使用过视图和触发器吗?遇到了哪些问题?
  2. 对于审计日志,你更倾向于使用触发器还是binlog解析?为什么?
  3. 分享一个你使用视图或触发器解决实际问题的案例吧!

欢迎在评论区留言讨论,如果觉得文章有帮助,别忘了点赞收藏哦!我们下节课见!


本文是MySQL全面教学系列第12篇,系列文章持续更新中...

相关推荐
我是一颗柠檬15 小时前
【JDK8新特性】新工具类与API改进Day11
java·开发语言·后端·intellij-idea
山峰哥15 小时前
索引策略与SQL优化:从Explain对比到生产调优的完整方法论
android·java·数据库·sql·性能优化·深度优先
qq_4523962315 小时前
第八篇:《Dockerfile 指令精讲(一):FROM、RUN、COPY、ADD》
数据库·docker·postgresql
woniu_buhui_fei15 小时前
Redis实现分布式限流
数据库·redis·分布式
Tony Bai15 小时前
从 Go 迁移到 Rust
开发语言·后端·golang·rust
我是一颗柠檬15 小时前
【JDK8新特性】JDK8实战与面试高频考点汇总Day12
java·开发语言·后端·面试·职场和发展
杜子不疼.15 小时前
从“能用“到“敢用“:DolphinDB 通过国家安全可靠测评,时序数据库国产替代迈入新阶段
数据库·oracle·时序数据库
量子-Alex15 小时前
【大模型智能体】A practical guide to building agents
大数据·数据库·人工智能
YOU OU15 小时前
Spring事务和事务传播机制
java·数据库·spring