主頁 > 後端開發 > Go 連接 MySQL之 MySQL 預處理

Go 連接 MySQL之 MySQL 預處理

2023-06-12 07:40:49 後端開發

Go 連接 MySQL之 MySQL 預處理

一、ChatGPT 關于 MySQL 預處理 的回答

問:什么是MySQL 的預處理 具體執行程序時什么

ChatGPT 答:

MySQL的預處理是一種在執行SQL陳述句之前,先進行編譯和優化的機制,它將SQL陳述句分成兩個階段:預處理階段和執行階段,

具體的執行程序如下:

  1. 預處理階段:
    • 應用程式發送SQL陳述句給MySQL服務器,將其中的引數部分用占位符(如?)代替,形成一個預處理陳述句,
    • MySQL服務器對預處理陳述句進行決議、編譯和優化,
    • 在這個階段,MySQL會檢查語法的正確性,創建執行計劃,以及進行權限驗證等,
  2. 執行階段:
    • 在預處理完成后,應用程式可以多次執行這個預處理陳述句,每次執行時只需提供具體的引數值,
    • 應用程式將具體的引數值系結到預處理陳述句的占位符上,
    • MySQL服務器使用系結的引數值執行預處理陳述句,并回傳執行結果,

預處理的好處包括:

  • 提高執行效率:預處理陳述句只需要編譯一次,后續的執行可以重復使用,避免了每次執行都要重新決議和編譯的開銷,
  • 防止SQL注入:通過使用引數化查詢,將引數值與SQL陳述句分開處理,可以防止惡意用戶利用輸入資料進行SQL注入攻擊,
  • 簡化引數處理:預處理陳述句可以通過占位符來接收引數,避免了手動拼接SQL陳述句的繁瑣和潛在的錯誤,

總結而言,MySQL的預處理是一種提前編譯和優化SQL陳述句的機制,它將SQL陳述句分為預處理和執行兩個階段,提高了執行效率和安全性,并簡化了引數處理程序,

問:Go實作MySQL預處理

ChatGPT 答:

在 Go 中,可以使用官方提供的 database/sql 包來實作 MySQL 的預處理,下面是一個示例代碼,展示了如何在 Go 中進行 MySQL 預處理:

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "username:password@tcp(hostname:port)/database")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 準備預處理陳述句
	stmt, err := db.Prepare("INSERT INTO users (name, age) VALUES (?, ?)")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	// 執行預處理陳述句
	name := "John"
	age := 30
	_, err = stmt.Exec(name, age)
	if err != nil {
		log.Fatal(err)
	}

	fmt.Println("Insert successful!")
}

在上述代碼中,我們使用 sql.Open 函式建立與 MySQL 資料庫的連接,然后使用 db.Prepare 函式準備預處理陳述句,其中 SQL 陳述句中的引數位置用占位符 ? 表示,接下來,通過 stmt.Exec 函式執行預處理陳述句,并傳入具體的引數值,最后,我們在 main 函式中進行了錯誤處理,并列印了插入成功的訊息,

請確保在代碼中填入正確的 MySQL 連接資訊(用戶名、密碼、主機名、埠號和資料庫名),以便與目標資料庫建立連接,同時,請根據實際的預處理陳述句和引數進行適當的修改,

注意:上述示例代碼僅演示了預處理的基本流程,并沒有包含完整的錯誤處理和其他功能,在實際應用中,建議加入適當的錯誤處理、事務處理等機制,以確保代碼的健壯性和安全性,

問:MySQL預處理適用于什么場景?

ChatGPT 答:

MySQL預處理適用于以下場景:

  1. 執行頻繁的重復查詢:如果應用程式需要多次執行相同的SQL查詢,但只是引數值不同,預處理可以減少服務器的作業量,預處理陳述句只需要編譯一次,后續的執行可以重復使用,避免了每次都重新決議和編譯SQL陳述句的開銷,
  2. 引數化查詢:當需要執行帶有引數的查詢時,預處理可以提高安全性并防止SQL注入攻擊,通過使用引數化查詢,將引數值與SQL陳述句分開處理,可以確保輸入資料被正確地轉義和處理,避免惡意用戶利用輸入資料進行攻擊,
  3. 提高性能:預處理可以在編譯和優化階段對SQL陳述句進行處理,生成更高效的執行計劃,這可以提高查詢的性能和回應時間,特別是對于復雜查詢或涉及大量資料的查詢,
  4. 簡化引數處理:預處理陳述句可以通過占位符(如?)來接收引數值,避免了手動拼接SQL陳述句的繁瑣和潛在的錯誤,同時,使用預處理陳述句可以直接將引數值系結到占位符上,而無需手動轉義和處理引數值,

總結而言,MySQL預處理適用于需要執行重復查詢、引數化查詢、提高性能和簡化引數處理的場景,它可以減少服務器的作業量,提高查詢的安全性和性能,并簡化代碼的撰寫和維護,

二、Go 實作 MySQL 預處理

查詢

package main

import (
	"database/sql"
	"fmt"
	"time"

	_ "github.com/go-sql-driver/mysql" // 匿名匯入 自動執行 init()
)

var db *sql.DB

func initMySQL() (err error) {
	//DSN (Data Source Name)
	dsn := "root:12345678@tcp(127.0.0.1:3306)/sql_test"
	// 注意:要初始化全域的 db 物件,不要新宣告一個 db 變數
	db, err = sql.Open("mysql", dsn) // 只對格式進行校驗,并不會真正連接資料庫
	if err != nil {
		return err
	}

	// Ping 驗證與資料庫的連接是否仍處于活動狀態,并在必要時建立連接,
	err = db.Ping()
	if err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
		return err
	}
	// 數值需要根據業務具體情況來確定
	db.SetConnMaxLifetime(time.Second * 10) // 設定可以重用連接的最長時間
	db.SetConnMaxIdleTime(time.Second * 5)  // 設定連接可能處于空閑狀態的最長時間
	db.SetMaxOpenConns(200)                 // 設定與資料庫的最大打開連接數
	db.SetMaxIdleConns(10)                  //  設定空閑連接池中的最大連接數
	return nil
}

type user struct {
	id   int
	age  int
	name string
}

// 預處理查詢
func prepareQueryDemo(id int) {
	sqlStr := "SELECT id, name, age FROM user WHERE id > ?"
	stmt, err := db.Prepare(sqlStr)
	if err != nil {
		fmt.Printf("prepare failed, err: %v\n", err)
		return
	}
	defer stmt.Close()
	rows, err := stmt.Query(id)
	if err != nil {
		fmt.Printf("query failed, err: %v\n", err)
		return
	}
	defer rows.Close()
	// 回圈讀取結果集中的資料
	for rows.Next() {
		var u user
		err := rows.Scan(&u.id, &u.name, &u.age)
		if err != nil {
			fmt.Printf("scan failed, err: %v\n", err)
			return
		}
		fmt.Printf("id: %d name: %s age: %d\n", u.id, u.name, u.age)
	}
}

func main() {
	if err := initMySQL(); err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
	}
	// 檢查完錯誤之后執行,確保 db 不為 nil
	// Close() 用來釋放資料庫連接相關的資源
	// Close 將關閉資料庫并阻止啟動新查詢,關閉,然后等待服務器上已開始處理的所有查詢完成,
	defer db.Close()

	fmt.Println("connect to database success")
	// db.xx() 去使用資料庫操作...

	// MySQL預處理查詢多行資料
	prepareQueryDemo(0)
}

運行

Code/go/mysql_demo via ?? v1.20.3 via ?? base 
? go run main.go
connect to database success
id: 1 name: 小喬 age: 16
id: 2 name: 小喬 age: 12

Code/go/mysql_demo via ?? v1.20.3 via ?? base 
? 

插入、更新和洗掉操作的預處理基本一樣,下面是插入示例

package main

import (
	"database/sql"
	"fmt"
	"time"

	_ "github.com/go-sql-driver/mysql" // 匿名匯入 自動執行 init()
)

var db *sql.DB

func initMySQL() (err error) {
	//DSN (Data Source Name)
	dsn := "root:12345678@tcp(127.0.0.1:3306)/sql_test"
	// 注意:要初始化全域的 db 物件,不要新宣告一個 db 變數
	db, err = sql.Open("mysql", dsn) // 只對格式進行校驗,并不會真正連接資料庫
	if err != nil {
		return err
	}

	// Ping 驗證與資料庫的連接是否仍處于活動狀態,并在必要時建立連接,
	err = db.Ping()
	if err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
		return err
	}
	// 數值需要根據業務具體情況來確定
	db.SetConnMaxLifetime(time.Second * 10) // 設定可以重用連接的最長時間
	db.SetConnMaxIdleTime(time.Second * 5)  // 設定連接可能處于空閑狀態的最長時間
	db.SetMaxOpenConns(200)                 // 設定與資料庫的最大打開連接數
	db.SetMaxIdleConns(10)                  //  設定空閑連接池中的最大連接數
	return nil
}

type user struct {
	id   int
	age  int
	name string
}

// 預處理插入
func prepareInsertDemo() {
	sqlStr := "INSERT INTO user(name, age) VALUES (?,?)"
	// 為以后的查詢或執行創建預準備陳述句,
	// 可以從回傳的陳述句并發運行多個查詢或執行,
	// 當不再需要陳述句時,呼叫方必須呼叫陳述句的 Close 方法,
	stmt, err := db.Prepare(sqlStr)
	if err != nil {
		fmt.Printf("prepare failed, err:%v\n", err)
		return
	}
	defer stmt.Close()
	_, err = stmt.Exec("昭君", 12)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	_, err = stmt.Exec("黛玉", 16)
	if err != nil {
		fmt.Printf("insert failed, err:%v\n", err)
		return
	}
	fmt.Println("insert success.")
}

func main() {
	if err := initMySQL(); err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
	}
	// 檢查完錯誤之后執行,確保 db 不為 nil
	// Close() 用來釋放資料庫連接相關的資源
	// Close 將關閉資料庫并阻止啟動新查詢,關閉,然后等待服務器上已開始處理的所有查詢完成,
	defer db.Close()

	fmt.Println("connect to database success")
	// db.xx() 去使用資料庫操作...
	
	// MySQL預處理 插入資料
	prepareInsertDemo()
}

運行

Code/go/mysql_demo via ?? v1.20.3 via ?? base 
? go run main.go
connect to database success
insert success.

Code/go/mysql_demo via ?? v1.20.3 via ?? base 
? 

SQL 查詢 插入結果

mysql> select * from user;
+----+--------+------+
| id | name   | age  |
+----+--------+------+
|  1 | 小喬   |   16 |
|  2 | 小喬   |   12 |
|  5 | 昭君   |   12 |
|  6 | 黛玉   |   16 |
+----+--------+------+
4 rows in set (0.00 sec)

mysql>

三、SQL注入問題

問:什么是SQL注入問題?

ChatGPT 答:

SQL注入(SQL Injection)是一種常見的安全漏洞,指的是攻擊者通過在應用程式的用戶輸入中插入惡意的SQL代碼,從而利用應用程式對資料庫的不當處理,執行未經授權的資料庫操作,

SQL注入攻擊通常發生在使用動態構建SQL陳述句的應用程式中,例如Web應用程式,攻擊者利用應用程式沒有正確驗證、過濾或轉義用戶輸入的資料,將惡意的SQL代碼插入到查詢陳述句中,

攻擊者可以利用SQL注入問題進行各種惡意行為,包括但不限于以下情況:

  1. 繞過身份驗證:通過注入惡意的SQL代碼,攻擊者可以繞過應用程式的身份驗證機制,以管理員或其他特權用戶的身份執行操作,
  2. 資料泄露:攻擊者可以通過注入SELECT陳述句,獲取應用程式未授權訪問的資料,包括敏感資訊(如用戶密碼、個人資訊等),
  3. 資料篡改:攻擊者可以通過注入UPDATE或DELETE陳述句,修改或洗掉資料庫中的資料,破壞資料完整性,
  4. 執行任意代碼:攻擊者可以通過注入惡意的SQL代碼,執行任意的資料庫操作或其他系統命令,導致系統崩潰、服務拒絕或其他安全問題,

為了防止SQL注入攻擊,開發人員應該采取以下措施:

  • 使用引數化查詢或預處理陳述句:使用引數化查詢或預處理陳述句可以將引數值與SQL陳述句分開處理,確保輸入資料被正確轉義和處理,避免了直接拼接用戶輸入到SQL陳述句中的問題,
  • 輸入驗證與過濾:對用戶輸入的資料進行嚴格的驗證和過濾,確保只接受符合預期的資料格式和范圍,并在必要時進行轉義處理,
  • 最小權限原則:應用程式在連接資料庫時,使用具有最低權限的資料庫用戶,僅具備執行必要操作的權限,
  • 安全配置:確保資料庫和應用程式的安全配置,包括禁用不必要的資料庫功能、限制網路訪問、定期更新資料庫軟體等,

通過采取這些安全措施,可以有效減輕SQL注入攻擊的風險,提升應用程式的安全性,

注意:不要自己拼接SQL陳述句,不要相信用戶輸入的內容是安全的、合法的,

例子

以下是一個示例,展示了一個存在SQL注入漏洞的情況,并使用Go語言來演示如何預防注入問題:

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "username:password@tcp(hostname:port)/database")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 假設用戶輸入的引數
	username := "admin' OR 1=1 --"
	password := "123456"

	// 構建SQL查詢陳述句
	query := fmt.Sprintf("SELECT * FROM users WHERE username = '%s' AND password = '%s'", username, password)

	// 執行查詢
	rows, err := db.Query(query)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	// 處理查詢結果
	for rows.Next() {
		// 處理每一行資料
		var id int
		var username string
		var password string
		err := rows.Scan(&id, &username, &password)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(id, username, password)
	}

	if err = rows.Err(); err != nil {
		log.Fatal(err)
	}
}

在上述代碼中,我們假設用戶輸入的username引數為admin' OR 1=1 --,這是一種常見的注入嘗試,然后,我們使用字串插值的方式構建了一個SQL查詢陳述句,將用戶輸入的引數直接嵌入到SQL陳述句中,

這種構建SQL陳述句的方式存在SQL注入漏洞,攻擊者可以在username引數中插入惡意的SQL代碼,使查詢陳述句的邏輯被破壞,在本例中,1=1條件將始終為真,繞過了正常的身份驗證,

為了防止SQL注入,我們應該使用預處理陳述句或引數化查詢,以下是修復SQL注入漏洞的示例代碼:

import (
	"database/sql"
	"fmt"
	"log"

	_ "github.com/go-sql-driver/mysql"
)

func main() {
	db, err := sql.Open("mysql", "username:password@tcp(hostname:port)/database")
	if err != nil {
		log.Fatal(err)
	}
	defer db.Close()

	// 假設用戶輸入的引數
	username := "admin' OR 1=1 --"
	password := "123456"

	// 使用預處理陳述句
	stmt, err := db.Prepare("SELECT * FROM users WHERE username = ? AND password = ?")
	if err != nil {
		log.Fatal(err)
	}
	defer stmt.Close()

	// 執行查詢
	rows, err := stmt.Query(username, password)
	if err != nil {
		log.Fatal(err)
	}
	defer rows.Close()

	// 處理查詢結果
	for rows.Next() {
		// 處理每一行資料
		var id int
		var username string
		var password string
		err := rows.Scan(&id, &username, &password)
		if err != nil {
			log.Fatal(err)
		}
		fmt.Println(id, username, password)
	}

	if err = rows.Err

例子二

package main

import (
	"database/sql"
	"fmt"
	"time"

	_ "github.com/go-sql-driver/mysql" // 匿名匯入 自動執行 init()
)

var db *sql.DB

func initMySQL() (err error) {
	//DSN (Data Source Name)
	dsn := "root:12345678@tcp(127.0.0.1:3306)/sql_test"
	// 注意:要初始化全域的 db 物件,不要新宣告一個 db 變數
	db, err = sql.Open("mysql", dsn) // 只對格式進行校驗,并不會真正連接資料庫
	if err != nil {
		return err
	}

	// Ping 驗證與資料庫的連接是否仍處于活動狀態,并在必要時建立連接,
	err = db.Ping()
	if err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
		return err
	}
	// 數值需要根據業務具體情況來確定
	db.SetConnMaxLifetime(time.Second * 10) // 設定可以重用連接的最長時間
	db.SetConnMaxIdleTime(time.Second * 5)  // 設定連接可能處于空閑狀態的最長時間
	db.SetMaxOpenConns(200)                 // 設定與資料庫的最大打開連接數
	db.SetMaxIdleConns(10)                  //  設定空閑連接池中的最大連接數
	return nil
}

type user struct {
	id   int
	age  int
	name string
}

// sql注入示例
func sqlInjectDemo(name string) {
	sqlStr := fmt.Sprintf("select id, name, age from user where name='%s'", name)
	fmt.Printf("SQL: %s\n", sqlStr)
	var u user
	err := db.QueryRow(sqlStr).Scan(&u.id, &u.name, &u.age)
	if err != nil {
		fmt.Printf("exec failed, err: %v\n", err)
		return
	}
	fmt.Printf("user: %#v\n", u)
}

func main() {
	if err := initMySQL(); err != nil {
		fmt.Printf("connect to db failed, err: %v\n", err)
	}
	// 檢查完錯誤之后執行,確保 db 不為 nil
	// Close() 用來釋放資料庫連接相關的資源
	// Close 將關閉資料庫并阻止啟動新查詢,關閉,然后等待服務器上已開始處理的所有查詢完成,
	defer db.Close()

	fmt.Println("connect to database success")
	// db.xx() 去使用資料庫操作...
	
	// SQL 注入
	//sqlInjectDemo("黛玉")
	//  select id, name, age from user where name='xxx ' or 1=1#'
	sqlInjectDemo("xxx ' or 1=1#")
}

運行

? go run main.go
connect to database success
SQL:select id, name, age from user where name='黛玉'
user: main.user{id:6, age:16, name:"黛玉"}

Code/go/mysql_demo via ?? v1.20.3 via ?? base 
? go run main.go
connect to database success
SQL: select id, name, age from user where name='xxx ' or 1=1#'
user: main.user{id:1, age:16, name:"小喬"}

Code/go/mysql_demo via ?? v1.20.3 via ?? base 
? 

四、SQL 占位符

不同的資料庫使用不同的占位符語法,下面是一些常見資料庫的占位符語法:

  1. MySQL 使用問號(?)作為占位符,

示例:

SELECT * FROM table WHERE column = ?
  1. PostgreSQL 使用美元符號加數字($1、$2、$3...)作為占位符,

示例:

SELECT * FROM table WHERE column = $1
  1. SQLite 使用問號(?)或冒號加數字(:1、:2、:3...)作為占位符,

示例:

SELECT * FROM table WHERE column = ?

SELECT * FROM table WHERE column = :1
  1. Oracle 使用冒號加數字(:1、:2、:3...)作為占位符,

示例:

SELECT * FROM table WHERE column = :1

需要注意的是,占位符的語法可能會因不同的資料庫驅動程式或框架而略有差異,因此,使用資料庫驅動程式的檔案或框架的指南來確定正確的占位符語法是很重要的,

此外,還有一些ORM(物件關系映射)框架,如GORM、Hibernate等,它們可以在不同的資料庫中使用統一的語法和方式來表示占位符,以提供更高級的查詢功能和更好的跨資料庫兼容性,

本文來自博客園,作者:尋月隱君,轉載請注明原文鏈接:https://www.cnblogs.com/QiaoPengjun/p/17473280.html

轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/554897.html

標籤:其他

上一篇:Java 網路編程 —— 基于 UDP 的資料報和套接字

下一篇:返回列表

標籤雲
其他(160786) Python(38219) JavaScript(25492) Java(18216) C(15237) 區塊鏈(8270) C#(7972) AI(7469) 爪哇(7425) MySQL(7246) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5873) 数组(5741) R(5409) Linux(5347) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4589) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2435) ASP.NET(2404) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) .NET技术(1984) 功能(1967) HtmlCss(1961) Web開發(1951) C++(1933) python-3.x(1918) 弹簧靴(1913) xml(1889) PostgreSQL(1881) .NETCore(1863) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • 【C++】Microsoft C++、C 和匯編程式檔案

    ......

    uj5u.com 2020-09-10 00:57:23 more
  • 例外宣告

    相比于斷言適用于排除邏輯上不可能存在的狀態,例外通常是用于邏輯上可能發生的錯誤。 例外宣告 Item 1:當函式不可能拋出例外或不能接受拋出例外時,使用noexcept 理由 如果不打算拋出例外的話,程式就會認為無法處理這種錯誤,并且應當盡早終止,如此可以有效地阻止例外的傳播與擴散。 示例 //不可 ......

    uj5u.com 2020-09-10 00:57:27 more
  • Codeforces 1400E Clear the Multiset(貪心 + 分治)

    鏈接:https://codeforces.com/problemset/problem/1400/E 來源:Codeforces 思路:給你一個陣列,現在你可以進行兩種操作,操作1:將一段沒有 0 的區間進行減一的操作,操作2:將 i 位置上的元素歸零。最終問:將這個陣列的全部元素歸零后操作的最少 ......

    uj5u.com 2020-09-10 00:57:30 more
  • UVA11610 【Reverse Prime】

    本人看到此題沒有翻譯,就附帶了一個自己的翻譯版本 思考 這一題,它的第一個要求是找出所有 $7$ 位反向質數及其質因數的個數。 我們應該需要質數篩篩選1~$10^{7}$的所有數,這里就不慢慢介紹了。但是,重讀題,我們突然發現反向質數都是 $7$ 位,而將它反過來后的數字卻是 $6$ 位數,這就說明 ......

    uj5u.com 2020-09-10 00:57:36 more
  • 統計區間素數數量

    1 #pragma GCC optimize(2) 2 #include <bits/stdc++.h> 3 using namespace std; 4 bool isprime[1000000010]; 5 vector<int> prime; 6 inline int getlist(int ......

    uj5u.com 2020-09-10 00:57:47 more
  • C/C++編程筆記:C++中的 const 變數詳解,教你正確認識const用法

    1、C中的const 1、區域const變數存放在堆疊區中,會分配記憶體(也就是說可以通過地址間接修改變數的值)。測驗代碼如下: 運行結果: 2、全域const變數存放在只讀資料段(不能通過地址修改,會發生寫入錯誤), 默認為外部聯編,可以給其他源檔案使用(需要用extern關鍵字修飾) 運行結果: ......

    uj5u.com 2020-09-10 00:58:04 more
  • 【C++犯錯記錄】VS2019 MFC添加資源不懂如何修改資源宏ID

    1. 首先在資源視圖中,添加資源 2. 點擊新添加的資源,復制自動生成的ID 3. 在解決方案資源管理器中找到Resource.h檔案,編輯,使用整個專案搜索和替換的方式快速替換 宏宣告 4. Ctrl+Shift+F 全域搜索,點擊查找全部,然后逐個替換 5. 為什么使用搜索替換而不使用屬性視窗直 ......

    uj5u.com 2020-09-10 00:59:11 more
  • 【C++犯錯記錄】VS2019 MFC不懂的批量添加資源

    1. 打開資源頭檔案Resource.h,在其中預先定義好宏 ID(不清楚其實ID值應該設定多少,可以先新建一個相同的資源項,再在這個資源的ID值的基礎上遞增即可) 2. 在資源視圖中選中專案資源,按F7編輯資源檔案,按 ID 型別 相對路徑的形式添加 資源。(別忘了先把檔案拷貝到專案中的res檔案 ......

    uj5u.com 2020-09-10 01:00:19 more
  • C/C++編程筆記:關于C++的參考型別,專供新手入門使用

    今天要講的是C++中我最喜歡的一個用法——參考,也叫別名。 參考就是給一個變數名取一個變數名,方便我們間接地使用這個變數。我們可以給一個變數創建N個參考,這N + 1個變數共享了同一塊記憶體區域。(參考型別的變數會占用記憶體空間,占用的記憶體空間的大小和指標型別的大小是相同的。雖然參考是一個物件的別名,但 ......

    uj5u.com 2020-09-10 01:00:22 more
  • 【C/C++編程筆記】從頭開始學習C ++:初學者完整指南

    眾所周知,C ++的學習曲線陡峭,但是花時間學習這種語言將為您的職業帶來奇跡,并使您與其他開發人員區分開。您會更輕松地學習新語言,形成真正的解決問題的技能,并在編程的基礎上打下堅實的基礎。 C ++將幫助您養成良好的編程習慣(即清晰一致的編碼風格,在撰寫代碼時注釋代碼,并限制類內部的可見性),并且由 ......

    uj5u.com 2020-09-10 01:00:41 more
最新发布
  • Go 連接 MySQL之 MySQL 預處理

    # Go 連接 MySQL之 MySQL 預處理 ## 一、ChatGPT 關于 MySQL 預處理 的回答 ### 問:什么是MySQL 的預處理 具體執行程序時什么 #### ChatGPT 答: MySQL的預處理是一種在執行SQL陳述句之前,先進行編譯和優化的機制。它將SQL陳述句分成兩個階段: ......

    uj5u.com 2023-06-12 07:40:49 more
  • Java 網路編程 —— 基于 UDP 的資料報和套接字

    ## UDP 簡介 UDP(User Datagram Protocol,用戶資料報協議)是傳輸層的另一種協議,比 TCP 具有更快的傳輸速度,但是不可靠。UDP 發送的資料單元被稱為 UDP 資料報,當網路傳輸 UDP 資料報時,無法保證資料報一定到達目的地,也無法保證各個資料報按發送的順序到達目 ......

    uj5u.com 2023-06-12 07:40:45 more
  • Go語言中的init函式: 特點、用途和注意事項

    # 1. 引言 在Go語言中,`init()`函式是一種特殊的函式,用于在程式啟動時自動執行一次。它的存在為我們提供了一種機制,可以在程式啟動時進行一些必要的初始化操作,為程式的正常運行做好準備。 在這篇文章中,我們將詳細探討`init()`函式的特點、用途和注意事項,希望能幫助你更好地理解和使用這 ......

    uj5u.com 2023-06-12 07:40:41 more
  • 【技識訓累】SpringBoot中的簡介與配置【一】

    博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ......

    uj5u.com 2023-06-12 07:40:36 more
  • Go 語言連接資料庫實作增刪改查

    title: "Go 語言連接資料庫實作增刪改查" date: 2023-06-10T18:55:16+08:00 draft: true tags: ["Go"] categories: ["Go"] # Go 連接 MySQL實作增刪改查 ## 一、初始化連接 ### 創建專案 ![](http ......

    uj5u.com 2023-06-12 07:35:18 more
  • Maven常用命令及其作用

    一、Maven常用命令及其作用 Maven的生命周期包括:clean、validate、compile、test、package、verify、install、site、deploy,其中需要注意的是:執行后面的命令時,前面的命令自動得到執行,(其中,也可以跳過其中的步驟,如:test,在mvn i ......

    uj5u.com 2023-06-12 07:35:10 more
  • 【技識訓累】Python中的Pandas庫【三】

    博客推行版本更新,成果積累制度,已經寫過的博客還會再次更新,不斷地琢磨,高質量高數量都是要追求的,工匠精神是學習必不可少的精神。因此,大家有何建議歡迎在評論區踴躍發言,你們的支持是我最大的動力,你們敢投,我就敢肝 ......

    uj5u.com 2023-06-12 07:34:50 more
  • C++ 指標

    # 一、C++ 指標的算術運算 ## 遞增一個指標 我們喜歡在程式中使用指標代替陣列,因為變數指標可以遞增,而陣列不能遞增,因為陣列是一個常量指標。下面的程式遞增變數指標,以便順序訪問陣列中的每一個元素: ``` 實體 #include using namespace std; const int ......

    uj5u.com 2023-06-11 07:17:06 more
  • ImageIO的應用 (AWT和Swing初接觸)

    # ImageIO的應用 # 一、關于IO流 在講imageio之前,我們先來復習一下IO流的使用。 這里我建立一個Java類,用來實作讀取檔案中的內容,并且能夠識別換行,話不多說,上代碼: ```java package com.Evan.demo; import java.io.Buffered ......

    uj5u.com 2023-06-10 07:56:56 more
  • C++面試八股文:了解sizeof運算子嗎?

    某日二師兄參加XXX科技公司的C++工程師開發崗位第10面: > 面試官:了解`sizeof`運算子嗎? > > 二師兄:略微了解(不就是求大小的嘛。。) > > 面試官:請講以下如何使用`sizeof`? > > 二師兄:`sizeof`主要是求變數或者型別的大小。直接使用`sizeof(type ......

    uj5u.com 2023-06-10 07:56:48 more