MySQL-15.存儲過程和函數

来源:https://www.cnblogs.com/changming06/p/18026363
-Advertisement-
Play Games

C-15.存儲過程和函數 MySQL從5.0版本開始支持存儲過程和函數。存儲過程和函數能夠將複雜的SQL邏輯封裝在一起,應用程式無須關註存儲過程和函數內部複雜的SQL邏輯,而只需要簡單地調用存儲過程和函數即可。 1.存儲過程概述 1.1 理解 含義:存儲過程的英文是Stored Procedure。 ...


C-15.存儲過程和函數

MySQL從5.0版本開始支持存儲過程和函數。存儲過程和函數能夠將複雜的SQL邏輯封裝在一起,應用程式無須關註存儲過程和函數內部複雜的SQL邏輯,而只需要簡單地調用存儲過程和函數即可。

1.存儲過程概述

1.1 理解

含義:存儲過程的英文是Stored Procedure。它的思想很簡單,就是一組經過預先編譯的SQL語句的封裝。

執行過程:存儲過程預先存儲在MySQL伺服器上,需要執行的時候,客戶端只需要向伺服器端發出調用存儲過程的命令,伺服器端就可以把預先存儲好的這一系列SQL語句全部執行。

好處

1.簡化操作,提高了sql語句的重用性,減少了開發程式員的壓里。

2.減少操作過程中的失誤,提高效率。

3.減少網路傳輸量(客戶端不需要把所有的SQL語句通過網路發給伺服器)。

4.減少了SQL語句暴露在網上的風險,也提高了數據查詢的安全性。

和視圖,函數的對比

它和視圖有著同樣的優點,清晰,安全,還可以減少網路傳輸量。不過它和視圖不同,視圖是虛擬表,通常不對底層數據表直接操作,而存儲過程是程式化的SQL,可以直接操作底層數據表,相比於面向集合的操作方式,能夠實現一些更複雜的數據處理。

一旦存儲過程被創建出來,使用它就像使用函數一樣簡單,我們直接通過調用存儲過程名即可。相較於函數,存儲過程是沒有返回值的。

1.2 分類

存儲過程的參數類型可以是IN、OUT和INOUT。根據這點分類如下:

  • 1、沒有參數(無參數無返回)

  • 2、僅僅帶 IN 類型(有參數無返回)

  • 3、僅僅帶 OUT 類型(無參數有返回)

  • 4、既帶 IN 又帶 OUT(有參數有返回)

  • 5、帶 INOUT(有參數有返回)

註意:IN、OUT、INOUT 都可以在一個存儲過程中帶多個。

2.創建存儲過程

2.1 語法分析

語法

DELIMITER //

CREATE PROCEDURE 存儲過程名(IN|OUT|INOUT 參數名 參數類型,...)

[characteristics ...]
BEGIN 
	存儲過程體
END //

DELIMITER ;

類型Java中的方法

// 修飾符 返回值 方法名(參數類型 參數名,...) 
public static void main(String[] args){
    //方法體;
}

說明:

1、參數前面的符號的意思

  • IN:當前參數為輸入參數,也就是表示入參。存儲過程只是讀取這個參數的值。如果沒有定義參數種類,預設就是IN,表示輸入參數。
  • OUT:當前參數為輸出參數,也就是表示出參。執行完成之後,調用這個存儲過程的客戶端或者應用程式可以讀取這個參數的返回值。
  • INOUT:當前參數既可以是輸入參數,也可以是輸出參數。

2、形參類型可以是MySQL資料庫中的任意類型

2.1.1 存儲過程和函數約束類型

3、characteristrics表示創建存儲過程時指定的對存儲過程的約束條件,其取值信息如下:

LANGUAGE SQL
# DETERMINISTIC a.確定性的
| [NOT] DETERMINISTIC
# CONTAINS 包含 MODIFIES 修改
| { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
# DEFINER 定義者 INVOKER 調用者
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT '註釋'
  • LANGUAGE SQL :說明存儲過程體是由SQL語句組成的,當前系統支持的語言為SQL。

  • [NOT] DETERMINISTIC:指明存儲過程執行的結果是否確定。DETERMINISTIC表示結果就是確定的。每次執行存儲過程時,相同的輸入會得到相同的輸出。NOT DETERMINISTIC 表示結果時不確定的,相同的輸入可能得到不同的輸出。如果沒有指定任意一個值,預設為NOT DETERMINISTIC。

  • { CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }:指明子程式使用SQL語句的限制。

    • CONTAINS SQL表示當前存儲過程的子程式包含SQL語句,但不包含讀寫數據的SQL語句;

    • NO SQL表示當前存儲過程的子查詢中不包含任何SQL語句;

    • READS SQL DATA表示當前存儲過程的子查詢中包含讀數據的SQL語句;

    • MODIFIES SQL DATA表示當前存儲過程的子查詢中包含寫數據的SQL語句;

    • 預設情況下,系統會制定為CONTAINS SQL。

  • SQL SECURITY { DEFINER | INVOKER }:調用當前存儲過程的許可權,即指明那些用戶能夠執行當前存儲過程。

    • DEFINER表示只有當前存儲過程的創建者或定義者才能執行當前存儲過程。

    • INVOKER表示擁有當前存儲過程的訪問許可權的用戶能夠執行當前存儲過程。

    • 預設情況下,MySQL預設指定值為DEFINER。

  • COMMENT '註釋':註釋信息,可以用來描述存儲過程。

4、存儲過程體中可以由多條SQL語句,如果僅僅一條SQL語句,則可以省略BEGIN 和END。

編寫存儲過程並不是一件簡單的事情,可能存儲過程中需要複雜的 SQL 語句。

1. BEGIN…END:BEGIN…END 中間包含了多個語句,每個語句都以(;)號為結束符。
2. DECLARE:DECLARE 用來聲明變數,使用的位置在於 BEGIN…END 語句中間,而且需要在其他語句使用之前進行變數的聲明。
3. SET:賦值語句,用於對變數進行賦值。
4. SELECT… INTO:把從數據表中查詢的結果存放到變數中,也就是為變數賦值。

5、需要設置新的結束標記

DELIMITER 新的結束標記

因為MySQL預設的語句結束符號為分號';'。為了避免與存儲過程中SQL語句結束符相衝突,需要使用DELIMITER改變存儲過程的結束符。

比如:“DELIMITER //”語句的作用是將MySQL的結束符設置為//,並以“END //”結束存儲過程。存儲過程定義完畢之後再使用“DELIMITER ;”恢復預設結束符。DELIMITER也可以指定其他符號作為結束符。

註意:當使用DELIMITER命令時,應該避免使用反斜杠(‘\’)字元,因為反斜線是MySQL的轉義字元。

實例:

DELIMITER $

CREATE PROCEDURE 存儲過程名(IN|OUT|INOUT 參數名 參數類型,...)
[characteristics ...]
BEGIN

    sql語句1;
    sql語句2;

END $

DELIMITER ;

2.2 舉例

#無參類型
#舉例1:創建存儲過程select_all_data(),查看 emps 表的所有數據
DELIMITER $

CREATE PROCEDURE select_all_date()
BEGIN 
    SELECT * FROM emps;
END $

DELIMITER ;

-- 存儲過程的調用
CALL select_all_date();

#無參類型
#舉例2:創建存儲過程avg_employee_salary(),返回所有員工的平均工資
DELIMITER $

CREATE PROCEDURE avg_emps_salary()
BEGIN
    SELECT AVG(salary) FROM emps;
END $

DELIMITER ;

CALL avg_emps_salary();

#無參類型
#舉例3:創建存儲過程show_max_salary(),用來查看“emps”表的最高薪資值。
DELIMITER //

CREATE PROCEDURE show_max_salary()
BEGIN
    SELECT MAX(salary) FROM emps;
END //

DELIMITER ;

CALL show_max_salary();

#OUT類型
#舉例4:創建存儲過程show_min_salary(),查看“emps”表的最低薪資值。並將最低薪資通過OUT參數“ms”輸出
DELIMITER $

CREATE PROCEDURE show_min_salary(OUT ms DOUBLE)
BEGIN 
    SELECT MIN(salary) INTO ms
    FROM emps;
END $

DELIMITER ;

-- 有輸出參數的存儲過程調用
CALL show_min_salary(@ms);
SELECT @ms;

#IN類型
#舉例5:創建存儲過程show_someone_salary(),查看“emps”表的某個員工的薪資,並用IN參數empname輸入員工姓名。
DELIMITER $

CREATE PROCEDURE show_someone_salary(IN empname VARCHAR(20))
BEGIN
    SELECT salary FROM emps WHERE last_name = empname;
END $

DELIMITER ;

-- 輸入參數的存儲過程調用
-- 方式1
CALL show_someone_salary('Abel');
-- 方式2
-- 這種方式,需要變數和使用變數的sql語句一起執行
SET @empname = 'Abel';
CALL show_someone_salary(@empname);

# 有IN,有OUT類型
#舉例6:創建存儲過程show_someone_salary2(),查看“emps”表的某個員工的薪資,並用IN參數empname
#輸入員工姓名,用OUT參數empsalary輸出員工薪資。
DELIMITER $

CREATE PROCEDURE show_someone_salary2(IN empname VARCHAR(20), OUT empsalary DOUBLE)
BEGIN 
    SELECT salary INTO empsalary FROM emps WHERE last_name = empname;
END $

DELIMITER ;

-- 調用方式
CALL show_someone_salary2('Abel',@empsalary);
SELECT @empsalary;

#INOUT類型
#舉例7:創建存儲過程show_mgr_name(),查詢某個員工領導的姓名,並用INOUT參數“empname”輸入員工姓名,輸出領導的姓名。
DELIMITER $

CREATE PROCEDURE show_mgr_name(INOUT empname VARCHAR(20))
BEGIN 
    SELECT m.last_name INTO empname 
    FROM emps w,emps m 
    WHERE w.manager_id = m.employee_id 
    AND w.last_name = empname;
END $

DELIMITER ;

-- inout類型參數的存儲過程的調用方式
SET @empname = 'Hunold';
CALL show_mgr_name(@empname);
SELECT @empname;

3.調用存儲過程

3.1 調用格式

存儲過程有多種調用方法。存儲過程必須使用CALL語句調用,並且存儲過程和資料庫相關,如果要執行其他資料庫中的存儲過程,需要指定資料庫名稱,例如CALL dbname.procname。

CALL 存儲過程名(實參列表);

格式:

1.調用IN模式

call sq1('值');

2.調用OUT模式

SET @name;#聲明空變數可以省略,MySQL系統會自動創建,並根據存儲過程結果(結果,不是返回值)賦值給變數
CALL sp1(@name);
SELECT @name;

3.調用INOUT模式

SET @name=值;
CALL sp1(@name);
SELECT @name;

3.2 舉例

INT類型:創建存儲過程,實現累加運算,計算 1+2+…+n 等於多少。具體的代碼如下:

DELIMITER //

CREATE PROCEDURE `add_num`(IN n INT)

BEGIN
    DECLARE i INT;
    DECLARE sum INT;
    
    SET i = 1; 
    SET sum = 0;
    
    WHILE i <= n DO
        SET sum = sum + i;
        SET i = i +1;
    END WHILE;
    
    SELECT sum;
END //

DELIMITER ;

如果你用的是 Navicat 工具,那麼在編寫存儲過程的時候,Navicat 會自動設置 DELIMITER 為其他符號,我們不需要再進行 DELIMITER 的操作。

直接使用 CALL add_num(50); 即可。這裡我傳入的參數為 50,也就是統計 1+2+…+50 的積累之和。

其他類型見上 2.2 舉例。

3.3 如何調試

在 MySQL 中,存儲過程不像普通的編程語言(比如 VC++、Java 等)那樣有專門的集成開發環境。因此,你可以通過 SELECT 語句,把程式執行的中間結果查詢出來,來調試一個 SQL 語句的正確性。調試成功之後,把 SELECT 語句後移到下一個 SQL 語句之後,再調試下一個 SQL 語句。這樣 逐步推進 ,就可以完成對存儲過程中所有操作的調試了。當然,你也可以把存儲過程中的 SQL 語句複製出來,逐段單獨調試。存儲過程動輒成百上千行,不好調試。

4.存儲函數的使用

前面學習了很多函數,使用這些函數可以對數據進行的各種處理操作,極大地提高用戶對資料庫的管理效率。MySQL支持自定義函數,定義好之後,調用方式與調用MySQL預定義的系統函數一樣。

4.1 語法分析

學過的函數:LENGTH、SUBSTR、CONCAT等

語法格式:

CREATE FUNCTION 函數名(參數名 參數類型,...)
RETURNS 返回值類型
[characteristics ...]
BEGIN 
	函數體 #函數體中一定有return語句
END

說明:

1、參數列表:指定參數為IN、OUT或INOUT只對PROCEDURE是合法的,FUNCTION中總是預設為IN參數。

2、RETURNS type 語句表示函數返回數據的類型;RETURNS子句只能對FUNCTION做指定,對函數而言這是強制的。它用來指定函數的返回類型,而且函數體必須包含一個RETURN value語句。

3、characteristic 創建函數時指定的對函數的約束。取值與創建存儲過程時相同,這裡不再贅述。

4、函數體也可以用BEGIN…END來表示SQL代碼的開始和結束。如果函數體只有一條語句,也可以省略BEGIN…END。

4.2 調用存儲函數

在MySQL中,存儲函數的使用方法與MySQL內部函數的使用方法是一樣的。換言之,用戶自己定義的存儲函數與MySQL內部函數是一個性質的。區別在於,存儲函數是用戶自己定義的,而內部函數是MySQL的開發者定義的。

SELECT 函數名(實參列表)

4.3 舉例

-- 舉例1,創建存儲函數,名稱為email_by_name(),參數定義為空
-- 該函數查詢Abel的email,並返回,數據類型為字元串型
DELIMITER //

CREATE FUNCTION email_by_name()
RETURNS VARCHAR(25)
    DETERMINISTIC
    CONTAINS SQL
    READS SQL DATA
BEGIN
    RETURN(SELECT email FROM emps WHERE last_name = 'Abel');
END //

DELIMITER ;
-- 調用
SELECT email_by_name();

-- 舉例2 創建存儲函數,名稱為email_by_id(),參數傳入emp_id,該函數
-- 查詢emp_id的email,並返回,數據類型為字元串類型
DELIMITER //

CREATE FUNCTION email_by_id(empId INT)
RETURNS VARCHAR(25)
    DETERMINISTIC
    CONTAINS SQL
    READS SQL DATA
BEGIN
    RETURN(SELECT email FROM emps WHERE employee_id = empId);
END //

DELIMITER ;

SELECT email_by_id(101);

SET @emp_id = 102;
SELECT email_by_id(@emp_id);

# 舉例3,創建存儲函數count_by_id(),參數傳入dept_id,該函數查詢dept_id部門的
# 員工人數,並返回,數據類型為整形
DELIMITER //

CREATE FUNCTION count_by_id(dept_id INT)
RETURNS INT
    DETERMINISTIC
    CONTAINS SQL
    READS SQL DATA
BEGIN   
    RETURN(SELECT COUNT(*) FROM emps WHERE department_id = dept_id);
END //

DELIMITER ;

-- 常量調用存儲函數
SELECT count_by_id(30);

-- 變數調用存儲函數
SET @dept_id = 30;
SELECT count_by_id(@dept_id);

註意:

若在創建存儲函數中報錯you might want to use the less safelog_bin_trust_function_creators variable,有兩種處理方法

  • 方式1,加上必要的函數特性“[NOT] DETERMINISTIC”和“{CONTAINS SQL | NO SQL | READS SQL DATA |MODIFIES SQL DATA}”

  • 方式2:

mysql> SET GLOBAL log_bin_trust_function_creators = 1;

方式2說明,log_bin_trust_function_creators = 0時,對於用戶在創建存儲函數時, MySQL系統,會進行檢查,存儲函數的創建語句。= 1,後MySQL不會進行檢查。

4.4 存儲函數和過程對比

關鍵字 調用語法 返回值 應用場景
存儲過程 PROCEDURE call name() 理解為有0個或多個 一般用於更新
存儲函數 FUNCTION select name() 只能是一個 一般用於查詢結果為一個值時

此外,存儲函數可以放在查詢語句中使用,存儲過程不行。反之,存儲過程的功能更加強大,包括能夠執行對錶的操作(比如創建表,刪除表等)和事務操作,這些功能是存儲函數不具備的。

5.存儲過程和函數的查看,修改,刪除

5.1 查看

創建完之後,怎麼知道我們創建的存儲過程、存儲函數是否成功了呢?

MySQL存儲了存儲過程和函數的狀態信息,用戶可以使用SHOW STATUS語句或SHOW CREATE語句來查看,也可直接從系統的information_schema資料庫中查詢。這裡介紹3種方法。

1.使用SHOW CREATE語句查看存儲過程和函數的創建信息

語法:

SHOW CREATE {PROCEDURE | FUNCTION} 存儲過程名或函數名

舉例

#(1).使用show create 查看存儲過程或函數
SHOW CREATE PROCEDURE show_mgr_name;

SHOW CREATE FUNCTION count_by_id;

2.使用SHOW STATUS語句查看存儲過程和函數的狀態信息

語法

SHOW {PROCEDURE | FUNCTION} STATUS [LIKE 'pattern']

這個語句返回子程式的特征,如資料庫、名字、類型、創建者及創建和修改日期。

[LIKE 'pattern']:匹配存儲過程或函數的名稱,可以省略。當省略不寫時,會列出MySQL資料庫中存在的所有存儲過程或函數的信息。 舉例:SHOW STATUS語句示例,代碼如下:

mysql> SHOW PROCEDURE STATUS LIKE 'show_min_salary'\G
*************************** 1. row ***************************
                  Db: test15
                Name: show_min_salary
                Type: PROCEDURE
             Definer: root@localhost
            Modified: 2024-02-21 17:02:17
             Created: 2024-02-21 17:02:17
       Security_type: DEFINER
             Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.01 sec)

mysql> SHOW FUNCTION STATUS LIKE 'count_by_id'\G
*************************** 1. row ***************************
                  Db: test15
                Name: count_by_id
                Type: FUNCTION
             Definer: root@localhost
            Modified: 2024-02-20 20:40:00
             Created: 2024-02-20 20:40:00
       Security_type: DEFINER
             Comment:
character_set_client: utf8
collation_connection: utf8_general_ci
  Database Collation: utf8mb4_0900_ai_ci
1 row in set (0.00 sec)

3. 從information_schema.Routines表中查看存儲過程和函數的信息

MySQL中存儲過程和函數的信息存儲在information_schema資料庫下的Routines表中。可以通過查詢該表的記錄來查詢存儲過程和函數的信息。其基本語法形式如下:

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='存儲過程或函數的名' [AND ROUTINE_TYPE = {'PROCEDURE|FUNCTION'}];

說明:如果在MySQL資料庫中存在存儲過程和函數名稱相同的情況,最好指定ROUTINE_TYPE查詢條件來指明查詢的是存儲過程還是函數。

舉例

-- (3).從information_schema.Routines表中查看存儲過程和函數的信息
SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='count_by_id' AND ROUTINE_TYPE = 'FUNCTION';

SELECT * FROM information_schema.Routines
WHERE ROUTINE_NAME='show_mgr_name' AND ROUTINE_TYPE = 'PROCEDURE';

5.2 修改

修改存儲過程或函數,不影響存儲過程或函數功能,只是修改相關特性。使用ALTER語句實現。

ALTER {PROCEDURE | FUNCTION} 存儲過程或函數的名 [characteristic ...]

其中,characteristic指定存儲過程或函數的特性,其取值信息與創建存儲過程、函數時的取值信息略有不同。

{ CONTAINS SQL | NO SQL | READS SQL DATA | MODIFIES SQL DATA }
| SQL SECURITY { DEFINER | INVOKER }
| COMMENT 'string'
  • CONTAINS SQL ,表示子程式包含SQL語句,但不包含讀或寫數據的語句。

  • NO SQL ,表示子程式中不包含SQL語句。

  • READS SQL DATA ,表示子程式中包含讀數據的語句。

  • MODIFIES SQL DATA ,表示子程式中包含寫數據的語句。

  • SQL SECURITY { DEFINER | INVOKER } ,指明誰有許可權來執行。

    • DEFINER ,表示只有定義者自己才能夠執行。

    • INVOKER ,表示調用者可以執行。

  • COMMENT 'string' ,表示註釋信息。

修改存儲過程使用ALTER PROCEDURE語句,修改存儲函數使用ALTER FUNCTION語句。但是,這兩個語句的結構是一樣的,語句中的所有參數也是一樣的。

註意,修改存儲過程或函數時,與創建存儲過程或函數時的約束少了,LANGUAGE SQL[NOT] DETERMINISTIC約束。

舉例

#(4).使用alter修改存儲過程或函數的特性,不能修改存儲過程或存儲函數體
ALTER PROCEDURE show_max_salary
    SQL SECURITY INVOKER
    COMMENT '查看薪水最大值';
-- 修改存儲函數略
ALTER FUNCTION count_by_id
    SQL SECURITY INVOKER
    COMMENT '根據id數量';

5.3 刪除

刪除存儲過程和函數,可以使用DROP語句,其語法結構如下:

DROP {PROCEDURE | FUNCTION} [IF EXISTS] 存儲過程或函數的名

IF EXISTS:如果程式或函數不存儲,它可以防止發生錯誤,產生一個用SHOW WARNINGS查看的警告。

舉例

#(5).刪除存儲函數或存儲過程
DROP PROCEDURE show_min_salary;

DROP FUNCTION email_by_name;

6. 關於存儲過程使用的爭議

儘管存儲過程有諸多優點,但是對於存儲過程的使用,一直都存在著很多爭議,比如有些公司對於大型項目要求使用存儲過程,而有些公司在手冊中明確禁止使用存儲過程,為什麼這些公司對存儲過程的使用需求差別這麼大呢?

6.1 優點

1、存儲過程可以一次編譯多次使用。存儲過程只在創建時進行編譯,之後的使用都不需要重新編譯,這就提升了 SQL 的執行效率。

2、可以減少開發工作量。將代碼封裝成模塊,實際上是編程的核心思想之一,這樣可以把複雜的問題拆解成不同的模塊,然後模塊之間可以重覆使用,在減少開發工作量的同時,還能保證代碼的結構清晰。

3、存儲過程的安全性強。我們在設定存儲過程的時候可以設置對用戶的使用許可權,這樣就和視圖一樣具有較強的安全性。

4、可以減少網路傳輸量。因為代碼封裝到存儲過程中,每次使用只需要調用存儲過程即可,這樣就減少了網路傳輸量。

5、良好的封裝性。在進行相對複雜的資料庫操作時,原本需要使用一條一條的 SQL 語句,可能要連接多次資料庫才能完成的操作,現在變成了一次存儲過程,只需要連接一次即可

6.2 缺點

基於上面這些優點,不少大公司都要求大型項目使用存儲過程,比如微軟、IBM 等公司。但是國內的阿裡並不推薦開發人員使用存儲過程,這是為什麼呢?


阿裡開發規範

【強制】禁止使用存儲過程,存儲過程難以調試和擴展,更沒有移植性。


存儲過程雖然有諸如上面的好處,但缺點也是很明顯的。

1、可移植性差。存儲過程不能跨資料庫移植,比如在 MySQL、Oracle 和 SQL Server 里編寫的存儲過程,在換成其他資料庫時都需要重新編寫。

2、調試困難。只有少數 DBMS 支持存儲過程的調試。對於複雜的存儲過程來說,開發和維護都不容易。雖然也有一些第三方工具可以對存儲過程進行調試,但要收費。

3、存儲過程的版本管理很困難。比如數據表索引發生變化了,可能會導致存儲過程失效。我們在開發軟體的時候往往需要進行版本管理,但是存儲過程本身沒有版本控制,版本迭代更新的時候很麻煩。

4、它不適合高併發的場景。高併發的場景需要減少資料庫的壓力,有時資料庫會採用分庫分表的方式,而且對可擴展性要求很高,在這種情況下,存儲過程會變得難以維護, 增加資料庫的壓力 ,顯然就不適用了。

6.3 小結

存儲過程既方便,又有局限性。儘管不同的公司對存儲過程的態度不一,但是對於我們開發人員來說,不論怎樣,掌握存儲過程都是必備的技能之一。

只是為了記錄自己的學習歷程,且本人水平有限,不對之處,請指正。


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 近期,Apache DolphinScheduler 社區激動地宣佈 3.2.1 版本的發佈。此次更新不僅著力解決了前一版本(3.2.0)中遺留的問題,而且引入了一系列的功能增強和優化措施。 原先的問題主要源於部分重要代碼在發佈過程中未能成功合併(cherry-pick),加之這部分代碼的合併過程較 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 一、什麼是SPA SPA(single-page application),翻譯過來就是單頁應用SPA是一種網路應用程式或網站的模型,它通過動態重寫當前頁面來與用戶交互,這種方法避免了頁面之間切換打斷用戶體驗在單頁應用中,所有必要的代碼( ...
  • 訂單履約系統用來管理從接到銷售訂單,到把貨品送到客戶手中的整個業務過程。它是上游交易(如銷售和客戶下單環節)和下游倉儲配送(如庫存管理、物流)之間的橋梁,確保信息流的順暢和操作的協同,提升整個供應鏈的效率和響應速度。 ...
  • 概括 這是一道PHP反序列化的CTF賽題,本意是想用這道題對PHP反序列化進行一定的學習。 過程 我們打開賽題,看看內容 沒有發現什麼東西,看看他的頁面代碼 根據他的提示,感覺是存在一個robots.txt文件的,嘗試訪問一下。 進去看看。 果然如此 我們來分析一下這段代碼 <?php error_ ...
  • 我們在《SqlSugar開發框架》中,有時候都會根據一些需要引入一些設計模式,主要的目的是為瞭解決問題提供便利和代碼重用等目的。而不是為用而用,我們的目的是解決問題,併在一定的場景下以水到渠成的方式處理。不過引入任何的設計模式,都會增加一定的學習難度,除非是自己本身領會比較好了,就會顯得輕鬆一些。本... ...
  • 一、OpenAL的原理和基本概念: 1.1 OpenAL的架構 OpenAL的架構同樣基於三個核心組件:Context(上下文)、Source(聲源)和Buffer(緩衝區)。Context代表了音頻處理的環境,Source是具體的音頻播放源,而Buffer則用於存儲音頻數據。 1.2 音頻渲染流程 ...
  • Admin3 —— 一個輕巧的後臺管理框架,項目後端基於 Java17、SpringBoot3.0,前端基於 TypeScript、Vite3、Vue3、Element Plus,提供登錄會話、用戶管理、角色管理、許可權資源管理、事件日誌、對象存儲等基礎功能。 ...
  • MQTT 概述 MQTT是基於TCP/IP協議棧構建的非同步通信消息協議,是一種輕量級的發佈、訂閱信息傳輸協議。 可以在不可靠的網路環境中進行擴展,適用於設備硬體存儲空間或網路帶寬有限的場景。 使用MQTT協議,消息發送者與接收者不受時間和空間的限制。 Docker 部署 MQTT(採用docker- ...
一周排行
    -Advertisement-
    Play Games
  • 下麵是一個標準的IDistributedCache用例: public class SomeService(IDistributedCache cache) { public async Task<SomeInformation> GetSomeInformationAsync (string na ...
  • 這個庫提供了在啟動期間實例化已註冊的單例,而不是在首次使用它時實例化。 單例通常在首次使用時創建,這可能會導致響應傳入請求的延遲高於平時。在註冊時創建實例有助於防止第一次Request請求的SLA 以往我們要在註冊的時候實例單例可能會這樣寫: //註冊: services.AddSingleton< ...
  • 最近公司的很多項目都要改單點登錄了,不過大部分都還沒敲定,目前立刻要做的就只有一個比較老的項目 先改一個試試手,主要目標就是最短最快實現功能 首先因為要保留原登錄方式,所以頁面上的改動就是在原來登錄頁面下加一個SSO登錄入口 用超鏈接寫的入口,頁面改造後如下圖: 其中超鏈接的 href="Staff ...
  • Like運算符很好用,特別是它所提供的其中*、?這兩種通配符,在Windows文件系統和各類項目中運用非常廣泛。 但Like運算符僅在VB中支持,在C#中,如何實現呢? 以下是關於LikeString的四種實現方式,其中第四種為Regex正則表達式實現,且在.NET Standard 2.0及以上平... ...
  • 一:背景 1. 講故事 前些天有位朋友找到我,說他們的程式記憶體會偶發性暴漲,自己分析了下是非托管記憶體問題,讓我幫忙看下怎麼回事?哈哈,看到這個dump我還是非常有興趣的,居然還有這種游戲幣自助機類型的程式,下次去大玩家看看他們出幣的機器後端是不是C#寫的?由於dump是linux上的程式,剛好win ...
  • 前言 大家好,我是老馬。很高興遇到你。 我們為 java 開發者實現了 java 版本的 nginx https://github.com/houbb/nginx4j 如果你想知道 servlet 如何處理的,可以參考我的另一個項目: 手寫從零實現簡易版 tomcat minicat 手寫 ngin ...
  • 上一次的介紹,主要圍繞如何統一去捕獲異常,以及為每一種異常添加自己的Mapper實現,並且我們知道,當在ExceptionMapper中返回非200的Response,不支持application/json的響應類型,而是寫死的text/plain類型。 Filter為二方包異常手動捕獲 參考:ht ...
  • 大家好,我是R哥。 今天分享一個爽飛了的面試輔導 case: 這個杭州兄弟空窗期 1 個月+,面試了 6 家公司 0 Offer,不知道問題出在哪,難道是杭州的 IT 崩盤了麽? 報名面試輔導後,經過一個多月的輔導打磨,現在成功入職某上市公司,漲薪 30%+,955 工作制,不咋加班,還不捲。 其他 ...
  • 引入依賴 <!--Freemarker wls--> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.30</version> </dependency> ...
  • 你應如何運行程式 互動式命令模式 開始一個互動式會話 一般是在操作系統命令行下輸入python,且不帶任何參數 系統路徑 如果沒有設置系統的PATH環境變數來包括Python的安裝路徑,可能需要機器上Python可執行文件的完整路徑來代替python 運行的位置:代碼位置 不要輸入的內容:提示符和註 ...