Qt實戰:使用QSqlDatabase連接MySQL,并實現增刪改查

文章目錄

    • 一、創建數據表
    • 二、連接MySQL數據庫
    • 三、封裝成一個完整的輕量級 ORM 風格類
    • 四、實現派生具體模型類
    • 五、支持多線程連接池 + ORM + 事務封裝

一、創建數據表

數據庫名:
我們先創建一個數據庫,名字叫 game_db:

CREATE DATABASE IF NOT EXISTS game_db DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_general_ci;
USE game_db;

創建玩家表:players

CREATE TABLE players (player_id INT AUTO_INCREMENT PRIMARY KEY,username VARCHAR(32) NOT NULL UNIQUE,password_hash VARCHAR(64) NOT NULL,nickname VARCHAR(32),level INT DEFAULT 1,experience INT DEFAULT 0,gold INT DEFAULT 0,created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);

插入 20 條玩家信息 SQL 語句:

INSERT INTO players (username, password_hash, nickname, level, experience, gold) VALUES
('user001', MD5('password1'), 'Knight001', 5, 1200, 500),
('user002', MD5('password2'), 'Mage002', 3, 800, 300),
('user003', MD5('password3'), 'Archer003', 7, 1800, 750),
('user004', MD5('password4'), 'Rogue004', 2, 400, 100),
('user005', MD5('password5'), 'Cleric005', 10, 3200, 1200),
('user006', MD5('password6'), 'Paladin006', 4, 950, 400),
('user007', MD5('password7'), 'Hunter007', 6, 1400, 600),
('user008', MD5('password8'), 'Druid008', 8, 2200, 900),
('user009', MD5('password9'), 'Monk009', 9, 2500, 1000),
('user010', MD5('password10'), 'Barbarian010', 1, 100, 50),
('user011', MD5('password11'), 'Warrior011', 5, 1300, 550),
('user012', MD5('password12'), 'Sorcerer012', 3, 700, 300),
('user013', MD5('password13'), 'Assassin013', 6, 1600, 650),
('user014', MD5('password14'), 'Priest014', 7, 1900, 800),
('user015', MD5('password15'), 'Ranger015', 2, 500, 200),
('user016', MD5('password16'), 'Berserker016', 4, 1100, 450),
('user017', MD5('password17'), 'Necromancer017', 8, 2300, 950),
('user018', MD5('password18'), 'Templar018', 9, 2700, 1100),
('user019', MD5('password19'), 'Shaman019', 10, 3000, 1250),
('user020', MD5('password20'), 'Witch020', 1, 200, 100);

表中結果如下所示:
在這里插入圖片描述

二、連接MySQL數據庫

database_manager.h

#ifndef DATABASEMANAGER_H
#define DATABASEMANAGER_H#include <QObject>
#include <QMutex>
#include <QSqlDatabase>
#include <QSqlError>enum DatabaseType {MySQL = 0,SQLite,PostgreSQL,// 可擴展更多類型
};typedef struct stConnectParams {DatabaseType dbType;QString strHostName;QString strDbName;QString strUserName;QString strPassword;QString strConnectionName;int port;
} ConnectParams;class DatabaseManager : public QObject
{Q_OBJECT
public:static DatabaseManager& instance();void initConnectionParams(const ConnectParams& connectParams);void initializeConnection();private:explicit DatabaseManager(QObject *parent = nullptr);~DatabaseManager();DatabaseManager(const DatabaseManager&) = delete;DatabaseManager& operator =(const DatabaseManager&) = delete;DatabaseManager(const DatabaseManager&&) = delete;DatabaseManager& operator =(const DatabaseManager&&) = delete;signals:private:ConnectParams m_connectParams;
};

database_manager.cpp

#include "database_manager.h"#include <QDebug>DatabaseManager::DatabaseManager(QObject *parent) : QObject(parent)
{}DatabaseManager::~DatabaseManager()
{}DatabaseManager& DatabaseManager::instance()
{static DatabaseManager instance;return instance;
}void DatabaseManager::initConnectionParams(const ConnectParams& connectParams)
{m_connectParams.dbType = connectParams.dbType;m_connectParams.strHostName = connectParams.strHostName;m_connectParams.strDbName = connectParams.strDbName;m_connectParams.strUserName = connectParams.strUserName;m_connectParams.strPassword = connectParams.strPassword;m_connectParams.strConnectionName = connectParams.strConnectionName;m_connectParams.port = connectParams.port;
}void DatabaseManager::initializeConnection()
{if (QSqlDatabase::contains(m_connectParams.strConnectionName)) {qDebug() << "db:" << m_connectParams.strConnectionName << "already connected";return;}QString strDriver;switch (m_connectParams.dbType) {case DatabaseType::SQLite:strDriver = "QSQLITE";break;case DatabaseType::MySQL:strDriver = "QMYSQL";break;case DatabaseType::PostgreSQL:strDriver = "QPSQL";break;}if (strDriver.isEmpty()) {qDebug() << "can't find driver";return;}QSqlDatabase db = QSqlDatabase::addDatabase(strDriver, m_connectParams.strConnectionName);if (m_connectParams.dbType == DatabaseType::SQLite) {db.setDatabaseName(m_connectParams.strDbName); // SQLite只需數據庫文件路徑} else {db.setConnectOptions("MYSQL_OPT_CONNECT_TIMEOUT=5;""MYSQL_OPT_READ_TIMEOUT=5;""MYSQL_OPT_WRITE_TIMEOUT=5;");db.setHostName(m_connectParams.strHostName);db.setPort(m_connectParams.port);db.setDatabaseName(m_connectParams.strDbName);db.setUserName(m_connectParams.strUserName);db.setPassword(m_connectParams.strPassword);}if (!db.open()) {qDebug() << "Database connection failed:" << db.lastError().text();} else {qDebug() << "Database connected successfully!";}
}

三、封裝成一個完整的輕量級 ORM 風格類

什么是ORM 模型類的?
ORM(Object-Relational Mapping)模型類的作用,是將數據庫中的表與 C++(或其他語言)中的類進行映射和封裝,讓你能像操作普通對象那樣操作數據庫數據,避免直接拼接 SQL 字符串,提高代碼的可讀性、可維護性、安全性和抽象性。

ORM 模型類的作用總結如下:
3.1 表結構 → 類結構
ORM 會把數據庫表(如 users)映射成一個類(如 User),表字段對應類成員或字段名:

// 數據庫表字段
// id | name | age// ORM類字段
QVariantMap row;
row["id"] = 1;
row["name"] = "Alice";
row["age"] = 30;

3.2 簡化 SQL 操作
讓你寫這樣的代碼:

userModel.insert({{"name", "Tom"}, {"age", 25}});

而不需要寫繁瑣的 SQL:

INSERT INTO users (name, age) VALUES ('Tom', 25);

目標功能:

  • 封裝成類 OrmModel 或基類 OrmBase
  • 支持設置數據庫連接、表名
  • 支持 select / insert / update / delete 等基礎操作
  • 使用 QVariantMap 傳入/返回數據
  • ORM風格:調用 model.select(…) 而不是手寫 SQL 字符串

類定義:OrmBase

#ifndef DBORMBASE_H
#define DBORMBASE_H#include <QObject>
#include <QSqlDatabase>
#include <QVariantMap>
#include <QVariantList>class DbOrmBase : public QObject
{Q_OBJECT
public:explicit DbOrmBase(const QString &tableName, const QString &connectionName);~DbOrmBase();// CRUDQVariantList select(const QString &strWhereClause = "", const QStringList &columns = {});bool insert(const QVariantMap &values);bool update(const QVariantMap &values, const QString &strWhereClause);bool remove(const QString &strWhereClause);private:bool isConnected() const;private:QString m_tableName;QString m_connectionName;QSqlDatabase m_db; // 保存數據庫實例
};#endif // DBORMBASE_H

類實現:OrmBase.cpp

#include "OrmBase.h"
#include <QSqlQuery>
#include <QSqlError>
#include <QSqlRecord>
#include <QDebug>OrmBase::OrmBase(const QString &tableName, const QString &connectionName): m_tableName(tableName), m_connectionName(connectionName)
{}QVariantList OrmBase::select(const QString &whereClause, const QStringList &columns)
{QVariantList results;QSqlDatabase db = QSqlDatabase::database(m_connectionName);if (!db.isOpen()) {qDebug() << "Database not open";return results;}QString columnStr = columns.isEmpty() ? "*" : columns.join(", ");QString sql = QString("SELECT %1 FROM %2").arg(columnStr, m_tableName);if (!whereClause.trimmed().isEmpty()) {sql += " WHERE " + whereClause;}QSqlQuery query(db);if (!query.exec(sql)) {qDebug() << "Select failed:" << query.lastError().text();return results;}while (query.next()) {QVariantMap row;QSqlRecord rec = query.record();for (int i = 0; i < rec.count(); ++i) {row[rec.fieldName(i)] = query.value(i);}results << row;}return results;
}bool OrmBase::insert(const QVariantMap &values)
{QSqlDatabase db = QSqlDatabase::database(m_connectionName);if (!db.isOpen()) return false;QStringList columns, placeholders;QVariantList bindValues;for (auto it = values.begin(); it != values.end(); ++it) {columns << it.key();placeholders << "?";bindValues << it.value();}QString sql = QString("INSERT INTO %1 (%2) VALUES (%3)").arg(m_tableName).arg(columns.join(", ")).arg(placeholders.join(", "));QSqlQuery query(db);query.prepare(sql);for (const QVariant &val : bindValues) {query.addBindValue(val);}if (!query.exec()) {qDebug() << "Insert failed:" << query.lastError().text();return false;}return true;
}bool OrmBase::update(const QVariantMap &values, const QString &whereClause)
{QSqlDatabase db = QSqlDatabase::database(m_connectionName);if (!db.isOpen()) return false;QStringList sets;QVariantList bindValues;for (auto it = values.begin(); it != values.end(); ++it) {sets << QString("%1 = ?").arg(it.key());bindValues << it.value();}QString sql = QString("UPDATE %1 SET %2").arg(m_tableName, sets.join(", "));if (!whereClause.trimmed().isEmpty()) {sql += " WHERE " + whereClause;}QSqlQuery query(db);query.prepare(sql);for (const QVariant &val : bindValues) {query.addBindValue(val);}if (!query.exec()) {qDebug() << "Update failed:" << query.lastError().text();return false;}return true;
}bool OrmBase::remove(const QString &whereClause)
{QSqlDatabase db = QSqlDatabase::database(m_connectionName);if (!db.isOpen()) return false;QString sql = QString("DELETE FROM %1").arg(m_tableName);if (!whereClause.trimmed().isEmpty()) {sql += " WHERE " + whereClause;}QSqlQuery query(db);if (!query.exec(sql)) {qDebug() << "Delete failed:" << query.lastError().text();return false;}return true;
}

使用示例:

#include <QCoreApplication>
#include <QDebug>
#include <QDateTime>#include "database_manager.h"
#include "db_ormbase.h"int main(int argc, char *argv[])
{QCoreApplication a(argc, argv);ConnectParams connectParams;connectParams.dbType = DatabaseType::MySQL;connectParams.strHostName = "localhost";connectParams.strDbName = "game_db";connectParams.strUserName = "root";connectParams.strPassword = "root";connectParams.strConnectionName = "user_game";connectParams.port = 3306;DatabaseManager::instance().initConnectionParams(connectParams);DatabaseManager::instance().initializeConnection();DbOrmBase userModel("players", "user_game");QVariantList playerList =  userModel.select("experience > 1000");for (const QVariant &playerVar : playerList) {QVariantMap playerMap = playerVar.toMap();int playerId = playerMap.value("player_id").toInt();QString username = playerMap.value("username").toString();QString nickname = playerMap.value("nickname").toString();int level = playerMap.value("level").toInt();int experience = playerMap.value("experience").toInt();int gold = playerMap.value("gold").toInt();QString passwordHash = playerMap.value("password_hash").toString();QDateTime createdAt = playerMap.value("created_at").toDateTime();// 可以進行打印、顯示、或保存到類對象中qDebug() << "ID:" << playerId<< "用戶名:" << username<< "昵稱:" << nickname<< "等級:" << level<< "經驗:" << experience<< "金幣:" << gold<< "密碼Hash:" << passwordHash<< "創建時間:" << createdAt.toString(Qt::ISODate);}return a.exec();
}

輸出結果:
在這里插入圖片描述

四、實現派生具體模型類

為什么要派生?
雖然 OrmBase 已支持通用 CRUD,但派生后的 UserModel 能實現:

  • 指定固定表名(如 players)
  • 添加和 players 表相關的專屬函數(如 getAdultUsers()、findByName())
  • 讓調用更具語義:UserModel user; user.insert(…)

創建 UserModel 類
UserModel.h

#ifndef USERMODEL_H
#define USERMODEL_H#include "OrmBase.h"class UserModel : public OrmBase
{
public:explicit UserModel(const QString &connectionName = "default");// 自定義業務函數QVariantList getAdultUsers();QVariantMap findById(int id);QVariantList findByName(const QString &name);
};#endif // USERMODEL_H

UserModel.cpp

#include "UserModel.h"UserModel::UserModel(const QString &connectionName): OrmBase("players", connectionName) // 固定表名為 users
{}// 查詢年齡 >= 18 的用戶
QVariantList UserModel::getAdultUsers()
{return select("experience >= 1000", {"player_id", "username", "experience"});
}// 查詢某個 ID 的用戶(返回一行)
QVariantMap UserModel::findById(int id)
{auto results = select(QString("player_id = %1").arg(id));return results.isEmpty() ? QVariantMap() : results.first().toMap();
}// 查詢某個名字的所有用戶
QVariantList UserModel::findByName(const QString &name)
{QString clause = QString("username = '%1'").arg(name.replace("'", "''")); // 簡單防注入return select(clause);
}

五、支持多線程連接池 + ORM + 事務封裝

將構建以下組件:

+-------------------------+
| DBConnectionPool       | 線程安全連接池類(單例)
+-------------------------+
| OrmBase                | ORM 基類(封裝表操作 + 自動獲取線程連接)
+-------------------------+
| OrmManager             | 管理多個模型,支持事務封裝
+-------------------------+
| XxxModel : OrmBase     | 表模型(如 UserModel)
+-------------------------+

5.1 線程安全數據庫連接池:DBConnectionPool
DBConnectionPool.h

#ifndef DBCONNECTIONPOOL_H
#define DBCONNECTIONPOOL_H#include <QSqlDatabase>
#include <QMutex>
#include <QMap>
#include <QThreadStorage>class DBConnectionPool
{
public:static DBConnectionPool &instance();void init(const QString &driver,const QString &host,int port,const QString &dbName,const QString &user,const QString &password,int maxConn = 10);QSqlDatabase getConnection();void closeAll();private:DBConnectionPool() = default;Q_DISABLE_COPY(DBConnectionPool)QString m_driver, m_host, m_dbName, m_user, m_password;int m_port = 3306;int m_maxConn = 10;QMutex m_mutex;int m_connIndex = 0;QThreadStorage<QString> m_threadConnName;
};#endif // DBCONNECTIONPOOL_H

DBConnectionPool.cpp

#include "DBConnectionPool.h"
#include <QSqlDatabase>
#include <QSqlError>
#include <QDebug>DBConnectionPool &DBConnectionPool::instance()
{static DBConnectionPool pool;return pool;
}void DBConnectionPool::init(const QString &driver,const QString &host,int port,const QString &dbName,const QString &user,const QString &password,int maxConn)
{m_driver = driver;m_host = host;m_port = port;m_dbName = dbName;m_user = user;m_password = password;m_maxConn = maxConn;
}QSqlDatabase DBConnectionPool::getConnection()
{if (!m_threadConnName.hasLocalData()) {QMutexLocker locker(&m_mutex);QString connName = QString("conn_%1").arg(++m_connIndex);m_threadConnName.setLocalData(connName);QSqlDatabase db = QSqlDatabase::addDatabase(m_driver, connName);db.setHostName(m_host);db.setPort(m_port);db.setDatabaseName(m_dbName);db.setUserName(m_user);db.setPassword(m_password);db.setConnectOptions("MYSQL_OPT_CONNECT_TIMEOUT=5;""MYSQL_OPT_RECONNECT=1");if (!db.open()) {qCritical() << "Failed to open DB:" << db.lastError().text();}}return QSqlDatabase::database(m_threadConnName.localData());
}void DBConnectionPool::closeAll()
{QMutexLocker locker(&m_mutex);for (int i = 1; i <= m_connIndex; ++i) {QString name = QString("conn_%1").arg(i);if (QSqlDatabase::contains(name)) {QSqlDatabase::removeDatabase(name);}}m_connIndex = 0;
}

5.2 ORM 基類 OrmBase(使用連接池)

class OrmBase
{
public:OrmBase(const QString &tableName);virtual ~OrmBase() = default;bool insert(const QVariantMap &values);QVariantList select(const QString &whereClause = "", const QStringList &columns = {});bool update(const QVariantMap &values, const QString &whereClause);bool remove(const QString &whereClause);QSqlDatabase db() const;protected:QString m_tableName;
};

關鍵點:OrmBase 中不再保存 QSqlDatabase 實例,而是每次從線程池中獲取:

QSqlDatabase OrmBase::db() const
{return DBConnectionPool::instance().getConnection();
}

5.3 事務封裝類 OrmManager
用于封裝如下邏輯:

  • beginTransaction()
  • commit()
  • rollback()
class OrmManager
{
public:static bool beginTransaction();static bool commit();static bool rollback();
};

實現:

bool OrmManager::beginTransaction()
{QSqlDatabase db = DBConnectionPool::instance().getConnection();return db.transaction();
}bool OrmManager::commit()
{QSqlDatabase db = DBConnectionPool::instance().getConnection();return db.commit();
}bool OrmManager::rollback()
{QSqlDatabase db = DBConnectionPool::instance().getConnection();return db.rollback();
}

5.4 使用示例:線程內事務 + 多表操作

DBConnectionPool::instance().init("QMYSQL", "127.0.0.1", 3306, "testdb", "root", "123456");UserModel user;
OrderModel order;OrmManager::beginTransaction();
bool ok1 = user.insert({{"name", "Tom"}});
bool ok2 = order.insert({{"user_id", 1}, {"amount", 200.0}});
if (ok1 && ok2)OrmManager::commit();
elseOrmManager::rollback();

5.5 線程使用示例(多線程安全)

QtConcurrent::run([](){UserModel u;u.insert({{"name", "ThreadUser"}});
});

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

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

相關文章

Python腳本保護工具庫之pyarmor使用詳解

概要 PyArmor是一個專門為Python代碼提供加密保護的第三方庫,旨在解決Python源代碼易被反編譯和泄露的安全問題。作為一種動態代碼保護工具,PyArmor能夠對Python腳本進行混淆和加密處理,有效防止源代碼被惡意獲取、分析或篡改。該庫特別適用于商業軟件開發、知識產權保護和…

倉頡編程語言:從入門到精通

為啥要瞅瞅倉頡這玩意兒&#xff1f; 有一說一&#xff0c;現在的編程語言多得跟米一樣&#xff0c;對吧&#xff1f;那一門新語言想火&#xff0c;沒點絕活兒肯定不行。倉頡&#xff08;Cangjie&#xff09;這哥們兒&#xff0c;是華為搞出來的新玩意兒&#xff0c;靜態編譯的…

線性探針是什么:是一種用于探測神經網絡中特定特征的工具

線性探針是什么 線性探針是一種在機器學習和相關領域廣泛應用的技術,用于評估預訓練模型特征、檢測數據中的特定序列等。在不同的應用場景下,線性探針有著不同的實現方式和作用: 評估預訓練模型特征:在機器學習中,線性探針是一種評估預訓練模型“特征遷移能力”的標準化方…

【論文閱讀】Few-Shot PPG Signal Generation via Guided Diffusion Models

從少量樣本數據選擇到后處理的整體框架。首先,擴散模型在N樣本數據集和指導下的訓練。接著,模型生成一個增強的數據集,并進一步優化以提高保真度。最后,這些合成數據與少量樣本訓練數據集結合,用于基準模型的訓練和評估。數據分布從最初的紅色變為保真度增強的藍色,這表明…

CentOS-7的“ifupdown“與Debian的“ifupdown“對比 筆記250706

CentOS-7的"ifupdown"與Debian的"ifupdown"對比 筆記250706 CentOS 7 和 Debian 的 ifupdown 工具名稱相同&#xff0c;但在實現機制、配置文件語法和系統集成上存在顯著差異。以下是核心對比分析&#xff1a; ?? 一、核心差異概覽 對比維度CentOS 7De…

架構如傳承:技術長河中的可持續樂章

代碼結構&#xff1a;協作基石 在軟件開發的世界里&#xff0c;代碼結構就如同建筑的框架&#xff0c;支撐著整個項目的運行。想象一下&#xff0c;你加入了一個新的開發團隊&#xff0c;接手一個已經有一定規模的項目。當你打開代碼庫&#xff0c;看到的是一團亂麻般的代碼&a…

Ubuntu22.04更新Openssh至9.9p2無法正常連接,報錯解決

Ubuntu22.04更新Openssh至9.9p2無法正常連接&#xff0c;報錯解決 1.報錯信息如下所示ExecStart/usr/sbin/sshd -D $SSHD_OPTS (codeexited, status255/EXCEPTION)2.這通常說明 SSH 配置文件存在語法錯誤、缺失關鍵文件&#xff0c;或者端口被占用等問題。 3.檢查配置文件是否有…

基于小程序的智能停車管理系統設計與開發

項目介紹 本課程演示的是一款基于小程序的智能停車管理系統設計與開發&#xff0c;主要針對計算機相關專業的正在做畢設的學生與需要項目實戰練習的 Java 學習者。 1.包含&#xff1a;項目源碼、項目文檔、數據庫腳本、軟件工具等所有資料 2.帶你從零開始部署運行本套系統 3…

多模態大語言模型arxiv論文略讀(155)

Panther: Illuminate the Sight of Multimodal LLMs with Instruction-Guided Visual Prompts ?? 論文標題&#xff1a;Panther: Illuminate the Sight of Multimodal LLMs with Instruction-Guided Visual Prompts ?? 論文作者&#xff1a;Honglin Li, Yuting Gao, Chengl…

SAP ERP與Oracle EBS對比,兩個ERP系統有什么區別?

據統計&#xff0c;2024年中國ERP軟件市場規模預計突破210億元&#xff0c;其中SAP和Oracle占據第一梯隊&#xff0c;共占國內ERP市場45%以上的份額&#xff0c;在高端市場尤其顯著。SAP和Oracle作為ERP行業的兩大巨頭&#xff0c;具體有什么區別呢&#xff1f;SAP是什么&#…

網絡安全之RCE分析與利用詳情

Gogs背景介紹Gogs&#xff08;Go Git Service&#xff09;是一款用Go語言編寫的輕量級、開源的Git倉庫托管系統。它的設計目標是讓搭建和維護Git服務變得簡單、快速&#xff0c;同時提供類似GitHub的功能&#xff0c;但對資源消耗更少&#xff0c;適合個人或者小型團隊使用&…

OpenCV圖片操作100例:從入門到精通指南(2)

接上篇&#xff0c;本文將繼續分享OpenCV實用技巧&#xff0c;涵蓋圖像處理、目標檢測、3D視覺等進階領域&#xff01;六、圖像變換進階17. 圖像金字塔# 高斯金字塔下采樣 smaller cv2.pyrDown(img)# 高斯金字塔上采樣 larger cv2.pyrUp(img)用于多尺度圖像處理&#xff0c;構…

2、Connecting to Kafka

KafkaAdmin-請參閱配置主題ProducerFactory-請參閱發送消息ConsumerFactory-請參閱接收消息從2.5版本開始&#xff0c;每個版本都擴展了KafkaResourceFactory。這允許在運行時通過向引導服務器的配置中添加Supplier<String>來更改引導服務器&#xff1a;setBootstrapServ…

二進制部署CentOS8.5+Kubernetes1.33.2+Docker28.3.1高可用集群

Kubernetes 集群部署202507 本實驗主要軟件環境及資源如下&#xff1a; 二進制部署CentOS8.5Kubernetes1.33.2Docker28.3.1高可用集群 一、系統要求 ?Kubermetes 系統由一組可執行程序組成&#xff0c;用戶可以通過Kubernetes在GitHub 的項目網站下載編譯好的二進制文件或…

127. Java 泛型 - 泛型類與子類型

文章目錄127. Java 泛型 - 泛型類與子類型1. 泛型類和接口的子類型化示例&#xff1a;ArrayList 和 List2. 自定義泛型接口的子類型化示例&#xff1a;泛型接口的子類型解釋3. 泛型類和接口的類型參數4. 總結127. Java 泛型 - 泛型類與子類型 1. 泛型類和接口的子類型化 在 J…

內網服務器怎么設置公網遠程訪問? windows桌面連接和Linux自帶SSH外網異地跨網用完整步驟教程

沒有公網IP的本地主機跨網訪問是經常需要用到的網絡場景。要設置內網服務器在公網進行異地遠程訪問&#xff0c;需依次完成確保網絡連接正常、配置防火墻、啟用遠程訪問服務、和利用類似nat123內網映射外網打通等一系列步驟&#xff0c;以保障不同內網的遠程訪問的順利進行。一…

數據提取之bs4(BeautifuSoup4)模塊與Css選擇器

BeautifuSoup4from bs4 import BeautifulSoup創建對象 <class bs4.BeautifulSoup>soup BeautifulSoup(源碼, 解析器)bs4標簽種類&#xff08;1&#xff09;tag: 標簽print(soup.title, type(soup.title))&#xff08;2&#xff09;獲取標簽里面的文本內容, 可導航的字符…

CPP中的List

一.list的介紹&#xff1a;1.list是可以在常數范圍內在任意位置進行插入和刪除的序列式容器&#xff0c;并且該容器可以前后雙向迭代。2.list的底層是雙向鏈表結構&#xff0c;帶有哨兵位的頭結點 。3. list與forward_list非常相似&#xff1a;最主要的不同在于forward_list是單…

Ntfs!LfsUpdateLfcbFromRestart函數分析之Ntfs!LfsFindOldestClientLsn

第0部分&#xff1a;//// Find the oldest client Lsn. Use the last flushed Lsn as a starting point.//Lfcb->OldestLsn Lfcb->LastFlushedLsn;LfsFindOldestClientLsn( RestartArea,Add2Ptr( RestartArea, Lfcb->ClientArrayOffset, PLFS_CLIENT_RECORD ),&…

「日拱一碼」021 機器學習——特征工程

目錄 特征選擇 過濾法&#xff08;Filter Methods&#xff09; 方差選擇法 相關系數法 卡方檢驗 包裹法&#xff08;Wrapper Methods&#xff09; 遞歸特征消除&#xff08;RFE&#xff09; 嵌入法&#xff08;Embedded Methods&#xff09; L1正則化&#xff08;Lasso…