C/C++ 通過SQLiteSDK增刪改查

来源:https://www.cnblogs.com/LyShark/archive/2023/11/25/17856012.html
-Advertisement-
Play Games

SQLite,作為一款嵌入式關係型資料庫管理系統,一直以其輕量級、零配置以及跨平臺等特性而備受青睞。不同於傳統的資料庫系統,SQLite是一個庫,直接與應用程式一同編譯和鏈接,無需單獨的資料庫伺服器進程,實現了資料庫的零配置管理。這種設計理念使得SQLite成為許多嵌入式系統、移動應用和小型項目中的... ...


SQLite,作為一款嵌入式關係型資料庫管理系統,一直以其輕量級、零配置以及跨平臺等特性而備受青睞。不同於傳統的資料庫系統,SQLite是一個庫,直接與應用程式一同編譯和鏈接,無需單獨的資料庫伺服器進程,實現了資料庫的零配置管理。這種設計理念使得SQLite成為許多嵌入式系統、移動應用和小型項目中的首選資料庫引擎。

SQLite的特點包括:

  1. 嵌入式資料庫引擎: SQLite 是一個嵌入式資料庫引擎,意味著它是一個庫,與應用程式一同編譯和鏈接,而不是作為獨立的進程運行。
  2. 零配置: 無需配置或管理。SQLite 不需要一個獨立的資料庫伺服器進程,所有的操作都是直接在存儲在文件中的資料庫上執行。
  3. 輕量級: SQLite 是一個輕量級的資料庫,相對於一些其他資料庫管理系統來說,它的記憶體占用和資源消耗相對較小。
  4. 支持 SQL: SQLite 支持大部分標準的 SQL 語法,並提供了事務支持,包括隔離級別和回滾。
  5. 跨平臺: SQLite 可以在各種操作系統上運行,包括 Windows、Linux、macOS 和其他嵌入式系統。
  6. 自給自足: SQLite 資料庫是一個單一的磁碟文件,整個資料庫被存儲在一個文件中,這使得備份、複製或傳輸資料庫變得非常容易。
  7. 開源: SQLite 是一個開源項目,採用公共領域授權(Public Domain License),可以在商業和非商業項目中免費使用。

SQLite 資料庫以其獨特的自給自足特性脫穎而出,整個資料庫被存儲在一個單一的磁碟文件中,使得備份、複製或傳輸資料庫變得異常簡單。而作為一款開源項目,SQLite採用了公共領域授權,可以在商業和非商業項目中免費使用。

由於該資料庫的小巧和簡潔所以在使用上也非常容易,當讀者下載好附件以後會看到如下圖所示的文件;

使用時只需要將sqlite3.hsqlite3.c文件導入到項目中並使用#include "sqlite3.h"即可,無需做其他配置,圖中的sqlite3.dll是動態庫,sqlite3.exe則是一個命令行版本的資料庫可在測試時使用它。

打開與關閉庫

sqlite3_open 用於打開或創建一個 SQLite 資料庫文件。該函數的原型如下:

int sqlite3_open(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb          /* OUT: SQLite db handle */
);
  • filename: 要打開或創建的 SQLite 資料庫文件的路徑。如果文件不存在,將會創建一個新的資料庫文件。
  • ppDb: 用於存儲 SQLite 資料庫句柄(handle)的指針。SQLite 資料庫句柄是與一個打開的資料庫關聯的結構,它在後續的 SQLite 操作中用作標識。

該函數返回一個整數值,代表函數的執行狀態。如果函數成功執行,返回 SQLITE_OK。如果有錯誤發生,返回一個表示錯誤代碼的整數值。可以通過 sqlite3_errmsg 函數獲取更詳細的錯誤信息。

sqlite3_close 用於關閉資料庫連接的函數。其原型如下:

int sqlite3_close(sqlite3*);
  • sqlite3: 要關閉的 SQLite 資料庫連接的句柄。

該函數返回一個整數值,用於表示函數的執行狀態。如果函數成功執行,返回 SQLITE_OK。如果有錯誤發生,返回一個表示錯誤代碼的整數值。

使用 sqlite3_close 函數可以釋放與資料庫連接相關的資源,並確保資料庫文件被正確關閉。在關閉資料庫連接之前,應該確保已經完成了所有需要執行的 SQL 語句,併在需要的情況下檢查執行結果。

// 打開資料庫並返回句柄
sqlite3* open_database(std::string database_name)
{
  int ref =-1;
  sqlite3 *db = 0;

  ref = sqlite3_open(database_name.c_str(), &db);
  if (ref == SQLITE_OK)
    return db;
  return false;
}

// 關閉資料庫
bool close_database(sqlite3 *db)
{
  int ref = sqlite3_close(db);
  if (ref == SQLITE_OK)
    return true;
  return false;
}

執行查詢語句

sqlite3_exec 用於執行 SQL 語句的高級介面函數。它的原型如下:

int sqlite3_exec(
  sqlite3* db,                    /* Database handle */
  const char* sql,                /* SQL statement, UTF-8 encoded */
  int (*callback)(                /* Callback function */
    void*,                        /* Callback parameter */
    int,                          /* Number of columns in the result set */
    char**,                       /* Array of column values */
    char**                        /* Array of column names */
  ),
  void* callback_param,           /* 1st argument to callback function */
  char** errmsg                   /* Error msg written here */
);
  • db: SQLite 資料庫連接的句柄。
  • sql: 要執行的 SQL 語句,以 UTF-8 編碼。
  • callback: 回調函數,用於處理查詢結果的每一行數據。
  • callback_param: 傳遞給回調函數的參數。
  • errmsg: 用於存儲錯誤消息的指針。

sqlite3_exec 函數執行一個或多個 SQL 語句,並對每一條語句的執行結果調用指定的回調函數。回調函數的原型如下:

int callback(
  void* callback_param, /* 參數,由 sqlite3_exec 傳遞給回調函數 */
  int num_columns,      /* 結果集中的列數 */
  char** column_values,  /* 指向結果集中當前行的列值的數組 */
  char** column_names    /* 指向結果集中列名的數組 */
);
  • callback_param: 回調函數的參數,由 sqlite3_exec 傳遞給回調函數。
  • num_columns: 結果集中的列數。
  • column_values: 指向結果集中當前行的列值的數組。
  • column_names: 指向結果集中列名的數組。

回調函數返回一個整數,用於指示是否繼續執行後續的 SQL 語句。如果回調函數返回非零值,sqlite3_exec 將停止執行 SQL,並立即返回。

sqlite3_prepare_v2 用於準備 SQL 語句的介面函數。它的原型如下:

int sqlite3_prepare_v2(
  sqlite3* db,            /* Database handle */
  const char* sql,        /* SQL statement, UTF-8 encoded */
  int sql_len,            /* Length of SQL statement in bytes, or -1 for zero-terminated */
  sqlite3_stmt** stmt,    /* OUT: Statement handle */
  const char** tail       /* OUT: Pointer to unused portion of SQL statement */
);
  • db: SQLite 資料庫連接的句柄。
  • sql: 要準備的 SQL 語句,以 UTF-8 編碼。
  • sql_len: SQL 語句的長度,如果為 -1,則表示 SQL 語句以 null 結尾。
  • stmt: 用於存儲準備好的語句句柄的指針。
  • tail: 用於存儲未使用的 SQL 語句的指針。

sqlite3_prepare_v2 函數用於將 SQL 語句編譯成一個 SQLite 語句對象(prepared statement)。這個對象可以被多次執行,每次執行時可以綁定不同的參數。stmt 參數將用於存儲編譯後的語句的句柄,以供後續的操作。

sqlite3_step 執行預編譯 SQL 語句的介面函數。它的原型如下:

int sqlite3_step(sqlite3_stmt*);
  • sqlite3_stmt*: 由 sqlite3_prepare_v2 預編譯的 SQL 語句的句柄。

sqlite3_step 函數用於執行由 sqlite3_prepare_v2 預編譯的 SQL 語句。在執行過程中,可以通過不斷調用 sqlite3_step 來逐行獲取查詢結果,直到結果集結束。對於非查詢語句(如 INSERTUPDATEDELETE),sqlite3_step 函數執行一次即可完成操作。

該函數的返回值表示執行的結果,可能的返回值包括:

  • SQLITE_ROW: 成功獲取一行數據。
  • SQLITE_DONE: 執行完成,沒有更多的數據可用(用於非查詢語句)。
  • 其他錯誤碼,表示執行過程中出現了錯誤。

sqlite3_column_text 用於獲取查詢結果集中某一列的文本值。其原型為:

const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol);
  • sqlite3_stmt*: 由 sqlite3_prepare_v2 預編譯的 SQL 語句的句柄。
  • int iCol: 列的索引,從0開始。

該函數返回指向字元串值的指針,該字元串值是查詢結果集中指定列的文本表示。需要註意的是,返回的指針指向 SQLite 內部的存儲區,應該在使用完之後儘早釋放資源。

sqlite3_column_int 用於獲取查詢結果集中某一列的整數值。其原型為:

int sqlite3_column_int(sqlite3_stmt*, int iCol);
  • sqlite3_stmt*: 由 sqlite3_prepare_v2 預編譯的 SQL 語句的句柄。
  • int iCol: 列的索引,從0開始。

該函數返回查詢結果集中指定列的整數表示。需要註意的是,如果該列不是整數類型,或者包含的數據無法轉換為整數,那麼返回的結果可能不是有效的整數值。

sqlite3_finalize 用於釋放一個預備語句對象(prepared statement)。在使用 sqlite3_prepare_v2 函數準備 SQL 語句後,需要使用 sqlite3_finalize 來釋放相應的語句對象。

該函數的原型為:

int sqlite3_finalize(sqlite3_stmt *pStmt);
  • sqlite3_stmt *pStmt: 指向要釋放的語句對象的指針。

該函數返回 SQLITE_OK 表示成功,返回其他錯誤碼表示失敗。

// 執行SQL語句
bool exec_sql(sqlite3 *db, char *sql)
{
  char *error_code = 0;
  int ref = sqlite3_exec(db, sql, 0, 0, &error_code);
  if (ref == SQLITE_OK)
  {
    return true;
  }
  return false;
}

// 插入數據
bool insert_data(sqlite3 *db, char *sql)
{
  sqlite3_stmt *stmt = 0;

  // 插入前檢查語句合法性, -1自動計算SQL長度
  int ref = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
  if (ref == SQLITE_OK)
  {
    sqlite3_step(stmt);       // 執行語句
    sqlite3_finalize(stmt);   // 清理語句句柄
    return true;
  }
  sqlite3_finalize(stmt);
  return false;
}

// 查詢數據集
bool select_data(sqlite3 *db, char *sql)
{
  sqlite3_stmt *stmt = 0;

  int ref = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
  if (ref == SQLITE_OK)
  {
    // 每調一次sqlite3_step()函數,stmt就會指向下一條記錄
    while (sqlite3_step(stmt) == SQLITE_ROW)
    {
      // 取出第1列欄位的值
      const unsigned char *name = sqlite3_column_text(stmt, 1);
      
      // 取出第2列欄位的值
      int age = sqlite3_column_int(stmt, 2);
      std::cout << "姓名: " << name << " 年齡: " << age << std::endl;
    }
  }
  else
  {
    sqlite3_finalize(stmt);
    return false;
  }
  sqlite3_finalize(stmt);
  return true;
}

調用查詢語句

創建資料庫

首先打開了名為 "database.db" 的 SQLite 資料庫,並創建了一個名為 "LySharkDB" 的表,該表格包含了id、name、agemsg四個欄位。隨後,通過執行 SQL 語句創建了這個表格。最後,關閉了資料庫連接。這段代碼主要用於資料庫初始化操作,確保了資料庫中包含了指定的表格結構。

int main(int argc, char *argv[])
{
  sqlite3* open_db = open_database("database.db");
  if (open_db != false)
  {
    bool create_table_ref;

    std::string sql = 
      "create table LySharkDB("
      "id int auto_increment primary key,"
      "name char(30) not null," 
      "age int not null,"
      "msg text default null"
      ")";

    // 運行創建表操作
    char run_sql[1024] = { 0 };
    strcpy(run_sql, sql.c_str());
    create_table_ref = exec_sql(open_db, run_sql);
  }

  close_database(open_db);
  std::system("pause");
  return 0;
}

上述代碼運行後則可以創建一個資料庫database.db表名為LySharkDB讀者可以使用資料庫工具打開該表,其結構如下所示;

插入數據測試

創建資料庫後,接著就是插入數據測試,插入時可以使用insert_data,如下代碼項資料庫中插入5條記錄;

int main(int argc, char *argv[])
{
  sqlite3* open_db = open_database("./database.db");
  if (open_db != false)
  {
    bool create_table_ref;

    // 運行插入記錄
    if (create_table_ref == true)
    {
      bool insert_ref = 0;
      insert_ref = insert_data(open_db, "insert into LySharkDB(id,name,age,msg) values(1,'lyshark',1,'hello lyshark');");
      insert_ref = insert_data(open_db, "insert into LySharkDB(id,name,age,msg) values(2,'guest',2,'hello guest');");
      insert_ref = insert_data(open_db, "insert into LySharkDB(id,name,age,msg) values(3,'admin',3,'hello admin');");
      insert_ref = insert_data(open_db, "insert into LySharkDB(id,name,age,msg) values(4,'wang',4,'hello wang');");
      insert_ref = insert_data(open_db, "insert into LySharkDB(id,name,age,msg) values(5,'sqlite',5,'hello sql');");
      if (insert_ref == true)
      {
        std::cout << "插入完成" << std::endl;
      }
    }
  }
  close_database(open_db);
  std::system("pause");
  return 0;
}

插入後,打開資料庫管理軟體,可看到插入後的記錄;

查詢與刪除數據

而查詢刪除與增加記錄,我們這裡直接使用exec_sql()函數,通過傳入不同的SQL語句實現。

int main(int argc, char *argv[])
{
  sqlite3* open_db = open_database("./database.db");
  if (open_db != false)
  {
    // 刪除記錄
    bool delete_ref = exec_sql(open_db, "delete from LySharkDB where id = 5;");
    if (delete_ref == true)
    {
      std::cout << "刪除完成." << std::endl;
    }

    // 更新記錄
    bool update_ref = exec_sql(open_db, "update LySharkDB set name='lyshark' where id = 4;");
    if (update_ref == true)
    {
      std::cout << "更新完成." << std::endl;
    }

    // 查詢數據
    bool select_ref = select_data(open_db, "select * from LySharkDB;");
    if (select_ref == true)
    {
      std::cout << "查詢完畢." << std::endl;
    }
  }
  close_database(open_db);
  std::system("pause");
  return 0;
}

執行更新後的表記錄如下所示;

查詢區間數據

首先創建一些數據集,這裡通過迴圈生成並插入數據,如下代碼中新建一個TimeDB數據表,其中有三個欄位uid,host_time,cpu_value

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <time.h>
#include "sqlite3.h"

#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

using namespace std;
using namespace boost;

// 獲取本地時間日期
std::string get_local_datetime()
{
	char ct[80];
	time_t  tt;
	struct tm *tblock;

	tt = time(NULL);
	tblock = localtime(&tt);

	strftime(ct, sizeof(ct), "%Y-%m-%d %H:%M:%S", tblock);
	return ct;
}

// 初始化創建表結構
void Init_Database()
{
	sqlite3* open_db = open_database("./database.db");
	if (open_db != false)
	{
		bool create_table_ref;
		std::string sql =
			"create table TimeDB("
			"uid primary key,"
			"host_time char(128) not null,"
			"cpu_value int not null"
			");";
		char run_sql[1024] = { 0 };
		strcpy(run_sql, sql.c_str());
		exec_sql(open_db, run_sql);
	}
	close_database(open_db);
}

// 批量生成時間字元串並插入數據表
void Insert_Test()
{
	sqlite3* open_db = open_database("./database.db");
	for (int x = 0; x < 1000; x++)
	{
		// 獲取本地日期時間
		std::string local_times = get_local_datetime();
		std::string format_string = boost::str(boost::format("insert into TimeDB(uid,host_time,cpu_value) values(%d,'%s',%d);") % x %local_times %x);

		std::cout << "執行SQL: " << format_string << std::endl;

		char run_sql[1024] = { 0 };
		strcpy(run_sql, format_string.c_str());
		insert_data(open_db, run_sql);
		_sleep(1000);
	}
	close_database(open_db);
}

int main(int argc, char *argv[])
{
	sqlite3* open_db = open_database("./database.db");
	Init_Database();
	Insert_Test();

	std::system("pause");
	return 0;
}

如下是五分鐘的模擬數據;

當有了數據則再查詢,代碼中Select_Time_List函數演示瞭如何通過時間查詢一個區間的數據,並返回一個容器列表給被調用者使用,查詢代碼如下所示;

#include <iostream>
#include <string>
#include <map>
#include <vector>
#include <time.h>
#include "sqlite3.h"

#include <boost/lexical_cast.hpp>
#include <boost/format.hpp>

using namespace std;
using namespace boost;

// 打開資料庫並返回句柄
sqlite3* open_database(std::string database_name)
{
	int ref = -1;
	sqlite3 *db = 0;

	ref = sqlite3_open(database_name.c_str(), &db);
	if (ref == SQLITE_OK)
		return db;
	return false;
}

// 關閉資料庫
bool close_database(sqlite3 *db)
{
	int ref = sqlite3_close(db);
	if (ref == SQLITE_OK)
		return true;
	return false;
}

// 執行SQL語句
bool exec_sql(sqlite3 *db, char *sql)
{
	char *error_code = 0;
	int ref = sqlite3_exec(db, sql, 0, 0, &error_code);
	if (ref == SQLITE_OK)
	{
		return true;
	}
	return false;
}

// 插入數據
bool insert_data(sqlite3 *db, char *sql)
{
	sqlite3_stmt *stmt = 0;

	// 插入前檢查語句合法性, -1自動計算SQL長度
	int ref = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
	if (ref == SQLITE_OK)
	{
		sqlite3_step(stmt);       // 執行語句
		sqlite3_finalize(stmt);   // 清理語句句柄
		return true;
	}
	sqlite3_finalize(stmt);
	return false;
}

// 查詢數據集
bool select_data(sqlite3 *db, char *sql)
{
	sqlite3_stmt *stmt = 0;

	int ref = sqlite3_prepare_v2(db, sql, -1, &stmt, 0);
	if (ref == SQLITE_OK)
	{
		// 每調一次sqlite3_step()函數,stmt就會指向下一條記錄
		while (sqlite3_step(stmt) == SQLITE_ROW)
		{
			// 取出第1列欄位的值
			const unsigned char *name = sqlite3_column_text(stmt, 1);

			// 取出第2列欄位的值
			int age = sqlite3_column_int(stmt, 2);
			std::cout << "姓名: " << name << " 年齡: " << age << std::endl;
		}
	}
	else
	{
		sqlite3_finalize(stmt);
		return false;
	}
	sqlite3_finalize(stmt);
	return true;
}

// 獲取本地時間日期
std::string get_local_datetime()
{
	char ct[80];
	time_t  tt;
	struct tm *tblock;

	tt = time(NULL);
	tblock = localtime(&tt);

	strftime(ct, sizeof(ct), "%Y-%m-%d %H:%M:%S", tblock);
	return ct;
}

// 初始化創建表結構
void Init_Database()
{
	sqlite3* open_db = open_database("./database.db");
	if (open_db != false)
	{
		bool create_table_ref;
		std::string sql =
			"create table TimeDB("
			"uid primary key,"
			"host_time char(128) not null,"
			"cpu_value int not null"
			");";
		char run_sql[1024] = { 0 };
		strcpy(run_sql, sql.c_str());
		exec_sql(open_db, run_sql);
	}
	close_database(open_db);
}

// 批量生成時間字元串並插入數據表
void Insert_Test()
{
	sqlite3* open_db = open_database("./database.db");
	for (int x = 0; x < 1000; x++)
	{
		// 獲取本地日期時間
		std::string local_times = get_local_datetime();
		std::string format_string = boost::str(boost::format("insert into TimeDB(uid,host_time,cpu_value) values(%d,'%s',%d);") % x %local_times %x);

		std::cout << "執行SQL: " << format_string << std::endl;

		char run_sql[1024] = { 0 };
		strcpy(run_sql, format_string.c_str());
		insert_data(open_db, run_sql);
		_sleep(1000);
	}
	close_database(open_db);
}

// 查詢時間區間並返回 傳入開始時間與結束時間,過濾出特定的記錄
bool Select_Time_List(sqlite3 *db, std::vector<std::map<std::string, int>> &time_ref, std::string start_time, std::string end_time)
{
	sqlite3_stmt *stmt = 0;
	std::string format_string = boost::str(boost::format("select * from TimeDB where host_time >= '%s' and host_time <= '%s';") % start_time %end_time);

	char run_sql[1024] = { 0 };
	strcpy(run_sql, format_string.c_str());

	int ref = sqlite3_prepare_v2(db, run_sql, -1, &stmt, 0);
	if (ref == SQLITE_OK)
	{
		while (sqlite3_step(stmt) == SQLITE_ROW)
		{
			std::map < std::string, int > ptr;

			// 取出第一個和第二個欄位
			const unsigned char *time_text = sqlite3_column_text(stmt, 1);
			const int cpu_value = sqlite3_column_int(stmt, 2);

			// 放入一個map容器中
			ptr[boost::lexical_cast<std::string>(time_text)] = cpu_value;
			time_ref.push_back(ptr);
		}
		sqlite3_finalize(stmt);
		return true;
	}
	sqlite3_finalize(stmt);
	return false;
}

int main(int argc, char *argv[])
{
	sqlite3* open_db = open_database("./database.db");
	//Init_Database();
	//Insert_Test();

	// 查詢 2023-11-25 19:52:31 - 2023-11-25 19:53:35 區間內的所有的負載情況
	std::vector<std::map<std::string, int>> db_time;
	bool is_true = Select_Time_List(open_db, db_time, "2023-11-25 19:52:31", "2023-11-25 19:53:35");
	if (is_true == true)
	{
		for (int x = 0; x < db_time.size(); x++)
		{
			// 輸出該區間內的數據
			std::map < std::string, int>::iterator ptr;
			for (ptr = db_time[x].begin(); ptr != db_time[x].end(); ptr++)
			{
				std::cout << "時間區間: " << ptr->first << " CPU利用率: " << ptr->second << std::endl;
			}
		}
	}
	std::system("pause");
	return 0;
}

例如代碼中我們查詢2023-11-25 19:52:31 - 2023-11-25 19:53:35這個區間內的數據信息,並返回一個map容器給被調用者,運行效果如下所示;

文章出處:https://www.cnblogs.com/LyShark/p/17856012.html
本博客所有文章除特別聲明外,均採用 BY-NC-SA 許可協議。轉載請註明出處!
您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Group by 未加索引 使用的是臨時表,加文件排序(數據量小用記憶體排序) 加個索引(一般是聯合索引) 註意:這裡加的索引一般不會僅僅是group by後面的欄位索引(大多數多少條件是一個以該欄位開頭聯合索引,方便使用覆蓋索引或者索引下推)。如果該欄位是一個varchar類型,最好加個int冗餘字 ...
  • 什麼時候要使用嵌套查詢? 學生信息表: 學生編號姓名班級Id電話性別生日 180325011 任我行 5 13823204456 男 1999-09-09 180325012 張三 4 13823204452 女 1998-08-08 180325013 李四 2 18899251152 男 199 ...
  • ,: 小天才手錶系統指南(僅限Z6及以下舊款小天才主流機型)強烈推薦使用PDF版本閱讀 【 聲明】允許規範轉載並說明來源,不可用於商業用途。 【 重要提示】本教程配套其他up的講解視頻 點擊觀看 【 支持機型】降級和ROOT:Z2 Z3 Z5A/PRO/Q Z6(不含巔峰版、Z6A) → Z7以及更 ...
  • 這裡給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 JSONP是一種很遠古用來解決跨域問題的技術,當然現在實際工作當中很少用到該技術了,但是很多同學在找工作面試過程中還是經常被問到,本文將帶您深入瞭解JSONP的工作原理、使用場景及安全註意事項,讓您輕鬆掌握JSONP。 JSONP是什麼? ...
  • 事件匯流排是對發佈-訂閱模式的一種實現。 發佈-訂閱模式定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,所有依賴於它的對象都將得到通知。 發佈-訂閱模式實現了松耦合,發佈者不是直接將消息發送給訂閱者,而是經過了一個中間的代理,事件匯流排就是一種中間代理的實現。 ...
  • matplotlib是基於python生態開發的一個可視化繪圖庫,它的出現讓python在數據分析及機器學習方面占了重要的一部分,目前很多數據分析及機器學習相關方面的工程都有使用到這個庫,並且由於其簡單易用,安裝簡單等方面的優勢深得廣大開發者的喜愛。 ...
  • 15.1、常用組件 15.1.1、 DispatcherServlet DispatcherServlet 是前端控制器,由框架提供,不需要工程師開發; 作用:統一處理請求和響應,整個流程式控制制的中心,由它調用其它組件處理用戶的請求。 15.1.2、HandlerMapping HandlerMapp ...
  • 前言: 在Spring Boot中實現快遞鳥、順豐和快遞100的物流查詢功能通常需要與它們提供的API進行交互。當然使用他們的API 我們是需要申請和註冊,從而去拿到 key 來進行調用。所以為註冊的必須先進行註冊,以下是他們的官網地址,可以快捷到達。 快遞鳥官網:快遞鳥 - 快遞查詢介面_免費快遞 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...