存储过程 与 存储函数的区别及用法 及 触发器 !!!

引言:

             存储函数存储过程,作为数据库中的预编译代码块,能够封装复杂的业务逻辑和数据处理流程,使得数据库操作更加简洁、易读和可维护。而触发器,则像是一个智能的守卫,能够在特定事件发生时自动执行预设的操作,确保数据的完整性和一致性。

简单概述: 如果只是需要看大概,看上面就可以了,详解可以往下看!!!


One. 略解: 

一、存储过程

  1. 定义:存储过程是SQL语句和可选控制流语句的预编译集合,以一个名称存储并作为一个单元处理。

  2. 特点

    • 可以执行一系列SQL语句。
    • 可以从自己的存储过程内引用其它存储过程。
    • 可以返回参数,如记录集,参数类型有in、out、inout三种。
    • 声明时不需要返回类型。
    • 一般作为一个独立的部分来执行(使用EXEC执行)。
  3. 使用场景:存储过程通常用于执行一系列操作,如数据清洗、数据转移、批处理任务等。

二、存储函数

  1. 定义:存储函数是由一个或多个SQL语句组成的子程序,可用于封装代码以便重新使用。

  2. 特点

    • 有许多限制,如不能用临时表,只能用表变量等。
    • 可以直接引用返回值,用表变量返回记录集。
    • 不能用于执行一组修改全局数据库状态的操作。
    • 函数参数只有in类型。
    • 需要描述返回类型,且函数中必须包含一个有效的RETURN语句。
    • 可以嵌入在SQL中使用,可以在SELECT中调用。
  3. 使用场景:存储函数适用于需要在SQL查询中使用的计算和数据转换,可以将其视为一个可复用的查询片段。

三、存储过程和存储函数的区别

  1. 标识符:存储过程的标识符是procedure,而存储函数的标识符是function。
  2. 返回类型:存储过程可以有多个返回类型(记录集、单个值等),而存储函数通常只能返回一个值或一个表对象。
  3. 调用方式:存储过程需要使用CALL语句进行调用,而存储函数可以直接在SELECT语句中调用。
  4. 限制:存储过程通常没有太多限制,而存储函数则有许多限制,如不能使用临时表等。

四、存储过程和存储函数的用法

  1. 创建

    • 存储过程:使用CREATE PROCEDURE语句创建。
    • 存储函数:使用CREATE FUNCTION语句创建。
  2. 调用

    • 存储过程:使用CALL语句调用。
    • 存储函数:可以在SELECT语句中直接调用,如SELECT function_name(parameter) FROM table_name。
  3. 查看和删除

    • 查看:可以使用SHOW PROCEDURE STATUS或SHOW FUNCTION STATUS语句查看存储过程或存储函数的状态信息。
    • 删除:可以使用DROP PROCEDURE或DROP FUNCTION语句删除存储过程或存储函数。

综上所述:   存储过程和存储函数在数据库中都扮演着重要的角色,它们各有特点和使用场景。根据实际需求选择合适的对象进行封装和调用,可以提高数据库操作的效率和可维护性。


Two. 详解:

存储过程:

变量

  1. 系统变量: 
  1.1 定义与作用

        系统变量是MySQL服务器内部维护的变量,用于存储系统配置信息和状态信息。这些变量通常由MySQL服务器在启动时初始化,并且可以通过SET命令或运行时参数进行修改。

1.2 分类

系统变量分为全局变量和会话变量两种:

  • 全局变量:影响整个MySQL服务器的操作,作用范围为整个服务器实例。使用@@global.前缀进行访问和修改。
  • 会话变量:仅影响当前会话(连接)的操作,作用范围为当前会话。使用@@session.@@(默认)前缀进行访问和修改。
1.3 示例
-- 查看全局变量
SHOW VARIABLES LIKE 'max_connections';

-- 设置全局变量(需要管理员权限)
SET GLOBAL max_connections = 200;

-- 查看会话变量
SHOW VARIABLES LIKE 'autocommit';

-- 设置会话变量
SET SESSION autocommit = 0;
2. 用户变量:
2.1 定义与作用

        用户变量是在MySQL客户端会话中定义的变量,它们在当前会话范围内有效,可以在会话的任何地方被引用和修改。用户变量通常以@符号开头。

2.2 特性
  • 用户变量在会话开始时创建,在会话结束时销毁。
  • 用户变量无需声明即可使用,赋值操作会自动创建变量。
  • 用户变量的值类型是动态的,可以存储各种数据类型。
 2.3 示例
-- 赋值用户变量
SET @counter = 1;

-- 使用用户变量
SELECT @counter;

-- 用户变量可以进行算术运算
SET @counter = @counter + 1;
SELECT @counter;

-- 用户变量可以用于存储查询结果
SELECT @max_salary := MAX(salary) FROM employees;
SELECT @max_salary;
3. 局部变量:
3.1 定义与作用

        局部变量是在存储过程、函数或触发器中定义的变量,它们的作用范围仅限于定义它们的代码块内。局部变量需要显式声明,并且可以在声明时指定数据类型。

在begin ~~end 之间使用的 ! ! ! 

3.2 特性
  • 局部变量在存储过程、函数或触发器开始时创建,在结束时销毁。
  • 局部变量只能用于存储单一的数据类型,且需要在DECLARE语句中显式声明。
  • 局部变量的名称不能与同级的局部变量、用户变量或系统变量重复。
3.3 示例
DELIMITER //

CREATE PROCEDURE CalculateSalary(IN base_salary DECIMAL(10,2), OUT total_salary DECIMAL(10,2))
BEGIN
    -- 声明局部变量
    DECLARE tax_rate DECIMAL(5,2) DEFAULT 0.20;
    DECLARE net_salary DECIMAL(10,2);

    -- 计算净工资
    SET net_salary = base_salary * (1 - tax_rate);

    -- 计算总工资(包括税收)
    SET total_salary = base_salary + (base_salary * tax_rate);
END //

DELIMITER ;

-- 调用存储过程
CALL CalculateSalary(5000, @total_salary);
SELECT @total_salary;

参数:

create  procedure Double_Number(inout number double) -- 创建一个名为Double_Number的存储过程,该过程接受一个inout参数number,类型为double
begin
    set number = number * 0.5; -- 将参数number的值设为它自身的一半
end;

set @a = 195; -- 声明一个用户变

call Double_Number(@a); -- 调用Double_Number存储过程,传入用户变量@a作为参数

select @a; -- 查询用户变量@a的值,此时它的值应该是原值的一半

流程控制:: 

if         判断

基本语法:

示列:

# 存储过程 - if
create  procedure hz_if()
begin
    declare  i int default 58;
    if i > 80 then
        select '优秀' as '成绩';
    elseif i > 60 then
        select '良好' as '成绩';
    else
        select '还得练' as '成绩';
    end if;
end;

call hz_if();  # 输出: 还得练
case   判断


create  procedure hz_case(in num int)
begin
    declare the_Month varchar(10);
    case
       when  num >=1 and num <=3 then
        set the_Month = '第一季度';
       when  num >=4 and num <=6 then
        set the_Month = '第二季度';
        when  num >=7 and num <=9 then
        set the_Month = '第三季度';
        when  num >=9 and num <=12 then
        set the_Month = '第四季度';
       else
           set the_Month = '月份错误';
    end case;
    select  concat('你输入的月份',num ,'是第',the_Month) as '结果';
end;


call hz_case(1); 输出: 你输入的月份 1 是第一季度

循环语句 

where 

示列:

计算从1累加到n的值,n为传入的参数值。

create  procedure   hz_while(in num int)
begin
     declare  i int default 0;
     while num > 0 do
         set  i := i + num;
         set  num = num - 1;
     end while;
     select i as '结果';
end;

call hz_while(10);  # 输出 : 55
repeat

         有点类型与java中的循环控制语句 do  where(!循环条件 )  进入这个循环,先循环一次,在判断条件,如果条件满足就退出循环 !!!

示列:

create  procedure hz_repeat(in num int)
begin
    declare  i int default 0;
    repeat
         set  i := i + num;
         set  num = num - 1;
    until num <= 0
    end repeat;
end;

call hz_repeat(10); 输出: 55
loop

语法结构:

类似break  和 continue  !!

示列:

1.计算从1累加到n的值,n为传入的参数值,

# 1 - n 累加 循环
create  procedure hz_loop(in num int)
begin
    declare  i int default 0;
    my_loop: loop
    if num <= 0 then
        leave my_loop;
    end if;
    set  i := i + num;
    set  num = num - 1;
    end loop my_loop;
    select i as '结果';
end;

call hz_loop(10);  # 输出: 55


2.计算从1到n之间的偶数累加的值,n为传入的参数值。

# 1 - n  偶数累加 循环

create  procedure hz_loop2(in num int)
begin
    declare  i int default 0;
    my_loop: loop
        if num <= 0 then
            leave my_loop;
        end if;
        if num % 2 = 1 then
            set  num = num - 1;
            leave my_loop;
        end if;
        set  i := i + num;
        set  num = num - 2;
    end loop my_loop;
    select i as '结果';
end;

call hz_loop2(10);  输出: 30

游标

语法定义:

游标(CURSOR)        是用来存储查询结果集的数据类型,在存储过程和函数中可以使用游标对结果集进行循环的处理。游标的使用包括游标的声明、OPEN、FETCH 和 CLOSE,其语法分别如下。

        sqlServer里面有个ROWTYPE,可以定义为某table的一行数据类型,接受一行数据 但是在mysql中平常我们定义的变量,都是只能去接收单个变量。如果多行多列,一个表的话,就需要通过musql中提供的游标(Cursor 来实现 !!!

简单概述:游标相当于缓冲,数据库查询是查出一组,而外部程序接受是接受一个,存在多对一的矛盾。有了游标就可以暂存查处的数据,解决多对一矛盾

这里简单先做个列子:

任务:

# 通过游标 来实现
# 查询people 表中年龄小于20以下的学生的姓名 和 职位 并且存储到一张新的表 new_Students (id , name , position)中:

--  逻辑

--  A . 声明游标,来存储我们查询表的数据集

--  B.  准备,创建表结构

--  C.  开启游标

--  D.  循环获取游标中的记录数据(注意解决游标数据为空的时候,退出循环,下面在讲解)

--  E.  获取的数据插入到新的表中

--  F.   关闭游标

 代码:

注意:  规范,定义了变量,这个变量要在游标声明之前,否贼会报错:

[42000][1337] Variable or condition declaration after cursor or handler declaration

欧克:

# 通过游标 来实现
# 查询people 表中年龄小于20以下的学生的姓名 和 职位 并且存储到一张新的表 new_Students 中
create procedure hz_cursor(in age int)
begin
    # 声明变量
    declare name varchar(20);
    declare position varchar(20);
    # 声明游标
    declare  my_cursor cursor for select name,position from people where age < age;

    # 创建新表
    drop table if exists new_Students;
    create table  if not exists new_Students
    (
        id       int auto_increment primary key comment '主键',
        name     varchar(20) not null comment '姓名',
        position varchar(20) not null comment '职位'
    )comment '新学生表';
    # 打开游标
    open my_cursor;
    # 循环游标
    while true do
        fetch  my_cursor into name,position;
        insert into new_Students(name,position) values (name,position);
    end while;
    # 关闭游标
    close my_cursor;
end;

call     hz_cursor(20);

注:获取数据的 ,按照我们声明游标的时候,获取的字段顺序来,取数据顺序也是按照这个顺序取就完事了!!! 逐读取每一行 

测试:

我们通过 Call  来调用我们函数 :

可以看到 新表已经创建了:数据也成功插入了

但是可以发现,又报了异常:【02000】 的 

         这个就是我们上面循环 因为我们每次都会读取一行数据,下一次就会读取下一行,当读取到最后一行读取完了,我们没有做处理,当循环下一次的时候,此时游标下一行是没有数据的了,就会报异常了,报了错误,就自然退出了循环,然后就结束了,此时其实后面的逻辑也不会执行了 !

此时就可以用我们Mysql中提供的条件处理程序(Handler)来处理了,类似java中 Try Catch 捕获异常来执行相应的处理:

条件处理程序:

条件处理程序(Handler)可以用来定义在流程控制结构执行过程中遇到问题时相应的处理步骤。具体语法为:

 

 我们这里解决上面的问题,只需要定义一个处理程序,因为我们这里循环,当报错的时候,其实数据已经获取完了。我们只需要来捕获这个异常后退出程序,然后关闭游标。如下:

 declare exit  handler for sqlstate '02000' close my_cursor;

  02000是一个这里错误的编码。你要是处理其他错误,就用其他的编码

不用状态码也可以用其他简写的:

SQLSTATE sqlstate_value:状态码,如 02000
SQLWARNING:         所有以01开头的SQLSTATE代码的简写
NOT FOUND:        所有以02开头的SQLSTATE代码的简写
SQLEXCEPTION:        所有没有被SQLWARNING 或 NOT FOUND捕获的SQLSTATE代码的简写

也可以参考myslq 官方文档;

https://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.htmlicon-default.png?t=O83Ahttps://dev.mysql.com/doc/mysql-errors/8.0/en/server-error-reference.html 里面就描述各种状态码对应的含义

如 刚刚的02000

ok ,允许 可以看见没有报错了,其实死循环还是没有解决,靠异常捕捉后在执行退出

存储函数:

······其实存储过程了解了,存储函数也差不多了了。语法结构,流程控制都是一样的,只是一些基础语法有一些不同。

存储函数是有返回值的存储过程,存储函数的参数只能是IN类型的。具体语法如下:

 简单示列:

从1到n的累加 

create function hz_fun(num int)
returns int   
begin
    declare  i int default 0;
    while num > 0 do
        set  i := i + num;
        set  num = num - 1;
    end while;
    return i;
end;

报错: [HY000][1418] This function has none of DETERMINISTIC, NO SQL, or READS SQL DATA in its declaration and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)
 是因为mysql 8 默认开启了 二进制日志:都会被写进二进制日志 然后需要我们声明类型deterministic

具体可参考:https://blog.csdn.net/lv_hang515888/article/details/78094889

 

create function hz_fun(num int)

returns int  deterministic
begin
    declare  i int default 0;
    while num > 0 do
        set  i := i + num;
        set  num = num - 1;
    end while;
    return i;
end;

select hz_fun(10);

输出:

其实存储函数能够实现的,存储过程也能实现,并且存储函数必须要有返回值  

触发器: 

介绍:

        触发器是与表有关的数据库对象,指在 inset/update/delete 之前或之后,触发并自动执行触发器中定义的SOL语句集合

触发器的这种特性可以协助应用在数据库端确保数据的完整性,日志记录,数据校验等操作

                当在触发器上发生插入。修改,删除操作的时候,mysql中会自动生成2张特殊大的临时表,new表和old 表,使用别名 OLD 和 NEW 来引用触发器中发生变化的记录内容,这与其他的数据库是相似的,(SQL Server 中,就是inserted和deleted 表)。现在触发器还只支持行级触发,不支持语句级触发。

行级触发器: 就是我这个触发器影响了多少行,就会执行多少次这个触发器。

语句触发器: 就是我不管你影响了多少行,我就执行一次

语法:

关键字:trigger

创建:

CREATE TRIGGER  'your_tiggerName'
BEFORE/AFTER INSERT/UPDATE/DELETE
ON tbl name FOR EACH ROW --行级触发器
BEGIN
trigger_stmt ;
END;

 'your_tiggerName' :  自己拟一个触发器名字

BEFORE/AFTER : 指定了触发器的触发时机,就是在操作这个表之前执行下面begin -end之间逻辑还是这个操作这个表之后在执行,就先后顺序 

INSERT/UPDATE/DELETE : 指定了触发器的触发事件。就是操作这个表的类型,如果是insert 就是当这个表插入数据的时候,就会触发 

ON tblename :  ON 关键字后面跟着的是触发器所关联的表的名称(tbl name)。这意味着触发器会在对该表执行指定的操作时触发。

 BEGIN ... END; 关键字用来定义一个触发器体的开始和结束。在这个块内,你可以编写多条SQL语句来定义触发器被触发时要执行的操作。

 查看:

SHOW triggers

查看当前数据库所有触发器 

删除:

DROP TRIGGER [schema name] trigger_name;--如果没有指定 schema name,默认为当前数据库

schema name : 可以指定数据库的名字,没有,就是默认当前数据库

简单案例:

通过触发器记录 people 表的数据变更日志,将变更日志插入到日志表new_peopleInfo中,包含增加,修改,删除 

 创建一个日志表:

# 创建一个日志表
create  table people_log(
    id int primary key auto_increment comment '主键',
    operation varchar(20) not null comment '操作l类型',
    operation_time datetime not null comment '操作时间',
    operation_id varchar(250) not null comment '操作id',
    operation_content text comment '操作内容'
)comment '操作学生日志表';

insert:

# 创建触发器
create trigger people_trigger
after  insert on people for each row
begin
    insert into people_log(operation,operation_time,operation_id,operation_content)
        values ('insert',now(),new.id,concat('插入学生信息,姓名:',new.name,' 职位:',new.position));
end;

# 查看
show triggers;

# 删除
drop trigger people_trigger;

# 示列
insert people( id,name, age, create_time, gotime, dormitory, tuanw) values ('220510425', '张三', 20, now(), null, 3, 1);

效果:

update:

同理:

# 更新 触发器
create trigger people_update_trigger
    after  update on people for each row
begin
    insert into people_log(operation,operation_time,operation_id,operation_content)
    values ('insert',now(),new.id,concat('更新之前学生信息,姓名:',OLD.name,' 职位:',OLD.position,'|',
        '更新之后学生信息,姓名:',new.name,' 职位:',new.position));
end;

# 更新id 2205100338
update people set name='何政啊' where id = 2205100338;

 

delete:

删除之后,只能拿到old 的数据了:

# 创建触发器
create trigger people_delete_trigger
    after  delete on people for each row
begin
    insert into people_log(operation,operation_time,operation_id,operation_content)
    values ('insert',now(),OLD.id,concat('插入学生信息,姓名:',OLD.name,' 职位:',OLD.position));
end;

Three. 结尾:

        那就结束了 !!! 寒假我们在开卷 !!! 不对,相遇 !!!祝大家 工作顺利  ! ,身体健康,天天开心 !!! 心想事成 !!!

 

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

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

相关文章

用nginx部署两个前端(超简单,三步!)

1.首先在nginx的html目录下创两个文件夹分别用于放两个前端打包好的静态资源&#xff0c;并且把静态资源各自放好&#xff1a; 2. 在nginx的配置文件里&#xff0c;写好两个server。如图&#xff0c;写好两个前端要用的端口以及刚才那两文件夹的路径&#xff1a; worker_proces…

level2逐笔委托查询接口

沪深逐笔委托队列查询 前置步骤 分配数据库服务器 查询模板 以下是沪深委托队列查询的请求模板&#xff1a; http://<数据库服务器>/sql?modeorder_book&code<股票代码>&offset<offset>&token<token>查询参数说明 参数名类型说明mo…

flask-admin的modelview 实现list列表视图中某个列字段值翻译

背景&#xff1a; flask-admin 开发中modelview视图是非常强大的&#xff0c;但文档写的很难受&#xff0c;只能通过源码慢慢摸索学习&#xff0c;一点点记录 材料&#xff1a; 可用的flask-admin 环境 制作&#xff1a; 样例代码&#xff1a; 1、modelview 视图代码 col…

打造基于 SSM 和 Vue 的卓越电脑测评系统:挖掘电脑潜力

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常适…

物联网:全面概述、架构、应用、仿真工具、挑战和未来方向

中文论文标题&#xff1a;物联网&#xff1a;全面概述、架构、应用、仿真工具、挑战和未来方向 英文论文标题&#xff1a;Internet of Things: a comprehensive overview, architectures, applications, simulation tools, challenges and future directions 作者信息&#x…

【AI学习】OpenAI推出o3,向AGI迈出关键一步

2024年12月21日&#xff0c;OpenAI在其为期12天发布会活动的最后一天&#xff0c;正式发布了备受期待的o3系列模型&#xff0c;包括o3和o3-mini。 o3 是一个非常强大的模型&#xff0c;在编码、数学以及 ARC-AGI 基准测试等多个基准上超过了 OpenAI 此前的 o1 模型&#xff08…

Oracle 中间件 Webcenter Portal服务器环境搭建

环境信息 服务器基本信息 如下表&#xff0c;本次安装总共使用2台服务器&#xff0c;具体信息如下&#xff1a; Webcenter1服务器 归类 SOA服务器 Ip Address 172.xx.xx.xx.xx HostName wcc01.xxxxxx.com Alias wccprd01 Webcenter2服务器 归类 OSB服务器 Ip Addr…

仿途唬养车系统汽修服务小程序修车店小程序源码

仿途唬养车系统汽修服务小程序修车店小程序源码 用户端&#xff0b;商家端&#xff0b;师傅端 也支持根据客户保养记录&#xff0c;系统自动推送 定期车检短信提醒 功能介绍: 支持下单上门服务、到店核销&#xff0c;支持单独选择项目、也支持选择服务人员、 和选择门店…

CAD xy坐标标注(跟随鼠标位置实时移动)——C#插件实现

效果如下&#xff1a; &#xff08;使用方法&#xff1a;命令行输入 “netload” 加载此dll插件&#xff0c;然后输入“xx”运行&#xff0c;选择文件夹即可。&#xff09; 部分代码如下&#xff1a; #if DEBUG using Autodesk.AutoCAD.DatabaseServices; using Autodesk.AutoC…

Java性能调优 - JVM性能监测及调优

JVM 内存模型概述 堆 堆是JVM内存中最大的一块内存空间&#xff0c;该内存被所有线程共享&#xff0c;几乎所有对象和数组都被分配到了堆内存中。堆被划分为新生代和老年代&#xff0c;新生代又被进一步划分为Eden和Survivor区&#xff0c;最后Survivor由From Survivor和To Su…

RK3588 , mpp硬编码yuv, 保存MP4视频文件.

RK3588 , mpp硬编码yuv, 保存MP4视频文件. ⚡️ 传送 ➡️ Ubuntu x64 架构, 交叉编译aarch64 FFmpeg mppRK3588, FFmpeg 拉流 RTSP, mpp 硬解码转RGBRk3588 FFmpeg 拉流 RTSP, 硬解码转RGBRK3588 , mpp硬编码yuv, 保存MP4视频文件.

【计算机网络2】计算机网络的性能能指标

目录 一 、计算机网络的性能指标 二、具体介绍 1、速 率 2、带 宽 3、吞 吐 量 4、时 延 5、时延带宽积 6、往 返 时 延 7、信道利用率 一 、计算机网络的性能指标 计算机网络的性能指标就是从不同方面度量计算机网络的性能&#xff0c;有如下7个指标&#xff1a; 速…

OpenAI 12天发布会(12 Days of OpenAI)总结

在OpenAI的“12 Days of OpenAI”活动中&#xff0c;每一天都会发布新的功能或技术&#xff0c;展示公司在AI领域的最新进展。首先展示下全部功能发布完成后&#xff0c;现在ChatGPT的界面&#xff1a; 以下是每一天的简要概述及其意义&#xff1a; 第1天 - 完整版O1模型 今天…

android:sharedUserId 应用进程声明介绍

背景 adb install 安装系统软件报错,原因是签名不一致,进程改变。 代码分析 AndroidManifest.xml 定义的 android:sharedUserId 应用归属进程不同,从phone切换到system。 初始配置 <manifest xmlns:android="http://schemas.android.com/apk/res/android"c…

Spark优化----Spark 性能调优

目录 常规性能调优 常规性能调优一&#xff1a;最优资源配置 常规性能调优二&#xff1a;RDD 优化 RDD 复用 RDD 持久化 RDD 尽可能早的 filter 操作 常规性能调优三&#xff1a;并行度调节 常规性能调优四&#xff1a;广播大变量 常规性能调优五&#xff1a;Kryo 序列化 常规性…

Android Room 数据库使用详解

一、Room介绍 Android Room 是 Google 提供的一个 Android 数据持久化库&#xff0c;是 Android Jetpack 组成部分之一。它提供了一个抽象层&#xff0c;使得 SQLite 数据库的使用更为便捷。通过 Room&#xff0c;开发者可以轻松地操作数据库&#xff0c;不需要直接编写繁琐的…

数据结构十大排序之(冒泡,快排,并归)

接上期&#xff1a; 数据结十大排序之&#xff08;选排&#xff0c;希尔&#xff0c;插排&#xff0c;堆排&#xff09;-CSDN博客 前言&#xff1a; 在计算机科学中&#xff0c;排序算法是最基础且最重要的算法之一。无论是大规模数据处理还是日常的小型程序开发&#xff0c;…

【原生js案例】让你的移动页面实现自定义的上拉加载和下拉刷新

目前很多前端UI都是自带有上拉加载和下拉刷新功能,按照官网配置去实现即可,比如原生小程序,vantUI等UI框架,都替我们实现了内部功能。 那如何自己来实现一个上拉加载和下拉刷新的功能? 实现效果 不用浏览器的css滚动条,自定义实现滚动效果 自定义实现滚动,添加上拉加载…

【D3.js in Action 3 精译_046】DIY 实战:在 Observable 平台利用饼图布局函数实现 D3 多个环形图的绘制

当前内容所在位置&#xff1a; 第五章 饼图布局与堆叠布局 ✔️ 5.1 饼图和环形图的创建 ✔️ 5.1.1 准备阶段&#xff08;一&#xff09;5.1.2 饼图布局生成器&#xff08;二&#xff09;5.1.3 圆弧的绘制&#xff08;三&#xff09;5.1.4 数据标签的添加&#xff08;四&#…

【案例80】麒麟操作系统无法使用Uclient访问NC65

问题现象 麒麟操作系统&#xff0c;安装Uclient&#xff0c;添加应用后无法看到登录界面&#xff0c;一直在转圈。 问题分析 进入到Uclient的工作目录 发现在工作目录下&#xff0c;无相关app.log生成。 查看Uclient的main.log发现&#xff0c;有大量的报错与Uclient下的sha…