.Net程式員學用Oracle系列(28):PLSQL 之SQL分類和動態SQL

来源:http://www.cnblogs.com/hanzongze/archive/2017/05/22/Oracle-plsql-3.html
-Advertisement-
Play Games

" 1、SQL 語句分類 " "1.1、分類方法及類型" "1.2、數據定義語言" "1.3、數據操縱語言" "1.4、其它語句" " 2、動態 SQL 理論 " "2.1、動態 SQL 的用途" "2.2、動態 SQL 的語法" "2.3、綁定變數" " 3、動態 SQL 實戰 " "3.1、封裝 ...


1、SQL 語句分類

1.1、分類方法及類型

在 Oracle 的官方手冊《Oracle Database SQL Reference: Types of SQL Statements》中將 SQL 語句分為 6 類,分別是:數據定義語言語句、數據操縱語言語句、事務控制語句、會話控制語句、系統控制語句、嵌入式 SQL 語句。

按照官方的分類方法,數據定義語言的語句是非常豐富的。本人曾在一些非官方資料中看到有人把數據定義語言做了進一步的細分。例如,把 GRANT 和 REVOKE 稱之為數據控制語言,即 DCL(Data Control Language);把 AUDIT、NOAUDIT 稱之為審計控制語言。

1.2、數據定義語言

數據定義語言(DDL,Data Definition Language)語句主要有以下用途:

  • 1、創建、修改和刪除模式對象。
  • 2、授予或回收用戶許可權或角色。
  • 3、分析表、索引或集群的信息。
  • 4、打開或關閉審計選項。
  • 5、向數據字典中添加註釋。

DDL 語句主要有:

  • CREATE,所有以 CREATE 開頭的語句都是。
  • ALTER,所有以 ALTER 開頭的語句都是。
  • DROP,所有以 DROP 開頭的語句都是。
  • FLASHBACK,所有以 FLASHBACK 開頭的語句都是。
  • TRUNCATE
  • COMMENT
  • RENAME
  • PURGE
  • GRANT
  • REVOKE
  • AUDIT
  • NOAUDIT
  • ANALYZE
  • ASSOCIATE STATISTICS
  • DISASSOCIATE STATISTICS

CREATE、ALTER 及 DROP 命令需要對指定對象的獨占訪問。例如,如果某個用戶在指定的表上具有打開的事務,則其它用戶發出的 ALTER TABLE 語句將失敗。

GRANT、REVOKE、ANALYZE、AUDIT 及 COMMENT 命令不需要對指定對象的獨占訪問。例如,你可以在其他用戶更新表時分析表。

Oracle 資料庫在每個 DDL 語句之前和之後都會隱式地提交當前事務。有些 DDL 語句可能會導致 Oracle 資料庫重新編譯或重新授權模式對象,如更改對象定義的語句。

1.3、數據操縱語言

數據操作語言(DML,Data Manipulation Language)語句用於訪問或操縱現有模式對象中的數據。這些語句不會隱式的提交當前事務。數據操作語言語句主要有:

  • INSERT
  • DELETE
  • UPDATE
  • SELECT
  • MERGE
  • LOCK TABLE
  • EXPLAIN PLAN
  • CALL

SELECT 語句只能訪問資料庫中的數據,但不能處理資料庫中的數據,儘管它可以在返回查詢結果之前對訪問的數據進行操作。

只有在動態執行時,PL/SQL 才支持 CALL 和 EXPLAIN PLAN 語句。PL/SQL 中完全支持所有其它 DML 語句。

1.4、其它語句

事務控制語句:事務控制語句用於管理 DML 語句所做的更改。事務控制語句主要有:COMMIT、ROLLBACK、SAVEPOINT、SET TRANSACTION 共 4 個。

會話控制語句:會話控制語句用於動態管理用戶會話的屬性。會話控制語句是 ALTER SESSION 和 SET ROLE,這些語句不會隱式提交當前事務。PL/SQL 不支持會話控制語句。

系統控制語句:單一系統控制語句 ALTER SYSTEM 動態管理 Oracle 資料庫實例的屬性。 此語句不會隱式提交當前事務,並且在 PL/SQL 中不受支持。

嵌入式 SQL 語句:嵌入式 SQL 語句將 DDL、DML 和事務控制語句嵌入到 SQL 程式中,個人感覺這個概念挺模糊的。嵌入式 SQL 語句由 Oracle 預編譯器支持。

2、動態 SQL 理論

在 PL/SQL 程式塊中的 SQL 分為兩種:靜態 SQL 和動態 SQL。靜態 SQL 是早期綁定(early binding)的,是指 SQL 語句在編譯時是明確的,執行的是確定對象,大多數的編譯情況屬於這種類型。動態 SQL 是後期綁定(late binding)的,是指 SQL 語句在編譯時是不確定的,編譯程式對動態語句部分不進行處理,只是在程式運行時動態地創建語句、對語句進行語法分析並執行該語句。

2.1、動態 SQL 的用途

1、執行 DDL、DCL 語句:在 PL/SQL 程式中執行 DDL 語句、DCL 語句和會話控制語句必須使用動態 SQL 語句。因為這幾類語句都不能在 PL/SQL 程式中直接運行的。

2、構造通用 SQL 處理:為了開發靈活和通用的程式,往往需要利用數據字典來生成相關的腳本。由於動態 SQL 特有的靈活性,我們很容易按照某種共性去構造通用和重用功能的代碼,例如基於某個表的動態欄位查詢。

3、執行複雜業務邏輯查詢:動態 SQL 語句的另外一個重要應用場景是複雜業務邏輯查詢和報表開發環境。在這兩種情況下,查詢參數是由用戶的輸入開關和輸入項而定,甚至查詢出的欄位也根據查詢參數有所不同,不用動態 SQL 很難實現。

儘管動態 SQL 如此靈活和強大,但凡事總有利弊。首先,動態 SQL 語句無法在編譯前期檢查 SQL 是否正確,必須等到運行期才會發現問題;其次,靜態 SQL 是一次解析,多次執行,雖然動態 SQL 也可以使用綁定變數的方式,但也可能會帶來一些意想不到的性能問題。例如,綁定變數在 SQL 要訪問的表存在數據傾斜時會提供錯誤的執行計劃;最後,動態 SQL 語句可讀性較差,不易維護。

除非是上述三類情況,否則不應該使用動態 SQL 語句。我曾接手過一個大量使用動態 SQL 語句的資料庫,可以看的出來,這些存儲過程是從網上或其它庫中拷貝過來的,而且那些動態 SQL 語句大多也不夠靈活和通用,又長期沒怎麼維護,很多一調用就報錯,基於這個資料庫的項目的可維護性可想而知!

2.2、動態 SQL 的語法

理論說了這麼多,那到底何為動態 SQL 語句呢?簡單的說就是存儲在字元串變數中的 SQL 命令。如下例中的v_sql即為動態 SQL 語句:

DECLARE
  v_sql VARCHAR2(200):='SELECT t.course_name, t.course_desc FROM demo.t_course t';

早期 Oracle 提供了DBMS_SQL包來執行動態 SQL 語句,後來又提供了本地動態 SQL(Native Dynamic SQL),用來代替DBMS_SQL執行動態 SQL 語句。使用本地動態 SQL 比使用DBMS_SQL更簡單,且大部分情況比DBMS_SQL更高效。但 Oracle 依然支持DBMS_SQL,所以動態 SQL 既可以通過本地動態 SQL 來執行,也可以通過DBMS_SQL包來執行。

通過本地動態 SQL 執行動態 SQL 語句的語法是:

EXECUTE IMMEDIATE dynamic_string
  {INTO {define_variable1 [,define_variable2 ...] | record_name}}
  [USING [IN|OUT|IN OUT] bind_argument1 [,[IN|OUT|IN OUT] bind_argument2] ...]
  [returning_clause];

EXECUTE IMMEDIATE 解析並馬上執行動態的 SQL 語句或非運行時創建的 PL/SQL 塊。語法中的 INTO 子句用於將查詢返回的結果值傳遞給已定義的標量類型變數或記錄變數,但這裡只能接收單行查詢的返回結果。

使用 EXECUTE IMMEDIATE 方式比使用DBMS_SQL方式寫法更簡潔,運行數度也更快。但DBMS_SQL比 EXECUTE IMMEDIATE 更強大,某些極端複雜的情況只有DBMS_SQL能實現,不過話又說回來了,如今過於複雜的功能基本也沒人會依賴於資料庫的,所以我個人覺得沒必要掌握DBMS_SQL。但如果不幸需要維護使用了DBMS_SQL的老代碼時,可以參考:《Oracle Database PL/SQL Packages and Types Reference: DBMS_SQL》

2.3、綁定變數

綁定變數也就是動態 SQL 語句中的一個占位符,它告訴 Oracle 現在需要生成一個執行計劃,隨後會為這個占位符提供一個值。綁定變數的占位符是在動態 SQL 語句中指定的,可以是 :1、:2、:3 之類的,也可以是 :a、:b、:c 這樣的定義。

綁定變數在動態 SQL 中應用,主要是為了實現一次解析,多次執行,從而提高效率的目的。綁定變數的優勢是可以在庫緩存中共用游標,這樣可以避免硬解析及與之相關的額外開銷。因此,綁定變數是一種減少應用程式在分析查詢時使用栓鎖數目的有效方法,其次,使用綁定變數可以避免註入攻擊。

本地動態 SQL 語法中的 USING 子句用於在 DML 需要傳入的變數中、共用庫緩存游標、避免硬解析。USING 後的是綁定變數的實際值,按照動態 SQL 中綁定變數的順序賦值,不管名字是否重覆,全部都要賦值。而 RETURNING INTO 子句主要用於 DML 語句中所返回被影響的列值。

使用綁定變數的幾個限制:

  • 1、綁定變數不能直接傳入 NULL 值。
  • 2、USING 後的綁定變數必須是 SQL 類型,例如:字元型、整形、浮點型等,而 PL/SQL 的 BOOLEAN 等類型是不支持的。
  • 3、綁定變數不能用表名或列別名來替換。
  • 4、綁定變數只能代替 SQL 或 PL/SQL 中的字面量、變數和簡單表達式。
  • 5、動態 DLL 語句中不允許出現綁定變數。因為在運行期間,引擎要解析動態語句中的對象,確保 SQL 語法正確,而綁定變數此時還是變數,這樣 Oracle 會認為對象不存在。此時可以通過拼接字元串的方式來實現。

3、動態 SQL 實戰

3.1、封裝執行 DML 的通用存儲過程

示例 1(證明動態 DLL 語句中不允許出現綁定變數):

DECLARE
  v_sql VARCHAR2(100);
  v_table_name VARCHAR2(30):='demo.t2';
BEGIN
  v_sql := 'DROP TABLE :1';
  EXECUTE IMMEDIATE v_sql USING v_table_name;
  
EXCEPTION
  WHEN OTHERS THEN
    DBMS_OUTPUT.PUT_LINE('異常:'||SQLCODE||': '||SUBSTR(SQLERRM,1,64));
END;

上例的輸出結果是:“異常:-903: ORA-00903: 表名無效”。這也就證明瞭 DROP TABLE 語句中是不允許使用綁定變數的,其它 DDL 也一樣,這裡就不一一證明瞭。上例的正確寫法是(將綁定變數換成拼接字元串):

DECLARE
  v_sql VARCHAR2(100);
  v_table_name VARCHAR2(30):='demo.t2';
BEGIN
  v_sql := 'DROP TABLE '||v_table_name;
  EXECUTE IMMEDIATE v_sql;
END;

示例 2(編寫一個簡單的動態查詢,遍歷輸出所有課程信息):

DECLARE
  v_sql VARCHAR2(500);
  v_table_name VARCHAR2(30):='T_COURSE';
  v_field_list VARCHAR2(300);
  v_cursor SYS_REFCURSOR;
  v_course demo.t_course%ROWTYPE;
BEGIN
  v_sql := 'SELECT WM_CONCAT(t.column_name) FROM USER_TAB_COLUMNS t WHERE t.table_name=:1';
  EXECUTE IMMEDIATE v_sql INTO v_field_list USING v_table_name;
  
  v_sql := 'SELECT '||v_field_list||' FROM '||v_table_name;
  OPEN v_cursor FOR v_sql;
  LOOP
    FETCH v_cursor INTO v_course;
    EXIT WHEN v_cursor%NOTFOUND;
    DBMS_OUTPUT.PUT_LINE(v_course.course_id||','||v_course.course_name||','||v_course.course_desc);
  END LOOP;
  CLOSE v_cursor;
END;

示例 3(封裝一個根據某個欄位值刪除表中數據的通用存儲過程):

CREATE OR REPLACE PROCEDURE sp_delete_data(
  p_table IN VARCHAR2,       -- 刪除表名稱
  p_field IN VARCHAR2 := '', -- 刪除條件欄位名
  p_value IN VARCHAR2 := ''  -- 刪除條件欄位值
)
/**************************************************
功能:刪除 p_table 表中 p_field 欄位值為 p_value 的數據

修訂記錄:
版本號    修訂時間      修訂人    描述
1.0.0     2017-05-17    hanzz     1.創建此存儲過程
**************************************************/
AS
  v_sql VARCHAR2(500);
BEGIN
  IF p_field IS NULL THEN -- 未指定欄位時,刪除整個表的數據
    v_sql := 'DELETE FROM '||p_table;
  ELSE
    v_sql := 'DELETE FROM '||p_table||' t WHERE t.'||p_field||'='''||p_value||'''';
  END IF;
  
  EXECUTE IMMEDIATE v_sql; -- 執行刪除語句
  COMMIT; -- 提交刪除
END;

調用:

BEGIN
  sp_delete_data('demo.t_course','course_id','1'); -- 刪除課程表中 ID 為 1 的課程
  sp_delete_data(p_table => 'demo.t_course'); -- 刪除課程表中的所有數據
END;

示例 4(封裝一個根據某個欄位值修改另一個欄位值的通用存儲過程):

CREATE OR REPLACE PROCEDURE sp_update_data(
  p_table_name IN VARCHAR2,        -- 修改表名稱
  p_update_field IN VARCHAR2,      -- 被修改欄位名
  p_update_value IN VARCHAR2,      -- 被修改欄位值
  p_where_field IN VARCHAR2 := '', -- 修改條件欄位名
  p_where_value IN VARCHAR2 := ''  -- 修改條件欄位值
)
/**************************************************
功能:將 p_table_name 表中 p_where_field 欄位值為 p_where_value 的行中 p_update_field 欄位的值修改為 p_update_value

修訂記錄:
版本號    修訂時間      修訂人    描述
1.0.0     2017-05-17    hanzz     1.創建此存儲過程
**************************************************/
AS
  v_sql VARCHAR2(500);
BEGIN
  IF p_where_field IS NULL THEN -- 未指定欄位時,修改整個表的數據
    v_sql := 'UPDATE '||p_table_name||' SET '||p_update_field||'=:1';
    EXECUTE IMMEDIATE v_sql USING p_update_value;
  ELSE
    v_sql := 'UPDATE '||p_table_name||' SET '||p_update_field||'=:1'||' WHERE '||p_where_field||'=:2';
    EXECUTE IMMEDIATE v_sql USING p_update_value,p_where_value; -- 執行修改語句
  END IF;

  COMMIT; -- 提交修改
END;

調用:

BEGIN
  sp_update_data('t_course','course_desc','漢語','course_id','1'); -- 將 ID 為 1 的課程備註改為漢語
  sp_update_data('t_course','course_desc','電腦'); -- 將表中所有課程備註改為電腦
END;

3.2、批量編譯資料庫對象

視圖、函數、存儲過程、包、觸發器等模式對象依賴於基表,當基表被修改後,可能會導致 Oracle 資料庫重新編譯這些模式對象,如果編譯未通過就會直接掛掉(在 PL/SQL Developer 里看的話,對象名左上角會有一個紅色的星號)。而且好像一旦編譯未通過就不再重新編譯了,這樣會導致即使正確的修改,只要中間過程有檢測到編譯未通過最終也會掛掉。所以有時候不得不在所有修改完成後對那些掛掉的對象進行編譯。

編譯對象的語法:

ALTER PROCEDURE|FUNCTION|PACKAGE [<schema>.]<name> COMPILE [BODY];

編譯示例可參考:《.Net程式員學用Oracle系列(7):視圖、函數、存儲過程、包》。但有時候掛掉的對象太多,如果為每個掛掉的對象都寫條編譯語句來編譯顯然效率太低,這時候可以用下麵這段 PL/SQL 實現批量編譯資料庫中所有已掛掉的模式對象(包括:視圖、函數、存儲過程、包、觸發器)。

DECLARE
  v_sql VARCHAR2(200);
BEGIN
  FOR obj IN(
    SELECT t.object_type,t.object_name FROM USER_OBJECTS t
    WHERE t.object_type IN('VIEW','FUNCTION','PROCEDURE','PACKAGE','TRIGGER') AND t.status='INVALID'
    ORDER BY t.object_type
  )
  LOOP
    v_sql:='ALTER '||obj.object_type||' '||USER||'.'||obj.object_name||' COMPILE';
    DBMS_OUTPUT.PUT_LINE(v_sql||';');
    EXECUTE IMMEDIATE v_sql;
  END LOOP;
END;

3.3、統計資料庫的總行數

示例 1(統計當前資料庫的總行數):

DECLARE
  v_cursor SYS_REFCURSOR;
  v_sql VARCHAR2(200);    -- 存放統計行數的 SQL 語句
  v_rows INT := 0;        -- 單表行數
  v_total_rows INT := 0;  -- 總行數
  v_total_tables INT :=0; -- 總表數
BEGIN
  OPEN v_cursor FOR
    SELECT 'SELECT COUNT(1) FROM '||LOWER(USER)||'.'||LOWER(t.table_name) 
    FROM USER_TABLES t;
  LOOP
    FETCH v_cursor INTO v_sql;
    EXIT WHEN v_cursor%NOTFOUND;

    EXECUTE IMMEDIATE v_sql INTO v_rows; -- 執行統計的 SQL 語句
    v_total_rows := v_total_rows + v_rows; -- 逐表累加行數
    v_total_tables := v_total_tables + 1;  -- 累加表數
  END LOOP;
  CLOSE v_cursor;
  DBMS_OUTPUT.PUT_LINE(USER||' 的總表數是:'||v_total_tables);
  DBMS_OUTPUT.PUT_LINE(USER||' 的總行數是:'||v_total_rows);
END;

示例 2(統計指定用戶所擁有表的總行數):

DECLARE
  v_cursor SYS_REFCURSOR;
  v_owner VARCHAR2(30):='JIRA';
  v_sql VARCHAR2(200);    -- 存放統計行數的 SQL 語句
  v_rows INT := 0;        -- 單表行數
  v_total_rows INT := 0;  -- 總行數
  v_total_tables INT :=0; -- 總表數
BEGIN
  OPEN v_cursor FOR
    SELECT 'SELECT COUNT(1) FROM '||LOWER(v_owner)||'.'||LOWER(t.table_name) 
    FROM DBA_TABLES t WHERE t.owner='JIRA';
  LOOP
    FETCH v_cursor INTO v_sql;
    EXIT WHEN v_cursor%NOTFOUND;

    EXECUTE IMMEDIATE v_sql INTO v_rows; -- 執行統計的 SQL 語句
    v_total_rows := v_total_rows + v_rows; -- 逐表累加行數
    v_total_tables := v_total_tables + 1;  -- 累加表數
  END LOOP;
  CLOSE v_cursor;
  DBMS_OUTPUT.PUT_LINE(v_owner||' 的總表數是:'||v_total_tables);
  DBMS_OUTPUT.PUT_LINE(v_owner||' 的總行數是:'||v_total_rows);
END;

4、總結

本文主要講述了 Oracle 中的 SQL 分類和動態 SQL 語句。在 SQL 分類部分著重講解了最為常用的兩類 SQL 語言:DDL 和 DML。在動態 SQL 語句部分,著重講解了動態 SQL 語句的語法和應用,並提供了幾個本人自我感覺比較有代表性的案例。

本文鏈接http://www.cnblogs.com/hanzongze/p/Oracle-plsql-3.html
版權聲明:本文為博客園博主 韓宗澤 原創,作者保留署名權!歡迎通過轉載、演繹或其它傳播方式來使用本文,但必須在明顯位置給出作者署名和本文鏈接!本人初寫博客,水平有限,若有不當之處,敬請批評指正,謝謝!


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

-Advertisement-
Play Games
更多相關文章
  • 一.ES6簡介 引用阮一峰老師的話:ECMAScript 6.0(以下簡稱 ES6)是 JavaScript 語言的下一代標準,已經在2015年6月正式發佈了。它的目標,是使得 JavaScript 語言可以用來編寫複雜的大型應用程式,成為企業級開發語言。 二.變數 let命令: ES6新增了let ...
  • js中的this是一個頭疼的問題,尤其對於筆者這種初級的菜鳥來講,下麵梳理下this的知識,可以當做是初級進階也好入門也罷,總歸輸出的才是自己掌握的: Js中this不是由詞法作用域決定的 而是調用時動態指定,這就有點麻煩了,如果不能明確知道函數調用時的詞法作用域this的指向也就只能靠猜了,算一卦 ...
  • 這是Webpack+React系列配置過程記錄的第四篇。其他內容請參考: 第一篇:使用webpack、babel、react、antdesign配置單頁面應用開發環境 第二篇:使用react-router實現單頁面應用路由 第三篇:優化單頁面開發環境:webpack與react的運行時打包與熱更新 ...
  • * 這東西叫“通配符”用來匹配頁面上所有元素。*{margin:0; padding:0;} 像 2L 所說,body ,ul, li ,p,h1~h6,dd,dt 等……都有預設的margin 或padding值的,加上這句就可以刪除瀏覽器這些預設值,方面後面的設置。(註:不是沒它不行,只是方便而 ...
  • 淺談Kotlin(一):簡介及Android Studio中配置 淺談Kotlin(二):基本類型、基本語法、代碼風格 前言: 已經學習了前兩篇文章,對Kotlin有了一個基本的認識,往後的文章開始深入介紹Kotlin的實戰使用。 本篇介紹Kotlin中類的使用。 一、表現形式 首先看一段Java中 ...
  • 一,效果圖。 二,工程圖。 三, 代碼。 RootViewController.h #import <UIKit/UIKit.h> //添加HPGrowingTextView頭文件 #import "HPGrowingTextView.h" @interface RootViewController ...
  • 原文來自:http://www.runoob.com/w3cnote/android-tutorial-imageview.html 本節引言: 本節介紹的UI基礎控制項是:ImageView(圖像視圖),見名知意,就是用來顯示圖像的一個View或者說控制項! 官方API:ImageView;本節講解的 ...
  • 在導出資料庫dmp文件時,有資料庫表空記錄的情況下,該空表不會被導出表結構,應用如下格式代碼: select 'alter table ' || table_name || ' allocate extent(size 64k);' sql_text, table_name, tablespace_ ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...