Qt使用sqlite數據庫及項目實戰

一.sqlite使用介紹

在Qt中使用SQLite數據庫非常簡單,SQLite是一個輕量級的嵌入式數據庫,不需要單獨的數據庫服務器,完全使用本地文件來存儲數據。

當在Qt中使用SQLite數據庫時,需要涉及到一些SQL語句以及Qt中的相關函數,接下來我將從頭開始介紹所有涉及的語句以及相應的解釋。

1. 連接到數據庫:addDatabase

在Qt中,你可以使用QSqlDatabase來連接數據庫。首先需要添加數據庫類型,然后指定數據庫的名稱:

QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
db.setDatabaseName("mydatabase.db");
if(!db.open()) {qDebug() << "無法連接到數據庫";return;
}

在這段代碼中,我們首先創建了一個名為mydatabase.db的SQLite數據庫,然后通過open()函數來打開數據庫連接。如果連接失敗,將會輸出錯誤信息。

2. 創建表:CREATE TABLE

一般來說,你需要在數據庫中創建表來存儲數據。這可以通過執行CREATE TABLE語句來實現:

QSqlQuery query;
query.exec("CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)");

這里我們使用exec()函數執行SQL語句,創建了一個名為users的表,包含id、name和age三個列。

3. 插入數據:INSERT

當需要在表中插入新的數據時,可以使用SQL的INSERT INTO語句。在Qt中,可以使用QSqlQuery對象的prepare()和bindValue()函數來執行預處理插入語句:

  • 常規的數據庫插入語句
INSERT into users(id,name,age)VALUES(111,"name",12)
  • Qt中
QString name = "Alice";
int age = 25;
QSqlQuery query;
query.prepare("INSERT INTO users (name, age) VALUES (:name, :age)");
query.bindValue(":name", name);
query.bindValue(":age", age);
if(!query.exec()) {qDebug() << "插入數據失敗:" << query.lastError().text();
}
  • prepare和bindValue函數介紹

當在Qt中進行數據庫操作時,使用query.prepare()和query.bindValue()方法可以幫助你執行預處理SQL語句并綁定參數的值。這兩個方法在插入操作中起到了重要作用,下面我將詳細介紹它們的功能和作用:

  1. query.prepare():

在Qt中,query.prepare()方法用于準備要執行的SQL語句。它的主要作用是將SQL語句中的參數部分用占位符(如:variable)代替,從而形成一個預處理的SQL語句。通過這種方式,可以避免SQL注入攻擊,并提高程序的安全性。

例如,在插入操作中,你可能會使用INSERT INTO table_name (column1, column2, …) VALUES (:value1, :value2, …)這樣的SQL語句,其中的:value1、:value2是占位符,用于將實際的數值動態地填充進去。使用query.prepare()方法可以將這個SQL語句準備好,等待綁定參數值。

  1. query.bindValue():

一旦調用了query.prepare()方法準備好了SQL語句,接下來就可以使用query.bindValue()方法為每個占位符綁定具體的數值。這個方法的作用是設置預處理語句中的占位符的值,從而將真實的數據插入到SQL語句中。

例如,在前面的插入操作示例中,我們對name和age這兩個占位符使用了query.bindValue()方法,將實際的name和age變量的值綁定到了這兩個占位符上。

使用query.bindValue()方法可以方便地將變量的值插入到SQL語句中,同時還可以防止數據類型轉換錯誤和SQL注入攻擊。

綜上所述,query.prepare()方法用于準備預處理SQL語句,并替換其中的占位符,而query.bindValue()方法則用于將實際的數值綁定到這些占位符上,從而完成對數據庫的插入操作。這兩個方法的結合使用可以簡化代碼編寫,同時提高程序的安全性和可維護性。

4. 查詢數據:SELECT

查詢數據最常見的方式是使用SELECT語句。在Qt中,我們可以通過exec()函數執行SELECT語句,并使用next()函數來逐行獲取結果:

QSqlQuery query;
query.exec("SELECT * FROM users");
while(query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();int age = query.value(2).toInt();qDebug() << "ID:" << id << " Name:" << name << " Age:" << age;
}

這段代碼遍歷了users表中的所有行,并輸出每一行的ID、名稱和年齡。

  • query.next介紹

在Qt中,query.next()方法用于遍歷查詢結果集中的下一行數據。當執行SELECT查詢語句并通過exec()方法獲取結果集后,可以使用query.next()方法逐行訪問查詢結果中的數據。

每次調用query.next()方法,會將查詢結果集中的指針移到下一行數據。如果存在下一行數據,則該方法返回true,并允許獲取下一行數據;如果不存在下一行數據,則返回false,表示已經遍歷完所有結果。

一般來說,可以在一個循環中使用query.next()方法來遍歷整個查詢結果集,逐行獲取數據并進行相應的處理。在循環中,通常會結合query.value()方法用于獲取特定列的值。

5. 更新數據:UPDATE

在 Qt 中使用 SQLite 實現更新(修改)數據庫操作可以通過執行 SQL UPDATE 語句來實現。下面是一個簡單的示例代碼,演示了如何使用 Qt 和 SQLite 執行更新操作:

#include <QCoreApplication>
#include <QSqlDatabase>
#include <QSqlQuery>
#include <QSqlError>
#include <QDebug>int main(int argc, char *argv[]) {QCoreApplication app(argc, argv);// 連接到SQLite數據庫QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");db.setDatabaseName("database.db"); // 指定SQLite數據庫文件if (!db.open()) {qDebug() << "Error: Unable to connect to database.";return 1;}// 執行 UPDATE 操作QSqlQuery query;query.prepare("UPDATE student SET name = :newName WHERE id = :id");query.bindValue(":newName", "New Name"); // 設置要更新的新名稱query.bindValue(":id", 1); // 設置要更新的記錄的 IDif (query.exec()) {qDebug() << "Update successful";} else {qDebug() << "Update failed:" << query.lastError().text();}return app.exec();
}

6. 刪除數據:DELETE

使用 QSqlQuery 類刪除數據:

QSqlQuery query;
query.prepare("DELETE FROM your_table WHERE condition = :condition");  // 設置刪除語句
query.bindValue(":condition", value);  // 綁定條件值
bool success = query.exec();  // 執行刪除操作
if(success) {// 刪除成功
} else {// 刪除失敗,處理錯誤qDebug() << "Error:" << query.lastError().text();
}

7. 更新數據庫中的數據:submitAll

  • 這是對模型進行了修改,將數據提交回數據庫中,以保持同步。
// 創建 QSqlTableModel 并設置數據庫表QSqlTableModel model;model.setTable("student");model.select(); // 從數據庫中選擇數據// 創建 QTableView 并設置模型QTableView tableView;tableView.setModel(&model);// 創建一個按鈕,當點擊時提交更新QPushButton updateButton("Update Database");QObject::connect(&updateButton, &QPushButton::clicked, [&model](){if (model.submitAll()) {qDebug() << "Database update successful";} else {qDebug() << "Database update failed:" << model.lastError().text();}});
  • model.submitAll介紹

QSqlTableModel 中的 submitAll() 函數是用于將對模型數據的更改提交到數據庫中的方法。當您在 QTableView 中對數據進行了修改、插入或刪除等操作后,調用 submitAll() 函數可將這些更改應用到數據庫中。

submitAll() 函數會執行以下操作:

  1. 檢查模型中的每一行,如果該行的狀態為 Inserted、Deleted 或 Modified,則將對應的更改提交到數據庫中。
  2. 如果提交成功,會返回 true;如果提交失敗,會返回 false。您可以通過檢查返回值來確定提交是否成功。
  3. 如果提交失敗,您可以調用 model.lastError().text() 來獲取詳細的錯誤信息。這將返回一個描述在提交過程中發生的錯誤的字符串。

在模型視圖的結構中,對model是臨時修改數據的中轉站。

8. 更新QSqlQueryModel中的數據

QSqlQueryModel 是一個只讀模型,無法直接編輯數據,因此更新數據的方式不同于可編輯的模型,比如 QSqlTableModel。如果您想要更新 QSqlQueryModel 中的數據,可以重新執行查詢語句或者重新設置查詢。

以下是更新 QSqlQueryModel 中數據的一種常見方法:

  1. 重新執行查詢語句:您可以重新設置 QSqlQueryModel 的查詢語句,然后調用 setQuery() 方法重新執行查詢。這將重新從數據庫中讀取數據并更新模型中的數據。
QSqlQueryModel model;
model.setQuery("SELECT * FROM your_table");
  1. 使用 clear() 方法清空數據:如果需要清空 QSqlQueryModel 中的數據,您可以調用 clear() 方法。清空數據后,您可以重新設置查詢或數據源,從而實現更新。
model.clear();

需要注意的是,QSqlQueryModel 是一個只讀模型,不支持直接編輯數據,如果您需要在界面上進行編輯和更新操作,可以考慮使用 QSqlTableModel 或自定義的 QAbstractTableModel。

9. 對指定列進行排序

  • 這是對模型進行排序
// 創建 QSqlQueryModel 并設置查詢語句
QSqlQueryModel *queryModel = new QSqlQueryModel;
queryModel->setQuery("SELECT * FROM your_table");// 創建 QSortFilterProxyModel 并設置源模型為 QSqlQueryModel
QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(this);
sortModel->setSourceModel(queryModel);// 設置排序的列索引
int sortColumn = 1; // 假設要按第1列排序
sortModel->sort(sortColumn, Qt::AscendingOrder); // 進行升序排序// 將排序后的模型設置給視圖
yourTableView->setModel(sortModel);
  • 對數據庫進行排序
-- 以id列的升序方式進行排序
SELECT id, name, age
FROM your_table
ORDER BY id ASC;SELECT id ,name ,score  FROM student ORDER BY id DESC//對模型中的數據進行排序
model->setQuery("SELECT id, name, score FROM student ORDER BY id DESC");

二.成績管理系統實戰

1. 項目效果

在這里插入圖片描述

  • 項目說明:底層存儲數據用的是sqlite,界面展示數據用的是tableView和QSqlQueryModel的視圖模型模式。

2. 項目源碼:

  • 類定義
#ifndef STUDENTDLG_H
#define STUDENTDLG_H#include <QDialog>#include <QSqlDatabase> // 專用于連接、創建數據庫
#include <QSqlQuery> // 專用于DML(數據操縱語言)、DDL(數據定義語言)
#include <QSqlQueryModel>//數據庫模型,用來和tableview關聯
#include <QSqlError>
#include <QDebug>
#include <QMessageBox>QT_BEGIN_NAMESPACE
namespace Ui { class StudentDlg; }
QT_END_NAMESPACEclass StudentDlg : public QDialog
{Q_OBJECTpublic:StudentDlg(QWidget *parent = nullptr);~StudentDlg();private slots:void on_pushButtonSort_clicked();void on_pushButton_INSERT_clicked();void on_pushButton_DELETE_clicked();void on_pushButton_UPDATE_clicked();void on_pushButton_SEARCH_clicked();
private: void CreateDatabaseFunc();  // 創建SQLite數據庫void CreateTableFunc();     // 創建SQLite數據表void QueryTableFunc();      // 執行查詢操作QSqlDatabase sqldb;         // 創建Qt和數據庫鏈接QSqlQueryModel *model=nullptr;//用來存儲數據
private:Ui::StudentDlg *ui;};
#endif // STUDENTDLG_H
  • 類實現
#include "studentdlg.h"
#include "ui_studentdlg.h"
#include<QSortFilterProxyModel>StudentDlg::StudentDlg(QWidget *parent): QDialog(parent), ui(new Ui::StudentDlg)
{ui->setupUi(this);// 調用函數創建且打開數據庫CreateDatabaseFunc();// 調用函數創建數據表CreateTableFunc();
}StudentDlg::~StudentDlg()
{delete ui;
}void StudentDlg::CreateDatabaseFunc()  // 創建SQLite數據庫
{// 1:添加數據庫驅動sqldb=QSqlDatabase::addDatabase("QSQLITE");// 2:設置數據庫名稱sqldb.setDatabaseName("studentmis.db");// 3:打開此數據庫是否成功if(sqldb.open()==true){QMessageBox::information(0,"正確","恭喜你,數據庫打開成功!",QMessageBox::Ok);}else{QMessageBox::critical(0,"錯誤","數據庫打開失敗,請重新檢測!",QMessageBox::Ok);}
}void StudentDlg::CreateTableFunc()     // 創建SQLite數據表
{QSqlQuery createquery;// 創建SQL語句QString strsql=QString("CREATE TABLE IF NOT EXISTS student(""id int primary key not null,""name text not null,""score real not null)");// 執行SQL語句if(createquery.exec(strsql)==false){QMessageBox::critical(0,"失敗","數據表創建失敗,請重新檢查!",QMessageBox::Ok);}else{QMessageBox::information(0,"成功","恭喜你,數據表創建成功!",QMessageBox::Ok);}// 準備數據模型model = new QSqlQueryModel();model->setQuery("SELECT id, name, score FROM student"); // 執行查詢// 將數據模型與QTableView綁定//QTableView *tableView = new QTableView();ui-> tableView->setModel(model);ui->tableView->resizeColumnsToContents(); // 調整列寬度使數據能夠完全顯示// 顯示QTableViewui->tableView->show();}
void StudentDlg::QueryTableFunc()      // 執行查詢操作
{QSqlQuery query;query.exec("SELECT * FROM users");while(query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();double score = query.value(2).toDouble();qDebug() << "ID:" << id << " Name:" << name << " Score:" << score;}}void StudentDlg::on_pushButtonSort_clicked()
{//    QSortFilterProxyModel *sortModel = new QSortFilterProxyModel(this);
//    sortModel->setSourceModel(model);//    // 設置排序的列索引
//    int sortColumn = 1; // 假設要按第1列排序
//    sortModel->sort(sortColumn, Qt::DescendingOrder); // 進行升序排序//    // 將排序后的模型設置給視圖
//    ui->tableView->setModel(sortModel);//    //使用sql語句進行操作
//    QSqlQuery query;
//    query.exec("SELECT id ,name ,score  FROM student ORDER BY id DESC");//更新數據庫中的數據model->setQuery("SELECT id, name, score FROM student ORDER BY id DESC");//model->setQuery("SELECT * FROM student");ui->tableView->viewport()->update();
}void StudentDlg::on_pushButton_INSERT_clicked()
{QSqlQuery sqlquery;int id=ui->lineEdit_ID->text().toInt();if(id==0){QMessageBox::critical(this,"失敗","提示:輸入錯誤?學號不能為0?",QMessageBox::Ok);return ;}QString name=ui->lineEdit_NAME->text();if(name==""){QMessageBox::critical(this,"失敗","提示:輸入錯誤?姓名不能為空?",QMessageBox::Ok);return ;}double score=ui->lineEdit_SCORE->text().toDouble();if(score<0 || score>100){QMessageBox::critical(this,"失敗","提示:輸入錯誤?分數范圍(0-100)?",QMessageBox::Ok);return ;}QString strs=QString("insert into student ""values(%1,'%2',%3)").arg(id).arg(name).arg(score);if(sqlquery.exec(strs)==false){QMessageBox::critical(0,"失敗","向數據表插入記錄失敗,請重新檢查!",QMessageBox::Ok);}else{QMessageBox::information(0,"成功","恭喜你,向數據表插入記錄成功!",QMessageBox::Ok);}}void StudentDlg::on_pushButton_DELETE_clicked()
{int id = ui->lineEdit_ID->text().toInt();QSqlQuery query;query.prepare("DELETE FROM student WHERE id = :id");  // 設置刪除語句query.bindValue(":id", id);  // 綁定條件值bool success = query.exec();  // 執行刪除操作if(success) {// 刪除成功} else {// 刪除失敗,處理錯誤qDebug() << "Error:" << query.lastError().text();}//更新數據庫中的數據model->setQuery("SELECT * FROM student");ui->tableView->viewport()->update();
}void StudentDlg::on_pushButton_UPDATE_clicked()
{// 執行 UPDATE 操作QString New_Name=ui->lineEdit_NAME->text();int id=ui->lineEdit_ID->text().toUInt();QSqlQuery query;query.prepare("UPDATE student SET name = :newName WHERE id = :id");query.bindValue(":newName", New_Name); // 設置要更新的新名稱query.bindValue(":id", id); // 設置要更新的記錄的 IDif (query.exec()) {qDebug() << "Update successful";} else {qDebug() << "Update failed:" << query.lastError().text();}}void StudentDlg::on_pushButton_SEARCH_clicked()
{QSqlQuery query;query.exec("SELECT * FROM student");while(query.next()) {int id = query.value(0).toInt();QString name = query.value(1).toString();double score = query.value(2).toDouble();qDebug() << "ID:" << id << " Name:" << name << " Score:" << score;}//更新數據庫中的數據model->setQuery("SELECT * FROM student");ui->tableView->viewport()->update();
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/41876.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/41876.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/41876.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【海賊王的數據航海】ST表——RMQ問題

目錄 1 -> RMQ問題 1.1 -> 定義 1.2 -> 解決策略 2 -> ST表 2.1 -> 定義 2.2 什么是可重復貢獻問題 2.3 -> 預處理ST表 2.4 -> 處理查詢 2.5 -> 實際問題 1 -> RMQ問題 1.1 -> 定義 RMQ (Range Minimum/Maximum Query)即區間最值查詢…

Go 語言多版本管理的最佳實踐 —— Linux 和 Windows 專題20240702

Go 語言多版本管理的最佳實踐 —— Linux 和 Windows 專題 引言 在軟件開發的世界里&#xff0c;保持開發環境的最新和兼容至關重要。特別是 Go 語言&#xff0c;隨著版本的更新&#xff0c;不同項目可能需要不同的 Go 版本。這時&#xff0c;如何在同一臺機器上高效管理多個…

黑馬點評DAY2|Redis基本操作

Redis客戶端 命令行客戶端 進入到redis的安裝目錄&#xff0c;可以看到redis-cli文件&#xff0c;這就是redis的命令行客戶端&#xff0c;在安裝redis時自帶的。 使用方式如下 redis-cli [options] [commonds]其中常見的options有&#xff1a; -h 127.0.0.1 &#xff1a;指…

電量監測與電量計基礎知識

硬件之路學習筆記 ?-----前文導讀----- ①、公眾號主頁點擊發消息 ②、點擊下方菜單獲取系列文章 -----本文簡介----- 主要內容包括&#xff1a; ①&#xff1a;簡介 ②&#xff1a;省成本方式-電阻分壓 ③&#xff1a;精確方式-電量計與阻抗跟蹤技術 ----- 正文 ----…

Hugging face Transformers(1)—— 基礎知識

Hugging Face 是一家在 NLP 和 AI 領域具有重要影響力的科技公司&#xff0c;他們的開源工具和社區建設為NLP研究和開發提供了強大的支持。它們擁有當前最活躍、最受關注、影響力最大的 NLP 社區&#xff0c;最新最強的 NLP 模型大多在這里發布和開源。該社區也提供了豐富的教程…

JavaWeb--jquery篇

概述 jQuery是一個快速、簡潔的JavaScript框架&#xff0c;是一個優秀的JavaScript代碼庫&#xff08;框架&#xff09;于2006年1月由John Resig發布。它封裝JavaScript常用的功能代碼&#xff0c;提供一種簡便的JavaScript設計模式&#xff0c;優化HTML文檔操作、事件處理、動…

2229:Sumsets

網址如下&#xff1a; OpenJudge - 2229:Sumsets 這題不是我想出來的 在這里僅做記錄 代碼如下&#xff1a; #include<iostream> using namespace std;const int N 1000000000; int dp[1000010]; int n;int main() {cin >> n;dp[0] 1;dp[1] 1;for (int i 2…

前端面試題7(單點登錄)

如何實現單點登錄 單點登錄&#xff08;Single Sign-On&#xff0c;簡稱SSO&#xff09;是一種允許用戶在多個應用系統中只需登錄一次&#xff0c;就可以訪問所有相互信任的應用系統的認證技術。實現前端單點登錄主要依賴于后端的支持和一些特定的協議&#xff0c;如OAuth、Ope…

無法下載cuda

cuda下載不了 一、臺式機電腦瀏覽器打不開cuda下載下面二、解決辦法 一、臺式機電腦瀏覽器打不開cuda下載下面 用360、chrome、Edge瀏覽器都打不開下載頁面&#xff0c;有的人說后綴com改成cn&#xff0c;都不行。知乎上說是網絡問題&#xff0c;電信換成換成移動/聯通的網絡會…

Selenium 切換 frame/iframe

環境&#xff1a; Python 3.8 selenium3.141.0 urllib31.26.19說明&#xff1a; driver.switch_to.frame() # 將當前定位的主體切換為frame/iframe表單的內嵌頁面中 driver.switch_to.default_content() # 跳回最外層的頁面# 判斷元素是否在 frame/ifame 中 # 126 郵箱為例 # …

無人機云臺類型及作用

無人機云臺主要分為三種類型&#xff1a; 單軸云臺&#xff1a;僅支持單向旋轉&#xff0c;適合拍攝平滑的延時攝影和全景照片。 雙軸云臺&#xff1a;支持水平和垂直旋轉&#xff0c;可用于拍攝流暢的視頻和運動物體。 三軸云臺&#xff1a;全面支持所有旋轉軸&#xff0c;…

醫院陪診系統開發的關鍵技術與挑戰

隨著醫療服務需求的不斷提升&#xff0c;傳統的醫院服務模式面臨著巨大的壓力和挑戰。為了提升患者的就醫體驗和醫療服務的效率&#xff0c;醫院陪診系統應運而生。本文將探討醫院陪診系統開發的關鍵技術與挑戰&#xff0c;并結合具體的技術代碼進行分析。 一、醫院陪診系統的…

什么是可定制的鋰電池?它的應用范圍有哪些?

鋰電池在新能源汽車領域已經得到了廣泛的應用。然而&#xff0c;隨著科技的不斷進步和人們對于個性化需求的日益增長&#xff0c;可定制的鋰電池逐漸成為了市場的新寵。那么&#xff0c;究竟什么是可定制的鋰電池&#xff1f;它與普通鋰電池有何不同&#xff1f;它的應用范圍又…

android——設計模式(工廠模式)

一、工廠模式 Android 設計模式中的工廠模式是一種創建型設計模式&#xff0c;它提供了一種創建對象的最佳方式&#xff0c;而不必暴露其內部的創建邏輯。在Android中&#xff0c;工廠模式通常用于管理復雜組件實例化的過程&#xff0c;比如創建各種View、Activity、Fragment等…

Docker實戰教程(二)

文章目錄 基于Docker的微服務架構案例一、準備工作二、服務定義1. 用戶服務(User Service)2. 訂單服務(Order Service)3. 前端服務(Frontend Service)三、Docker Compose文件四、啟動微服務架構五、常見問題和解決方案六、總結基于Docker的微服務架構案例 在本案例中,我…

悠律凝聲環開放式耳機強者現身:集顏值和創新技術于一體的杰作

隨著技術的飛速發展&#xff0c;藍牙耳機已經成為人們生活中不可缺少的一環&#xff0c;外觀、音質以及實用性已經成為人們在購買時最主要的考慮因素。悠律凝聲環RingBuds Pro開放式藍牙耳機&#xff0c;憑借其特有的輕奢時尚外觀&#xff0c;斬獲2024年度MUSE繆斯創意獎金獎&a…

Android SeekBar設置指示器標簽,使用PopupWindow的方式

給Android 原生的SeekBar控件添加一個指示器標簽&#xff1b;記錄一下 按下時彈出popupwindow&#xff0c;進度條更新時刷新pw&#xff0c;松開時關閉pw&#xff1b; public class SeekBarPopUtils {private static PopupWindow popWin null;private static ConstraintLayou…

Kotlin協程使用詳解

協程是什么 協程是一種編程思想,并不局限于特定的語言。協程是輕量級的線程,基于線程池API,通俗的來說,就是官方提供的線程框架。協程的調度完全由用戶控制。協程擁有自己的寄存器上下文和棧。當我們在了解協程的時候,不可避免的會跟線程、進程作比較作分析,下面來貼個圖…

數據可視化之智慧城市的脈動與洞察

在數字化轉型的浪潮中,城市作為社會經濟發展的核心單元,正經歷著前所未有的變革。城市數據可視化大屏看板作為這一變革中的重要工具,不僅極大地提升了城市管理效率,還為公眾提供了直觀、全面的城市運行狀態視圖,成為智慧城市建設不可或缺的一部分。本文將深入探討以“城市…

ruoyi后臺修改

一、日志文件過大分包 \ruoyi-admin\src\main\resources\logback.xml <!-- 系統日志輸出 --> <appender name"file_info" class"ch.qos.logback.core.rolling.RollingFileAppender"><file>${log.path}/sys-info.log</file><!…