ORACLE PL/SQL编程总结(一)

news2025/4/9 1:44:33


目录

1.1 SQL与PL/SQL

1.2 PL/SQL的优点或特征

1.3 PL/SQL 可用的SQL语句

1.4 运行PL/SQL程序

2.1 PL/SQL块

2.2 PL/SQL结构

2.3 标识符

2.4 PL/SQL 变量类型

2.5 运算符和表达式(数据定义)

2.6 变量赋值

2.7 变量作用范围及可见性

2.8 注释

2.9 简单例子

3.1 条件语句

3.2 CASE 表达式

3.3 循环

3.4 标号和GOTO

3.5 NULL 语句

4.1 游标概念

4.2 游标变量

🥇Summary

获取源码?私信?关注?点赞?收藏?



1.1 SQL与PL/SQL

1.1.1 什么是PL/SQL?

PL/SQL是 Procedure Language & Structured Query Language 的缩写。PL/SQL是对SQL语言存储过程语言的扩展。从ORACLE6以后,ORACLE的RDBMS附带了PL/SQL。它现在已经成为一种过程处理语言,简称PL/SQL。目前的PL/SQL包括两部分,一部分是数据库引擎部分;另一部分是可嵌入到许多产品(如C语言,JAVA语言等)工具中的独立引擎。可以将这两部分称为:数据库PL/SQL和工具PL/SQL。两者的编程非常相似。都具有编程结构、语法和逻辑机制。工具PL/SQL另外还增加了用于支持工具(如ORACLE Forms)的句法,如:在窗体上设置按钮等。


1.2 PL/SQL的优点或特征

1.2.1 有利于客户/服务器环境应用的运行

对于客户/服务器环境来说,真正的瓶颈是网络上。无论网络多快,只要客户端与服务器进行大量的数据交换。应用运行的效率自然就回受到影响。如果使用PL/SQL进行编程,将这种具有大量数据处理的应用放在服务器端来执行。自然就省去了数据在网上的传输时间。

1.2.2 适合于客户环境

PL/SQL由于分为数据库PL/SQL部分和工具PL/SQL。对于客户端来说,PL/SQL可以嵌套到相应的工具中,客户端程序可以执行本地包含PL/SQL部分,也可以向服务发SQL命令或激活服务器端的PL/SQL程序运行。

1.2.3 过程化

PL/SQL是Oracle在标准SQL上的过程性扩展,不仅允许在PL/SQL程序内嵌入SQL语句,而且允许使用各种类型的条件分支语句和循环语句,可以多个应用程序之间共享其解决方案。

1.2.4 模块化

PL/SQL程序结构是一种描述性很强、界限分明的块结构、嵌套块结构,被分成单独的过程、函数、触发器,且可以把它们组合为程序包,提高程序的模块化能力。

1.2.5 运行错误的可处理性

使用PL/SQL提供的异常处理(EXCEPTION),开发人员可集中处理各种ORACLE错误和PL/SQL错误,或处理系统错误与自定义错误,以增强应用程序的健壮性。

1.2.6 提供大量的内置程序包

ORACLE提供了大量的内置程序包。通过这些程序包能够实现DBS的一些低层操作、高级功能,不论对DBA还是应用开发人员都具有重要作用。

当然还有其它的一些优点如:更好的性能、可移植性和兼容性、可维护性、易用性与快速性等。


1.3 PL/SQL 可用的SQL语句

PL/SQL是ORACLE系统的核心语言,现在ORACLE的许多部件都是由PL/SQL写成。在PL/SQL中可以使用的SQL语句有:INSERT,UPDATE,DELETE,SELECT INTO,COMMIT,ROLLBACK,SAVEPOINT。

提示:在 PL/SQL中只能用 SQL语句中的 DML 部分,不能用 DDL 部分,如果要在PL/SQL中使用DDL(如CREATE table 等)的话,只能以动态的方式来使用。

l ORACLE 的 PL/SQL 组件在对 PL/SQL 程序进行解释时,同时对在其所使用的表名、列名及数据类型进行检查。

l PL/SQL 可以在SQL* PLUS 中使用。

l PL/SQL 可以在高级语言中使用。

l PL/SQL可以在ORACLE的开发工具中使用(如:SQL Developer或Procedure Builder等)。

l 其它开发工具也可以调用PL/SQL编写的过程和函数,如Power Builder 等都可以调用服务器端的PL/SQL过程。

1.4 运行PL/SQL程序

PL/SQL程序的运行是通过ORACLE中的一个引擎来进行的。这个引擎可能在ORACLE的服务器端,也可能在 ORACLE 应用开发的客户端。引擎执行PL/SQL中的过程性语句,然后将SQL语句发送给数据库服务器来执行。再将结果返回给执行端。


2.1 PL/SQL块

PL/SQL程序由三个块组成,即声明部分、执行部分、异常处理部分。

PL/SQL块的结构如下:

DECLARE
--声明部分: 在此声明PL/SQL用到的变量,类型及游标,以及局部的存储过程和函数
BEGIN
-- 执行部分: 过程及SQL 语句 , 即程序的主要部分
EXCEPTION
-- 执行异常部分: 错误处理
END``;

其中:执行部分不能省略。

PL/SQL 块可以分为三类:

  1. 无名块或匿名块(anonymous):动态构造,只能执行一次,可调用其它程序,但不能被其它程序调用。

  2. 命名块(named):是带有名称的匿名块,这个名称就是标签。

  3. 子程序(subprogram):存储在数据库中的存储过程、函数等。当在数据库上建立好后可以在其它程序中调用它们。

  4. 触发器(Trigger):当数据库发生操作时,会触发一些事件,从而自动执行相应的程序。

  5. 程序包(package):存储在数据库中的一组子程序、变量定义。在包中的子程序可以被其它程序包或子程序调用。但如果声明的是局部子程序,则只能在定义该局部子程序的块中调用该局部子程序。


2.2 PL/SQL结构

l PL/SQL块中可以包含子块;

l 子块可以位于 PL/SQL中的任何部分;

l 子块也即PL/SQL中的一条命令;


2.3 标识符

PL/SQL程序设计中的标识符定义与SQL 的标识符定义的要求相同。要求和限制有:

l 标识符名不能超过30字符;

l 第一个字符必须为字母;

l 不分大小写;

l 不能用 ‘ - ’ (减号);

l 不能是SQL保留字。

提示一般不要把变量名声明与表中字段名完全一样,如果这样可能得到不正确的结果

例如:下面的例子将会删除所有的纪录,而不是’EricHu’的记录;

DECLARE
  ename varchar2(20) :='EricHu';
BEGIN
  DELETE FROM scott.emp WHERE ename=ename;
END;

变量命名在PL/SQL中有特别的讲究,建议在系统的设计阶段就要求所有编程人员共同遵守一定的要求,使得整个系统的文档在规范上达到要求。下面是建议的命名方法:

标识符命名规则例子
程序变量V_nameV_name
程序常量C_NameC_company_name
游标变量Cursor_NameCursor_Emp
异常标识E_nameE_too_many
表类型Name_table_typeEmp_record_type
Name_tableEmp
记录类型Name_recordEmp_record
SQL* Plus 替代变量P_nameP_sal
绑定变量G_nameG_year_sal


2.4 PL/SQL 变量类型

在前面的介绍中,有系统的数据类型,也可以自定义数据类型。

2.4.1 变量类型

在ORACLE8i中可以使用的变量类型有:

类型子类说 明范 围ORACLE限制
CHARCharacterStringRowidNchar定长字符串 民族语言字符集0à32767可选,确省=12000
VARCHAR2Varchar, StringNVARCHAR2可变字符串民族语言字符集0à3276740004000
BINARY_INTEGER带符号整数,为整数计算优化性能
NUMBER(p,s)Dec Double precisionIntegerIntNumericRealSmall int小数, NUMBER 的子类型高精度实数整数, NUMBER 的子类型整数, NUMBER 的子类型与NUMBER等价与NUMBER等价整数, 比 integer 小
LONG变长字符串0->214748364732,767字节
DATE日期型公元前4712年1月1日至公元后4712年12月31日
BOOLEAN布尔型TRUE, FALSE,NULL不使用
ROWID存放数据库行号
UROWID通用行标识符,字符类型

在使用RETURNING 子句是应注意以下几点限制:

   1.不能与DML语句和远程对象一起使用;

 2.不能检索LONG 类型信息;

 3.当通过视图向基表中插入数据时,只能与单基表视图一起使用。

2.4.2 复合类型

ORACLE 在 PL/SQL 中除了提供象前面介绍的各种类型外,还提供一种称为复合类型的类型---记录和表。

2.4.2.1 记录类型

记录类型类似于C语言中的结构数据类型,它把逻辑相关的、分离的、基本数据类型的变量组成一个整体存储起来,它必须包括至少一个标量型或RECORD 数据类型的成员,称作PL/SQL RECORD 的域(FIELD),其作用是存放互不相同但逻辑相关的信息。在使用记录数据类型变量时,需要先在声明部分先定义记录的组成、记录的变量,然后在执行部分引用该记录变量本身或其中的成员。

定义记录类型语法如下:

TYPE record_name IS RECORD(
  v1 data_type1 [NOT NULL] [:= default_value ],
  v2 data_type2 [NOT NULL] [:= default_value ],
   ......
  vn data_typen [NOT NULL] [:= default_value ] );

例子:

DECLARE
    TYPE test_rec IS RECORD(
       Name VARCHAR2(30) NOT NULL := '胡勇',
       Info VARCHAR2(100));
    rec_book test_rec;
BEGIN
    rec_book.Name :='胡勇';
    rec_book.Info :='谈PL/SQL编程;';
    DBMS_OUTPUT.PUT_LINE(rec_book.Name||' '||rec_book.Info);
  END;

可以用 SELECT语句对记录变量进行赋值,只要保证记录字段与查询结果列表中的字段相配即可。

2.4.2.2 数组类型

数据是具有相同数据类型的一组成员的集合。每个成员都有一个唯一的下标,它取决于成员在数组中的位置。在PL/SQL中,数组数据类型是VARRAY。

定义VARRY数据类型语法如下:

TYPE varray_name IS VARRAY(size) OF element_type [NOT NULL];

varray_name是VARRAY数据类型的名称,size是下整数,表示可容纳的成员的最大数量,每个成员的数据类型是element_type。默认成员可以取空值,否则需要使用NOT NULL加以限制。对于VARRAY数据类型来说,必须经过三个步骤,分别是:定义、声明、初始化。

例子:

DECLARE
--定义一个最多保存5个VARCHAR(25)数据类型成员的VARRAY数据类型
  TYPE reg_varray_type IS VARRAY(5) OF VARCHAR(25);
--声明一个该VARRAY数据类型的变量
  v_reg_varray REG_VARRAY_TYPE;
BEGIN
--用构造函数语法赋予初值
  v_reg_varray := reg_varray_type
     ('中国', '美国', '英国', '日本', '法国');


  DBMS_OUTPUT.PUT_LINE('地区名称:'||v_reg_varray(1)||'、'
                  ||v_reg_varray(2)||'、'
                  ||v_reg_varray(3)||'、'
                  ||v_reg_varray(4));
  DBMS_OUTPUT.PUT_LINE('赋予初值NULL的第5个成员的值:'||v_reg_varray(5));
--用构造函数语法赋予初值后就可以这样对成员赋值
  v_reg_varray(5) := '法国';
  DBMS_OUTPUT.PUT_LINE('第5个成员的值:'||v_reg_varray(5));
END;

2.4.2.3 使用%TYPE

定义一个变量,其数据类型与已经定义的某个数据变量(尤其是表的某一列)的数据类型相一致,这时可以使用%TYPE。

  使用%TYPE特性的优点在于:

  l 所引用的数据库列的数据类型可以不必知道;

  l 所引用的数据库列的数据类型可以实时改变,容易保持一致,也不用修改PL/SQL程序。

DECLARE
  -- 用%TYPE 类型定义与表相配的字段
  TYPE T_Record IS RECORD(
    T_no emp.empno%TYPE,
    T_name emp.ename%TYPE,
    T_sal emp.sal%TYPE );
  -- 声明接收数据的变量
  v_emp T_Record;
BEGIN
  SELECT empno, ename, sal INTO v_emp FROM emp WHERE empno=7369;
  DBMS_OUTPUT.PUT_LINE
  (TO_CHAR(v_emp.t_no)||' '||v_emp.t_name||' ' || TO_CHAR(v_emp.t_sal));
END;

2.4.3 使用%ROWTYPE

PL/SQL 提供%ROWTYPE操作符, 返回一个记录类型, 其数据类型和数据库表的数据结构相一致。

  使用%ROWTYPE特性的优点在于:

  l 所引用的数据库中列的个数和数据类型可以不必知道;

  l 所引用的数据库中列的个数和数据类型可以实时改变,容易保持一致,也不用修改PL/SQL程序。

DECLARE
  v_empno emp.empno%TYPE :=&no;
  rec emp%ROWTYPE;
BEGIN
  SELECT * INTO rec FROM emp WHERE empno=v_empno;
  DBMS_OUTPUT.PUT_LINE('姓名:'||rec.ename||'工资:'||rec.sal||'工作时间:'||rec.hiredate);
END;

2.4.4 LOB类型

ORACLE提供了LOB (Large OBject)类型,用于存储大的数据对象的类型。ORACLE目前主要支持BFILE, BLOB, CLOB 及 NCLOB 类型。

BFILE (Movie)

存放大的二进制数据对象,这些数据文件不放在数据库里,而是放在操作系统的某个目录里,数据库的表里只存放文件的目录。

BLOB(Photo)

存储大的二进制数据类型。变量存储大的二进制对象的位置。大二进制对象的大小<=4GB。

CLOB(Book)

存储大的字符数据类型。每个变量存储大字符对象的位置,该位置指到大字符数据块。大字符对象的大小<=4GB。

NCLOB

存储大的NCHAR字符数据类型。每个变量存储大字符对象的位置,该位置指到大字符数据块。大字符对象的大小<=4GB。

2.4.5 BIND变量

绑定变量是在主机环境中定义的变量。在PL/SQL 程序中可以使用绑定变量作为他们将要使用的其它变量。为了在PL/SQL 环境中声明绑定变量,使用命令VARIABLE。例如:

VARIABLE return_code NUMBER
VARIABLE return_msg VARCHAR2(20)

可以通过SQL*Plus命令中的PRINT 显示绑定变量的值。例如:

PRINT return_code
PRINT return_msg

例子:

VARIABLE result NUMBER;
BEGIN
 SELECT (sal*10)+nvl(comm, 0) INTO :result FROM emp
 WHERE empno=7369;
END;
--然后再执行
PRINT result

2.4.6 PL/SQL 表(TABLE)

定义记录表(或索引表)数据类型。它与记录类型相似,但它是对记录类型的扩展。它可以处理多行记录,类似于高级中的二维数组,使得可以在PL/SQL中模仿数据库中的表。

定义记录表类型的语法如下:

TYPE table_name IS TABLE OF element_type [NOT NULL]
INDEX BY [BINARY_INTEGER | PLS_INTEGER | VARRAY2];

关键字INDEX BY表示创建一个主键索引,以便引用记录表变量中的特定行。

方法描述
EXISTS(n)如果集合的第n个成员存在,则返回true
COUNT返回已经分配了存储空间即赋值了的成员数量
FIRSTLASTFIRST:返回成员的最低下标值LAST:返回成员的最高下标值
PRIOR(n)返回下标为n的成员的前一个成员的下标。如果没有则返回NULL
NEXT(N)返回下标为n的成员的后一个成员的下标。如果没有则返回NULL
TRIMTRIM:删除末尾一个成员TRIM(n) :删除末尾n个成员
DELETEDELETE:删除所有成员DELETE(n) :删除第n个成员DELETE(m, n) :删除从n到m的成员
EXTENDEXTEND:添加一个null成员EXTEND(n):添加n个null成员EXTEND(n,i):添加n个成员,其值与第i个成员相同
LIMIT返回在varray类型变量中出现的最高下标值

例1:按一维数组使用记录表

DECLARE
--定义记录表数据类型
  TYPE reg_table_type IS` `TABLE` `OF` `varchar2(25)
  INDEX` `BY` `BINARY_INTEGER;
--声明记录表数据类型的变量
  v_reg_table REG_TABLE_TYPE;
  
BEGIN
  v_reg_table(1) := 'Europe';
  v_reg_table(2) := 'Americas';
  v_reg_table(3) := 'Asia';
  v_reg_table(4) := 'Middle East and Africa';
  v_reg_table(5) := 'NULL';


  DBMS_OUTPUT.PUT_LINE('地区名称:'||v_reg_table (1)||'、'
                  ||v_reg_table (2)||'、'
                  ||v_reg_table (3)||'、'
                  ||v_reg_table (4));
  DBMS_OUTPUT.PUT_LINE('第5个成员的值:'||v_reg_table(5));
END;

例2:按二维数组使用记录表

DECLARE
--定义记录表数据类型
  TYPE emp_table_type IS TABLE OF employees%ROWTYPE
  INDEX BY BINARY_INTEGER;
--声明记录表数据类型的变量
  v_emp_table EMP_TABLE_TYPE;
BEGIN
  SELECT first_name, hire_date, job_id INTO
  v_emp_table(1).first_name,v_emp_table(1).hire_date, v_emp_table(1).job_id
  FROM employees WHERE employee_id = 177;
  SELECT first_name, hire_date, job_id INTO
  v_emp_table(2).first_name,v_emp_table(2).hire_date, v_emp_table(2).job_id
  FROM employees WHERE employee_id = 178;

  DBMS_OUTPUT.PUT_LINE('177雇员名称:'||v_emp_table(1).first_name
       ||' 雇佣日期:'||v_emp_table(1).hire_date
       ||' 岗位:'||v_emp_table(1).job_id);
  DBMS_OUTPUT.PUT_LINE('178雇员名称:'||v_emp_table(2).first_name
       ||' 雇佣日期:'||v_emp_table(2).hire_date
       ||' 岗位:'||v_emp_table(2).job_id);
END;

2.5 运算符和表达式(数据定义)

2.5.1 关系运算符

运算符意义
=等于
<> , != , ~= , ^=不等于
<小于
>大于
<=小于或等于
>=大于或等于

2.5.2 一般运算符

运算符意义
+加号
-减号
*乘号
/除号
:=赋值号
=>关系号
..范围运算符
||字符连接符

2.5.3 逻辑运算符

运算符意义
IS NULL是空值
BETWEEN AND介于两者之间
IN在一列值中间
AND逻辑与
OR逻辑或
NOT取返,如IS NOT NULL, NOT IN

2.6 变量赋值

在PL/SQL编程中,变量赋值是一个值得注意的地方,它的语法如下:

1VARIABLE := EXPRESSION ;

  variable 是一个PL/SQL变量, expression 是一个PL/SQL 表达式.

2.6.1 字符及数字运算特点

空值加数字仍是空值:NULL + < 数字> = NULL

 空值加(连接)字符,结果为字符:NULL || <字符串> = < 字符串>

2.6.2 BOOLEAN 赋值

布尔值只有TRUE, FALSE及 NULL 三个值。如:

DECLARE bDone BOOLEAN; BEGIN bDone := FALSE; 
    WHILE NOT bDone LOOP Null;
    END LOOP; END;

2.6.3 数据库赋值

数据库赋值是通过 SELECT语句来完成的,每次执行 SELECT语句就赋值一次,一般要求被赋值的变量与SELECT中的列名要一一对应。如:

DECLARE emp_id emp.empno%TYPE :=7788; emp_name emp.ename%TYPE; wages emp.sal%TYPE; BEGINSELECT ename,
         NVL(sal,
        0) + NVL(comm,
        0) INTO emp_name,
         wages
FROM emp
WHERE empno = emp_id; DBMS_OUTPUT.PUT_LINE(emp_name||'----'||to_char(wages)); 
END;

提示:不能将***SELECT**语句中的列赋值给布尔变量。***

2.6.4 可转换的类型赋值

l CHAR 转换为 NUMBER**:**

使用 TO_NUMBER 函数来完成字符到数字的转换,如:

1V_TOTAL := TO_NUMBER(``'100.0'``) + SAL;

l NUMBER 转换为**CHAR:**

使用 TO_CHAR函数可以实现数字到字符的转换,如:

1V_COMM := TO_CHAR(``'123.45'``) || ``'元' ;

l 字符转换为日期:

使用 TO_DATE函数可以实现 字符到日期的转换,如:

1V_DATE := TO_DATE(``'2001.07.03'``,``'YYYY.MM.DD'``);

l 日期转换为字符

使用 TO_CHAR函数可以实现日期到字符的转换,如:

1V_TO_DAY := TO_CHAR(SYSDATE, ``'YYYY.MM.DD HH24:MI:SS'``) ;

2.7 变量作用范围及可见性

变量的作用域是指变量的有效作用范围,与其它高级语言类似,PL/SQL的变量作用范围特点是:

l 变量的作用范围是在你所引用的程序单元(块、子程序、包)内。即从声明变量开始到该块的结束。

l 一个变量(标识)只能在你所引用的块内是可见的。

l 当一个变量超出了作用范围,PL/SQL引擎就释放用来存放该变量的空间(因为它可能不用了)。

l 在子块中重新定义该变量后,它的作用仅在该块内。

2.8 注释

在PL/SQL里,可以使用两种符号来写注释,即:

l 使用双 ‘-‘ ( 减号) 加注释

PL/SQL允许用 – 来写注释,它的作用范围是只能在一行有效。如:

1V_SAL NUMBER(12,2); ``-- 人员的工资变量。

l 使用 /* */ 来加一行或多行注释,如:

/***********************************************/
/* 文件名: department_salary.sql   */
/* 作 者: Enovo          */
/* 时 间: 2023-6-10          */
/***********************************************/

*提示:*被解释后存放在数据库中的 PL/SQL 程序,一般系统自动将程序头部的注释去掉。只有在 PROCEDURE 之后的注释才被保留;另外程序中的空行也自动被去掉。

2.9 简单例子

2.9.1 简单数据插入例子:

/***********************************************/ /* 文件名: test.sql */ /* 说 明: 一个简单的插入测试,无实际应用。*/ /* 作 者: Enovo */ /* 时 间: 2023-6-11 */ /***********************************************/ 
v_ename VARCHAR2(20) := 'Bill'; v_sal NUMBER(7,2) :=1234.56; v_deptno NUMBER(2) := 10; v_empno NUMBER(4) := 8888; 
BEGIN INSERT INTO emp ( empno, ename, JOB, sal, deptno , hiredate ) VALUES (v_empno, v_ename, 'Manager', v_sal, v_deptno, TO_DATE('1954.06.09','yyyy.mm.dd') ); 
COMMIT; 
END;

2.9.2 简单数据删除例子:

/***********************************************/
/* 文件名: test_deletedata.sql   */
/* 说 明:
    简单的删除例子,不是实际应用。 */
/* 作 者: ZRJ           */
/* 时 间: 2017-3-22         */
/***********************************************/
DECLARE
 v_ename  VARCHAR2(20) := 'Bill';
 v_sal    NUMBER(7,2) :=1234.56;
 v_deptno  NUMBER(2) := 10;
 v_empno  NUMBER(4) := 8888;
BEGIN
 INSERT INTO emp ( empno, ename, JOB, sal, deptno , hiredate ) 
VALUES ( v_empno, v_ename, ‘Manager’, v_sal, v_deptno,
TO_DATE(’1954.06.09’,’yyyy.mm.dd’) );
 COMMIT;
END;
 DECLARE
 v_empno  number(4) := 8888;
BEGIN
 DELETE FROM emp WHERE empno=v_empno;
 COMMIT;
END;

****************
---------PL/SQL流程控制语句------------

介绍PL/SQL的流程控制语句, 包括如下三类:

控制语句: IF 语句

l 循环语句: LOOP语句, EXIT语句

l 顺序语句: GOTO语句, NULL语句

3.1 条件语句

IF <布尔表达式> THEN

PL/SQL 和 SQL语句

END IF;

-----------------------

IF <布尔表达式> THEN

PL/SQL 和 SQL语句

ELSE

其它语句

END IF;

-----------------------

IF <布尔表达式> THEN

PL/SQL 和 SQL语句

ELSIF < 其它布尔表达式> THEN

其它语句

ELSIF < 其它布尔表达式> THEN

其它语句

ELSE

其它语句

END IF;

提示: ELSIF 不能写成 ELSEIF

例1:

DECLARE v_empno employees.employee_id%TYPE :=&empno; V_salary employees.salary%TYPE; V_comment VARCHAR2(35); BEGINSELECT salary INTO v_salary
FROM employees
WHERE employee_id = v_empno; IF v_salary < 1500 THEN
    V_comment:= '太少了,加点吧~!'; ELSIF v_salary <3000 THEN
    V_comment:= '多了点,少点吧~!';
    ELSE V_comment:= '没有薪水~!';
    END IF; DBMS_OUTPUT.PUT_LINE(V_comment); exception
    WHEN no_data_found THEN
    DBMS_OUTPUT.PUT_LINE('没有数据~!');
    WHEN others THEN
    DBMS_OUTPUT.PUT_LINE(sqlcode || '---' || sqlerrm); END;

例2:

DECLARE v_first_name VARCHAR2(20); v_salary NUMBER(7,
        2); BEGINSELECT first_name,
         salary INTO v_first_name,
         v_salary
FROM employees
WHERE employee_id = &emp_id; DBMS_OUTPUT.PUT_LINE(v_first_name||'雇员的工资是'||v_salary); IF v_salary < 10000 THEN
    DBMS_OUTPUT.PUT_LINE('工资低于10000');
    ELSE IF 10000 <= v_salary
        AND v_salary < 20000 THEN
    DBMS_OUTPUT.PUT_LINE('工资在10000到20000之间');
    ELSE DBMS_OUTPUT.PUT_LINE('工资高于20000');
    END IF;
    END IF; END;

3.2 CASE 表达式

---------格式一---------

CASE 条件表达式

WHEN 条件表达式结果1 THEN

语句段1

WHEN 条件表达式结果2 THEN

语句段2

......

WHEN 条件表达式结果n THEN

语句段n

[ELSE 条件表达式结果]

END;

---------格式二---------

CASE

WHEN 条件表达式1 THEN

语句段1

WHEN 条件表达式2 THEN

语句段2

......

WHEN 条件表达式n THEN

语句段n

[ELSE 语句段]

END;

例子:

DECLARE v_first_name employees.first_name%TYPE; v_job_id employees.job_id%TYPE; v_salary employees.salary%TYPE; v_sal_raise NUMBER(3,
        2); BEGINSELECT first_name,
         job_id,
         salary INTO v_first_name,
         v_job_id,
         v_salary
FROM employees
WHERE employee_id = &emp_id;
    CASE
    WHEN v_job_id = 'PU_CLERK' THEN
    IF v_salary < 3000 THEN
    v_sal_raise := .08;
    ELSE v_sal_raise := .07;
    END IF;
    WHEN v_job_id = 'SH_CLERK' THEN
    IF v_salary < 4000 THEN
    v_sal_raise := .06;
    ELSE v_sal_raise := .05;
    END IF;
    WHEN v_job_id = 'ST_CLERK' THEN
    IF v_salary < 3500 THEN
    v_sal_raise := .04;
    ELSE v_sal_raise := .03;
    END IF;
    ELSE DBMS_OUTPUT.PUT_LINE('该岗位不涨工资: '||v_job_id);
    END CASE; DBMS_OUTPUT.PUT_LINE(v_first_name||'的岗位是'||v_job_id ||'、的工资是'||v_salary ||'、工资涨幅是'||v_sal_raise); END;

3.3 循环

\1. 简单循环

LOOP 要执行的语句; EXIT WHEN <条件语句> --条件满足,退出循环语句 END LOOP;

例子:

DECLARE int NUMBER(2) :=0; BEGIN LOOP int := int + 1; DBMS_OUTPUT.PUT_LINE('int 的当前值为:'||int); EXIT
    WHEN int =10;
    END LOOP; END;

\2. WHILE 循环

WHILE <布尔表达式> LOOP 要执行的语句; END LOOP;

例子:

DECLARE x NUMBER :=1; BEGIN WHILE x<=10 LOOP DBMS_OUTPUT.PUT_LINE('X的当前值为:'||x); x:= x+1;
    END LOOP; END;

\3. 数字式循环

[<<循环标签>>] FOR 循环计数器 IN [ REVERSE ] 下限 .. 上限 LOOP 要执行的语句; END LOOP [循环标签];

每循环一次,循环变量自动加1;使用关键字REVERSE,循环变量自动减1。跟在IN REVERSE 后面的数字必须是从小到大的顺序,而且必须是整数,不能是变量或表达式。可以使用EXIT 退出循环。

例子1:

BEGIN FOR int IN 1..10 LOOP DBMS_OUTPUT.PUT_LINE('int 的当前值为: '||int);
    END LOOP; END;

例子2:

DECLARE TYPE jobids_varray IS VARRAY(12) OF VARCHAR2(10); --定义一个VARRAY数据类型 v_jobids JOBIDS_VARRAY; --声明一个具有JOBIDS_VARRAY数据类型的变量 v_howmany NUMBER; --声明一个变量来保存雇员的数量

BEGIN

--用某些job_id值初始化数组

v_jobids := jobids_varray('FI_ACCOUNT', 'FI_MGR', 'ST_CLERK', 'ST_MAN');

--用FOR...LOOP...END LOOP循环使用每个数组成员的值

FOR i IN v_jobids.FIRST..v_jobids.LAST LOOP

--针对数组中的每个岗位,决定该岗位的雇员的数量

SELECT count(*) INTO v_howmany
FROM employees
WHERE job_id = v_jobids(i); DBMS_OUTPUT.PUT_LINE ( '岗位'||v_jobids(i)|| '总共有'|| TO_CHAR(v_howmany) || '个雇员');
    END LOOP; END;

例:在While循环中嵌套loop循环

/求100至110之间的素数/

DECLARE v_m NUMBER := 101; v_i NUMBER; v_n NUMBER := 0; BEGIN WHILE v_m < 110 LOOP v_i := 2; LOOP IF mod(v_m, v_i) = 0 THEN
    v_i := 0; EXIT;
    END IF; v_i := v_i + 1; EXIT
    WHEN v_i > v_m - 1;
    END LOOP; IF v_i > 0 THEN
    v_n := v_n + 1; DBMS_OUTPUT.PUT_LINE('第'|| v_n || '个素数是' || v_m);
    END IF; v_m := v_m + 2;
    END LOOP; END;


3.4 标号和GOTO

PL/SQL中GOTO语句是无条件跳转到指定的标号去的意思。语法如下:

GOTO label; ...... <<label>> /*标号是用<< >>括起来的标识符 */

注意,在以下地方使用是不合法的,编译时会出错误。

u 跳转到非执行语句前面。

u 跳转到子块中。

u 跳转到循环语句中。

u 跳转到条件语句中。

u 从异常处理部分跳转到执行。

u 从条件语句的一部分跳转到另一部分。

例子:

DECLARE v_i NUMBER := 0; v_s NUMBER := 0; BEGIN <<label_1>> v_i := v_i + 1; IF v_i <= 1000 THEN
    v_s := v_s + v_i; GOTO label_1;
    END IF; DBMS_OUTPUT.PUT_LINE(v_s); END;

3.5 NULL 语句

在PL/SQL 程序中,NULL语句是一个可执行语句,可以用 null 语句来说明“不用做任何事情”的意思,相当于一个占位符或不执行任何操作的空语句,可以使某些语句变得有意义,提高程序的可读性,保证其他语句结构的完整性和正确性。如:

例子:

DECLARE v_emp_id employees.employee_id%TYPE; v_first_name employees.first_name%TYPE; v_salary employees.salary%TYPE; v_sal_raise NUMBER(3,
        2); BEGIN v_emp_id := &emp_id;SELECT first_name,
         salary INTO v_first_name,
         v_salary
FROM employees
WHERE employee_id = v_emp_id; IF v_salary <= 3000 THEN
    v_sal_raise := .10; DBMS_OUTPUT.PUT_LINE(v_first_name||'的工资是'||v_salary ||'、工资涨幅是'||v_sal_raise);
    ELSE NULL;
    END IF; END;

在 PL/SQL 程序中,对于处理多行记录的事务经常使用游标来实现。


4.1 游标概念

在PL/SQL块中执行SELECT、INSERT、DELETE和UPDATE语句时,ORACLE会在内存中为其分配上下文区(Context Area),即缓冲区。游标是指向该区的一个指针,或是命名一个工作区(Work Area),或是一种结构化数据类型。它为应用等量齐观提供了一种对具有多行数据查询结果集中的每一行数据分别进行单独处理的方法,是设计嵌入式SQL语句的应用程序的常用编程方式。

在每个用户会话中,可以同时打开多个游标,其数量由数据库初始化参数文件中的OPEN_CURSORS参数定义。

对于不同的SQL语句,游标的使用情况不同:

SQL语句游标
非查询语句隐式的
结果是单行的查询语句隐式的或显示的
结果是多行的查询语句显示的

4.1.1 处理显示游标

1 . 显式游标处理

显式游标处理需四个 PL/SQL步骤:

l 定义/声明游标:就是定义一个游标名,以及与其相对应的SELECT 语句。

格式:

CURSOR cursor_name[(parameter[, parameter]…)] [RETURN datatype] IS select_statement;

游标参数只能为输入参数,其格式为:

parameter_name [IN] datatype [{:= | DEFAULT} expression]

在指定数据类型时,不能使用长度约束。如NUMBER(4),CHAR(10) 等都是错误的。

[RETURN datatype]是可选的,表示游标返回数据的数据。如果选择,则应该严格与select_statement中的选择列表在次序和数据类型上匹配。一般是记录数据类型或带“%ROWTYPE”的数据

l 打开游标:就是执行游标所对应的SELECT 语句,将其查询结果放入工作区,并且指针指向工作区的首部,标识游标结果集合。如果游标查询语句中带有FOR UPDATE选项,OPEN 语句还将锁定数据库表中游标结果集合对应的数据行。

格式:

OPEN cursor_name[([parameter =>] value[, [parameter =>] value]…)];

在向游标传递参数时,可以使用与函数参数相同的传值方法,即位置表示法和名称表示法。PL/SQL 程序不能用OPEN 语句重复打开一个游标。

l 提取游标数据:就是检索结果集合中的数据行,放入指定的输出变量中。

格式:

FETCH cursor_name INTO {variable_list | record_variable };

执行FETCH语句时,每次返回一个数据行,然后自动将游标移动指向下一个数据行。当检索到最后一行数据时,如果再次执行FETCH语句,将操作失败,并将游标属性%NOTFOUND置为TRUE。所以每次执行完FETCH语句后,检查游标属性%NOTFOUND就可以判断FETCH语句是否执行成功并返回一个数据行,以便确定是否给对应的变量赋了值。

l 对该记录进行处理;

l 继续处理,直到活动集合中没有记录;

l 关闭游标:当提取和处理完游标结果集合数据后,应及时关闭游标,以释放该游标所占用的系统资源,并使该游标的工作区变成无效,不能再使用FETCH 语句取其中数据。关闭后的游标可以使用OPEN 语句重新打开。

格式:

CLOSE cursor_name;

注:定义的游标不能有INTO 子句。

例子. 查询前10名员工的信息。

DECLARE CURSOR c_cursor ISSELECT first_name || last_name,
         Salary
FROM EMPLOYEES
WHERE rownum<11; v_ename EMPLOYEES.first_name%TYPE; v_sal EMPLOYEES.Salary%TYPE; BEGIN OPEN c_cursor; FETCH c_cursor INTO v_ename, v_sal; WHILE c_cursor%FOUND LOOP DBMS_OUTPUT.PUT_LINE(v_ename||'---'||to_char(v_sal) ); FETCH c_cursor INTO v_ename, v_sal;
    END LOOP; CLOSE c_cursor; END;

2.游标属性

Cursor_name%FOUND 布尔型属性,当最近一次提取游标操作FETCH成功则为 TRUE,否则为FALSE;

Cursor_name%NOTFOUND 布尔型属性,与%FOUND相反;

Cursor_name%ISOPEN 布尔型属性,当游标已打开时返回 TRUE;

Cursor_name%ROWCOUNT 数字型属性,返回已从游标中读取的记录数。

例1:没有参数且没有返回值的游标。

DECLARE v_f_name employees.first_name%TYPE; v_j_id employees.job_id%TYPE; CURSOR c1 --声明游标,
        没有参数没有返回值 ISSELECT first_name,
         job_id
FROM employees
WHERE department_id = 20; BEGIN OPEN c1; --打开游标 LOOP FETCH c1 INTO v_f_name, v_j_id; --提取游标 IF c1%FOUND THEN
    DBMS_OUTPUT.PUT_LINE(v_f_name||'的岗位是'||v_j_id);
    ELSE DBMS_OUTPUT.PUT_LINE('已经处理完结果集了'); EXIT;
    END IF;
    END LOOP; CLOSE c1; --关闭游标 END;

例2:有参数且没有返回值的游标。

DECLARE v_f_name employees.first_name%TYPE; v_h_date employees.hire_date%TYPE; CURSOR c2(dept_id NUMBER,
         j_id VARCHAR2) --声明游标,
        有参数没有返回值 ISSELECT first_name,
         hire_date
FROM employees
WHERE department_id = dept_id
        AND job_id = j_id; BEGIN OPEN c2(90, 'AD_VP'); --打开游标,传递参数值 LOOP FETCH c2 INTO v_f_name, v_h_date; --提取游标 IF c2%FOUND THEN
    DBMS_OUTPUT.PUT_LINE(v_f_name||'的雇佣日期是'||v_h_date);
    ELSE DBMS_OUTPUT.PUT_LINE('已经处理完结果集了'); EXIT;
    END IF;
    END LOOP; CLOSE c2; --关闭游标 END;

例3:有参数且有返回值的游标。

DECLARE TYPE emp_record_type IS RECORD( f_name employees.first_name%TYPE,
         h_date employees.hire_date%TYPE); v_emp_record EMP_RECORD_TYPE; CURSOR c3(dept_id NUMBER,
         j_id VARCHAR2) --声明游标,
        有参数有返回值 RETURN EMP_RECORD_TYPE ISSELECT first_name,
         hire_date
FROM employees
WHERE department_id = dept_id
        AND job_id = j_id; BEGIN OPEN c3(j_id => 'AD_VP', dept_id => 90); --打开游标,传递参数值 LOOP FETCH c3 INTO v_emp_record; --提取游标 IF c3%FOUND THEN
    DBMS_OUTPUT.PUT_LINE(v_emp_record.f_name||'的雇佣日期是' ||v_emp_record.h_date);
    ELSE DBMS_OUTPUT.PUT_LINE('已经处理完结果集了'); EXIT;
    END IF;
    END LOOP; CLOSE c3; --关闭游标 END;

3. 游标的FOR循环

PL/SQL语言提供了游标FOR循环语句,自动执行游标的OPEN、FETCH、CLOSE语句和循环语句的功能;当进入循环时,游标FOR循环语句自动打开游标,并提取第一行游标数据,当程序处理完当前所提取的数据而进入下一次循环时,游标FOR循环语句自动提取下一行数据供程序处理,当提取完结果集合中的所有数据行后结束循环,并自动关闭游标。

格式:

FOR index_variable IN cursor_name[(value[, value]…)] LOOP -- 游标数据处理代码 END LOOP;

其中:

index_variable为游标FOR 循环语句隐含声明的索引变量,该变量为记录变量,其结构与游标查询语句返回的结构集合的结构相同。在程序中可以通过引用该索引记录变量元素来读取所提取的游标数据,index_variable中各元素的名称与游标查询语句选择列表中所制定的列名相同。如果在游标查询语句的选择列表中存在计算列,则必须为这些计算列指定别名后才能通过游标FOR 循环语句中的索引变量来访问这些列数据。

注:不要在程序中对游标进行人工操作;不要在程序中定义用于控制FOR循环的记录。

例子:当所声明的游标带有参数时,通过游标FOR 循环语句为游标传递参数。

DECLARE CURSOR c_cursor(dept_no NUMBER DEFAULT 10) ISSELECT department_name,
         location_id
FROM departments
WHERE department_id <= dept_no; BEGIN DBMS_OUTPUT.PUT_LINE('当dept_no参数值为30:'); FOR c1_rec IN c_cursor(30) LOOP DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);
    END LOOP; DBMS_OUTPUT.PUT_LINE(CHR(10)||'使用默认的dept_no参数值10:'); FOR c1_rec IN c_cursor LOOP DBMS_OUTPUT.PUT_LINE(c1_rec.department_name||'---'||c1_rec.location_id);
    END LOOP; END;

4.1.2 处理隐式游标

显式游标主要是用于对查询语句的处理,尤其是在查询结果为多条记录的情况下;而对于非查询语句,如修改、删除操作,则由ORACLE 系统自动地为这些操作设置游标并创建其工作区,这些由系统隐含创建的游标称为隐式游标,隐式游标的名字为SQL,这是由ORACLE 系统定义的。对于隐式游标的操作,如定义、打开、取值及关闭操作,都由ORACLE 系统自动地完成,无需用户进行处理。用户只能通过隐式游标的相关属性,来完成相应的操作。在隐式游标的工作区中,所存放的数据是与用户自定义的显示游标无关的、最新处理的一条SQL 语句所包含的数据。

格式调用为: SQL%

注:INSERT, UPDATE, DELETE, SELECT 语句中不必明确定义游标。

隐式游标属性

属性SELECTINSERTUPDATEDELETE
SQL%ISOPENFALSEFALSEFALSEFALSE
SQL%FOUNDTRUE有结果成功成功
SQL%FOUNDFALSE没结果失败失败
SQL%NOTFUONDTRUE没结果失败失败
SQL%NOTFOUNDFALSE有结果成功失败
SQL%ROWCOUNT返回行数,只为1插入的行数修改的行数删除的行数

4.1.3 关于 NO_DATA_FOUND 和 %NOTFOUND 的区别

SELECT … INTO 语句触发 NO_DATA_FOUND;

当一个显式游标的WHERE子句未找到时触发%NOTFOUND;

当UPDATE或DELETE 语句的WHERE 子句未找到时触发 SQL%NOTFOUND;在提取循环中要用 %NOTFOUND 或%FOUND 来确定循环的退出条件,不要用 NO_DATA_FOUND

4.1.4 使用游标更新和删除数据

游标修改和删除操作是指在游标定位下,修改或删除表中指定的数据行。这时,要求游标查询语句中必须使用FOR UPDATE选项,以便在打开游标时锁定游标结果集合在表中对应数据行的所有列和部分列。

为了对正在处理(查询)的行不被另外的用户改动,ORACLE 提供一个 FOR UPDATE 子句来对所选择的行进行锁住。该需求迫使ORACLE锁定游标结果集合的行,可以防止其他事务处理更新或删除相同的行,直到您的事务处理提交或回退为止。

语法:

SELECT column_list FROM table_list FOR UPDATE [OF column[, column]…] [NOWAIT]

如果另一个会话已对活动集中的行加了锁,那么SELECT FOR UPDATE操作一直等待到其它的会话释放这些锁后才继续自己的操作,对于这种情况,当加上NOWAIT子句时,如果这些行真的被另一个会话锁定,则OPEN立即返回并给出:

ORA-0054 :resource busy and acquire with nowait specified.

如果使用 FOR UPDATE 声明游标,则可在DELETE和UPDATE 语句中使用

WHERE CURRENT OF cursor_name子句,修改或删除游标结果集合当前行对应的数据库表中的数据行。


4.2 游标变量

与游标一样,游标变量也是一个指向多行查询结果集合中当前数据行的指针。但与游标不同的是,游标变量是动态的,而游标是静态的。游标只能与指定的查询相连,即固定指向一个查询的内存处理区域,而游标变量则可与不同的查询语句相连,它可以指向不同查询语句的内存处理区域(但不能同时指向多个内存处理区域,在某一时刻只能与一个查询语句相连),只要这些查询语句的返回类型兼容即可。

4.2.1 声明游标变量

游标变量为一个指针,它属于参照类型,所以在声明游标变量类型之前必须先定义游标变量类型。在PL/SQL中,可以在块、子程序和包的声明区域内定义游标变量类型。

语法格式为:

TYPE ref_type_name IS REF CURSOR [ RETURN return_type];

其中:ref_type_name为新定义的游标变量类型名称;

return_type 为游标变量的返回值类型,它必须为记录变量。

在定义游标变量类型时,可以采用强类型定义和弱类型定义两种。强类型定义必须指定游标变量的返回值类型,而弱类型定义则不说明返回值类型。

声明一个游标变量的两个步骤:

步骤一:定义一个REF CURSOU数据类型,如:

TYPE ref_cursor_type IS REF CURSOR;

步骤二:声明一个该数据类型的游标变量,如:

cv_ref REF_CURSOR_TYPE;

🥇Summary

学期结束,💪

已经很长时间没有更新,但私信一直不断,💪

上述内容就是此次 ORACLE PL/SQL编程总结(一) 的全部内容了,感谢大家的支持,相信在很多方面存在着不足乃至错误,希望可以得到大家的指正。🙇‍(ง •_•)ง

调整自己。不忘来时路,努力前行,找到前进的方向。

2023年第四十期,希望得到大家的喜欢🙇‍

希望大家有好的意见或者建议,欢迎私信,一起加油


以上就是本篇文章的全部内容了

 ~ 关注我,点赞博文~ 每天带你涨知识!

1.看到这里了就 [点赞+好评+收藏] 三连 支持下吧,你的「点赞,好评,收藏」是我创作的动力。

2.关注我 ~ 每天带你学习 :各种前端插件、3D炫酷效果、图片展示、文字效果、以及整站模板 、HTML模板 、C++、数据结构、Python程序设计、Java程序设计、爬虫等! 「在这里有好多 开发者,一起探讨 前端 开发 知识,互相学习」!

3.以上内容技术相关问题可以相互学习,可 关 注 ↓公 Z 号 获取更多源码 !
 

获取源码?私信?关注?点赞?收藏?

👍+✏️+⭐️+🙇‍

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

算法刷题-哈希表-两数之和

两数之和 1. 两数之和思路总结其他语言版本 1. 两数之和 力扣题目链接 给定一个整数数组 nums 和一个目标值 target&#xff0c;请你在该数组中找出和为目标值的那 两个 整数&#xff0c;并返回他们的数组下标。 你可以假设每种输入只会对应一个答案。但是&#xff0c;数组中…

【Leetcode】DP | 买卖股票的最佳时机,DP居然还可以用状态机?

带状态的DP君~ 类型总结&#xff1a;买卖一次、买卖无限次、买卖k次、买卖无限次、含冷冻期。 买卖k次的问题需要不断统计、维护买卖i次的最大收益。 状态较多的题可以借助状态机分析状态转移情况。 121 买卖股票的最佳时机 统计第 i i i天之前的股票最低价格&#xff0c;…

性能测试项目实战:应用加载慢该怎么办?

背景 app收到留学push、课堂、资讯&#xff0c;用户点击push消息&#xff0c;进入app&#xff0c;应用加载很慢&#xff0c;容易出现应用假死、app崩溃或提示网络异常等信息。 给用户体验十分不友好&#xff0c;监控阿里云资源tcp连接数飙高&#xff0c;cpu打满&#xff0c…

Nginx运行原理与基本配置文件讲解

文章目录 Nginx基本运行原理Nginx的基本配置文件serverlocationroot 与 alias 的区别server 和 location 中的 rootnginx欢迎页 本文参考文章Nginx相关文章 Nginx基本运行原理 Nginx的进程是使用经典的「Master-Worker」模型,Nginx在启动后&#xff0c;会有一个master进程和多个…

docker-compose编排容器

系列文章目录 文章目录 系列文章目录一、docker-compose1.Docker Compose2.YAML 文件格式及编写注意事项3.安装docker-compose4.Docker Compose配置常用字段 二、创建compose1.准备依赖文件2. 总结 一、docker-compose 1.Docker Compose 如果需要定义多个容器就需要服务编排。…

priority_queue的模拟实现

前言 优先级队列听名字好像与队列有关&#xff0c;但是实际上&#xff0c;与队列没有很多关系&#xff0c;它也是容器适配器&#xff0c;是通过vector来适配的&#xff0c;但是里面又加入了堆的调整算法。跟栈和队列又有一些不同&#xff0c;了解它的实现对于我们更好的掌握它是…

新手上路,安全驾驶,做行车安全的第一责任人

目录 一、生活与汽车二、树立安全意识三、掌握驾驶经验四、参考材料 道路千万条&#xff0c;安全第一条&#xff0c;行车不规范&#xff0c;亲人两行泪。 ——《流浪地球》 一、生活与汽车 开车是为了节省在路途上花费的时间&#xff0c;片面的追求交通效率会引发交通安全问题&…

day8 栈顶的种类与应用

目录 多寄存器访问指令与寻址方式 多寄存器内存访问指令 多寄存器内存访问指令的寻址方式 ​编辑 栈的种类与使用 栈的概念 栈的分类 栈的应用举例 叶子函数的调用过程举例 多寄存器访问指令与寻址方式 多寄存器内存访问指令 MOV R1, #1 MOV R2, #2 MOV R3, #3 MOV R…

Redis 持久化存储机制:RDB 和 AOF

Redis&#xff08;Remote Dictionary Server&#xff09;是一个高性能的键值存储系统&#xff0c;它可以将数据存储在内存中以实现快速访问。为了保持数据的持久性&#xff0c;Redis 提供了两种数据持久化方法&#xff1a;RDB 和 AOF。 RDB&#xff08;Redis Database&#xff…

spring源码-代码的特殊写法

spring源码-代码的特殊写法 前言 在阅读spring源码中&#xff0c;可能会有很多种代码写法在工作中都没遇见过&#xff0c;阅读起来有一定的难度&#xff0c;在本文中&#xff0c;我会把我认为有难度的代码写法拿出来&#xff0c;并举例子说明清楚&#xff0c;方便大家阅读并理…

股价暴涨59%后,美股二手车平台Carvana在短期内还会进一步上涨?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 Carvana(CVNA)股票在财报发布近一个月后又重新开始出现了上涨。 仅6月9日就上涨了59%。 相对于纳斯达克综合指数的上涨幅度&#xff0c;Carvana今年迄今为止的上涨幅度已经比纳斯达克综合指数高出了约400%。 Carvana最…

RabbitMQ - 死信队列,延时队列

Time-To-Live and Expiration — RabbitMQ 一、死信队列 Dead Letter Exchanges — RabbitMQ 死信队列&#xff1a; DLX 全称&#xff08;Dead-Letter-Exchange&#xff09;,称之为死信交换器&#xff0c;当消息变成一个死信之后&#xff0c;如果这个消息所在的队列存在x-d…

全球、全国遥感土地利用数据产品下载(1m、10m、30m分辨率,内含链接与详细教程)

土地利用/覆被数据能够获取地表覆被信息&#xff0c;同时也是地球系统科学学科的基础数据&#xff08;如生态、水文、地质等&#xff09;吗&#xff0c;目前&#xff0c;基于遥感生成的土地利用/覆被数据产品比较多样&#xff0c;本文整理了目前应用比较多的7种数据产品进行介绍…

Hazel游戏引擎(007)Premake

文中若有代码、术语等错误&#xff0c;欢迎指正 文章目录 前言操作步骤premake写lua脚本文件执行premake.exe文件效果 前言 此节目的 由于之前配置VS项目各项属性需要根据不同平台手动一个一个设置&#xff0c;很麻烦&#xff0c;缺乏灵活性。 用lua脚本配置项目属性&#xff0…

基于Java+SpringBoot的鞋类商品购物商城系统设计与实现

博主介绍&#xff1a;✌擅长Java、微信小程序、Python、Android等&#xff0c;专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;&#x1f3fb; 不然下次找不到哟 Java项目精品实战案…

业务部门的通病:想搞了大而全的软件

业务部门的通病&#xff1a;想搞个大而全的软件 怎么样评价软件功能的价值重要性&#xff1f; 软件的消耗成本是惊人的 中小企业一定要约束需求 做SaaS的香港上市公司有赞&#xff08;做商城软件&#xff09; 10年了还在亏损 趣讲大白话&#xff1a;大而全的功能是陷阱 【趣讲信…

Geek-PC项目 文档

一款后台管理项目 - React-geek-PC 项目介绍 ● 项目功能演示 - 登录、退出 - 首页 - 内容&#xff08;文章&#xff09;管理&#xff1a;文章列表、发布文章、修改文章● 技术 - React 官方脚手架 create-react-app - react hooks - 状态管理&#xff1a;mobx - UI 组件库…

ESP32网络应用 -- ESP32-S3在STA模式下创建TCP-CLIENT应用程序

在ESP32-S3初始化为Station模式并且成功获取IP地址后,说明ESP32-S3芯片的底层设施已经具备Wi-Fi网络通信能力,但在实际的应用场景里面,仅仅建立数据链路层,还是不能够满足应用程序的数据通信需求。 TCP/IP是一种使用广泛的网络传输协议,网络上并不缺乏关于TCP/IP的具体原…

Atcoder Beginner Contest 304——A-D题讲解

蒟蒻来讲题&#xff0c;还望大家喜。若哪有问题&#xff0c;大家尽可提&#xff01; Hello, 大家好哇&#xff01;本初中生蒟蒻讲解一下AtCoder Beginner Contest 304这场比赛的A-D题&#xff01; A - First Player 题目描述 Problem Statement There are N N N people nu…

sequence2sequence

1. 基本模型 所谓的Seq2seq模型从字面上理解很简单&#xff0c;就是由一个序列到另一个序列的过程(比如翻译、语音等方面的应用)&#xff1a; 那么既然是序列模型&#xff0c;就需要搭建一个RNN模型(神经单元可以是GRU模型或者是LSTM模型) 下面两篇文章提出了这样的seq2seq的模…