国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

golang web學(xué)習(xí)隨便記4-內(nèi)存、文件、數(shù)據(jù)庫(kù)

這篇具有很好參考價(jià)值的文章主要介紹了golang web學(xué)習(xí)隨便記4-內(nèi)存、文件、數(shù)據(jù)庫(kù)。希望對(duì)大家有所幫助。如果存在錯(cuò)誤或未考慮完全的地方,請(qǐng)大家不吝賜教,您也可以點(diǎn)擊"舉報(bào)違法"按鈕提交疑問(wèn)。

我們來(lái)開(kāi)始學(xué)習(xí)如何存儲(chǔ)數(shù)據(jù)。書中有一點(diǎn)不錯(cuò),就是并不是一上來(lái)就告訴你存儲(chǔ)數(shù)據(jù)使用數(shù)據(jù)庫(kù),因?yàn)椴煌臄?shù)據(jù)存儲(chǔ)適合不同的手段。

用內(nèi)存存儲(chǔ)數(shù)據(jù)

先來(lái)看在內(nèi)存中存儲(chǔ)數(shù)據(jù):下面的例子用結(jié)構(gòu)體方式在內(nèi)存存放數(shù)據(jù),然后利用兩個(gè)map來(lái)表示“索引”,鍵值對(duì)中的值是指向內(nèi)存中結(jié)構(gòu)體實(shí)例的指針。以下main函數(shù)的主要步驟是,用make初始化兩個(gè)索引用的map,生成數(shù)據(jù)存放到結(jié)構(gòu)體實(shí)例中,調(diào)用store創(chuàng)建索引,驗(yàn)證兩種索引方式

package main

import "fmt"

type Post struct {
	Id      int
	Content string
	Author  string
}

var PostById map[int]*Post
var PostsByAuthor map[string][]*Post

func store(post Post) {
	PostById[post.Id] = &post
	PostsByAuthor[post.Author] = append(PostsByAuthor[post.Author], &post)
}

func main() {
	PostById = make(map[int]*Post)
	PostsByAuthor = make(map[string][]*Post)

	post1 := Post{Id: 1, Content: "你好, Golang", Author: "張三"}
	post2 := Post{Id: 2, Content: "你好, C++", Author: "李四"}
	post3 := Post{Id: 3, Content: "你好, Java", Author: "王五"}
	post4 := Post{Id: 4, Content: "你好, C", Author: "張三"}
	store(post1)
	store(post2)
	store(post3)
	store(post4)

	fmt.Println(PostById[1])
	fmt.Println(PostById[3])

	for _, post := range PostsByAuthor["張三"] {
		fmt.Println(post)
	}
	for _, post := range PostsByAuthor["李四"] {
		fmt.Println(post)
	}

}

go? run? . 運(yùn)行后輸出如下:

sjg@sjg-PC:~/go/src/memory_store$ go run .
&{1 你好, Golang 張三}
&{3 你好, Java 王五}
&{1 你好, Golang 張三}
&{4 你好, C 張三}
&{2 你好, C++ 李四}

正如書中所說(shuō),這個(gè)例子非常簡(jiǎn)單,但是,在實(shí)際應(yīng)用中,對(duì)于需要在內(nèi)存中緩存數(shù)據(jù)來(lái)提升性能的場(chǎng)合,并非都要用redis那樣厚重的外部?jī)?nèi)存數(shù)據(jù)庫(kù),或許我們簡(jiǎn)單構(gòu)建一下內(nèi)存數(shù)據(jù)存儲(chǔ)就能很好解決問(wèn)題。

用文件存儲(chǔ)數(shù)據(jù)

讀寫文本文件

用Golang讀寫字節(jié)數(shù)組數(shù)據(jù)并不復(fù)雜,而且和PHP類似,既可以一次性直接將數(shù)據(jù)寫入文件或者從文件讀取數(shù)據(jù),也可以先創(chuàng)建或者打開(kāi)文件,再讀寫數(shù)據(jù)

package main

import (
	"fmt"
	"io/ioutil"
	"os"
)

func main() {
	data := []byte("歡迎使用 Golang 編程語(yǔ)言\n")
	err := ioutil.WriteFile("datafile1", data, 0644) // 直接寫入字節(jié)數(shù)組數(shù)據(jù)到文件
	if err != nil {
		panic(err)
	}
	readBuf1, _ := ioutil.ReadFile("datafile1") // 直接讀取文件數(shù)據(jù)到緩沖字節(jié)數(shù)組
	fmt.Print(string(readBuf1))

	file1, _ := os.Create("datafile2")
	defer file1.Close()

	byteCnt, _ := file1.Write(data) // 創(chuàng)建文件再寫入字節(jié)數(shù)組數(shù)據(jù)
	fmt.Printf("寫入 %d 字節(jié)到文件 datafile2\n", byteCnt)

	file2, _ := os.Open("datafile2")
	defer file2.Close()

	readBuf2 := make([]byte, len(data))
	byteCnt, _ = file2.Read(readBuf2) // 打開(kāi)文件再讀取數(shù)據(jù)到緩沖字節(jié)數(shù)組
	fmt.Printf("從文件 datafile2 讀取 %d 字節(jié)\n", byteCnt)
	fmt.Println(string(readBuf2))
}

運(yùn)行結(jié)果如下(注意觀察在項(xiàng)目目錄下生成的數(shù)據(jù)文件datafile1和datafile2)

sjg@sjg-PC:~/go/src/file_store1$ go run .
歡迎使用 Golang 編程語(yǔ)言
寫入 33 字節(jié)到文件 datafile2
從文件 datafile2 讀取 33 字節(jié)
歡迎使用 Golang 編程語(yǔ)言

讀寫CSV

在各種應(yīng)用中,CSV是非常常用的數(shù)據(jù)格式,golang標(biāo)準(zhǔn)庫(kù)提供了專門的讀寫csv的包encoding/csv。下面的例子演示了csv文件的寫入和讀?。?/p>

package main

import (
	"encoding/csv"
	"fmt"
	"os"
	"strconv"
)

type Post struct {
	Id      int
	Content string
	Author  string
}

func main() {
	csv_file, err := os.Create("posts.csv") // 創(chuàng)建 csv 文件
	if err != nil {
		panic(err)
	}
	defer csv_file.Close()

	data_posts := []Post{
		{Id: 1, Content: "你好, Golang", Author: "張三"},
		{Id: 2, Content: "你好, C++", Author: "李四"},
		{Id: 3, Content: "你好, Java", Author: "王五"},
		{Id: 4, Content: "你好, C", Author: "張三"},
	}

	writer := csv.NewWriter(csv_file) // 創(chuàng)建寫入器(Writer型對(duì)象),參數(shù)為目標(biāo)寫入文件
	for _, post := range data_posts {
		line := []string{strconv.Itoa(post.Id), post.Content, post.Author}
		err := writer.Write(line) // 用寫入器寫入字符串?dāng)?shù)組(每個(gè)元素對(duì)應(yīng)一個(gè)字段)
		if err != nil {
			panic(err)
		}
	}
	writer.Flush() // 寫入器是帶緩沖的,需要刷寫確保全部寫完

	file, err := os.Open("posts.csv") // 打開(kāi) csv 文件
	if err != nil {
		panic(err)
	}
	defer file.Close()

	reader := csv.NewReader(file)   // 創(chuàng)建讀取器(Reader型對(duì)象),參數(shù)為目標(biāo)讀取文件
	reader.FieldsPerRecord = -1     // 正的指定字段數(shù),0按第一個(gè)記錄確定字段數(shù),負(fù)的變長(zhǎng)字段數(shù)
	record, err := reader.ReadAll() // 一次性讀取所有記錄(返回二維字符串?dāng)?shù)組)
	if err != nil {
		panic(err)
	}

	var posts []Post
	for _, item := range record { // 二維數(shù)組記錄保存到 posts
		id, _ := strconv.ParseInt(item[0], 0, 0) // 注意:strconv.ParseInt返回int64
		post := Post{Id: int(id), Content: item[1], Author: item[2]}
		posts = append(posts, post)
	}
	fmt.Println(posts[1].Id)
	fmt.Println(posts[1].Content)
	fmt.Println(posts[1].Author)
}

上述代碼中,對(duì)于csv文件的寫入,是一行行寫入的,對(duì)于讀取,則是一次性讀取到二維數(shù)組中,然后解析該數(shù)組還原結(jié)構(gòu)體對(duì)象的。對(duì)于需要讀取的數(shù)據(jù)量非常大的情況,csv.Reader對(duì)象是提供了Read()方法來(lái)一行行讀取的。同時(shí),為了提高性能,csv.Reader對(duì)象有一個(gè)ReuseRecord字段來(lái)控制是否復(fù)用返回的slice(默認(rèn)每次調(diào)用都會(huì)分配新的內(nèi)存)。csv.Reader對(duì)象還有其他一些字段來(lái)控制是否去除前導(dǎo)空格等。

編解碼方式讀寫文件

某種程度上,前述csv例子我們是手動(dòng)對(duì)寫入的數(shù)據(jù)和讀取的數(shù)據(jù)進(jìn)行編碼和解碼的,encoding/gob包提供了更通用的編碼和解碼方式,而且它不限于文本文件,可以用于二進(jìn)制文件。

下面的例子演示了gob包中編碼器和解碼器的使用:

package main

import (
	"bytes"
	"encoding/gob"
	"fmt"
	"io/ioutil"
)

type Post struct {
	Id      int
	Content string
	Author  string
}

func store(data interface{}, filename string) {
	buffer := new(bytes.Buffer)       // 用new初始化編碼器所需的緩沖
	encoder := gob.NewEncoder(buffer) // 創(chuàng)建編碼器
	err := encoder.Encode(data)       // 用編碼器編碼數(shù)據(jù),數(shù)據(jù)為接口類型
	if err != nil {
		panic(err)
	}
	err = ioutil.WriteFile(filename, buffer.Bytes(), 0600) // 寫入緩沖中編碼好的數(shù)據(jù)
	if err != nil {
		panic(err)
	}
}

func load(data interface{}, filename string) {
	raw, err := ioutil.ReadFile(filename) // 一次性讀取文件中所有數(shù)據(jù)
	if err != nil {
		panic(err)
	}
	buffer := bytes.NewBuffer(raw)    // 將數(shù)據(jù)放入緩沖
	decoder := gob.NewDecoder(buffer) // 創(chuàng)建解碼器
	err = decoder.Decode(data)        // 用解碼器解碼數(shù)據(jù),數(shù)據(jù)為接口類型
	if err != nil {
		panic(err)
	}
}

func main() {
	post := Post{Id: 1, Content: "你好, Golang", Author: "張三"}
	store(post, "datafile")         // 編碼存放到文件,數(shù)據(jù)是“讀”
	var post_read Post
	load(&post_read, "datafile")    // 解碼存放到結(jié)構(gòu)體,數(shù)據(jù)是“寫”
	fmt.Println(post_read)
}

上面的代碼表明:1、創(chuàng)建編碼器和解碼器,都需要一個(gè)buffer,編碼器需要new初始化的buffer,解碼器需要放入了原始字節(jié)切片數(shù)據(jù)的buffer(使用bytes.NewBuffer(..)函數(shù)完成)。2、上面的代碼store(post, "datafile")改成store(&post, "datafile")結(jié)果不變,而且似乎傳遞地址更好一點(diǎn),可以避免結(jié)構(gòu)體拷貝。3、調(diào)用編碼器的Encode(..)方法或者調(diào)用解碼器的Decode(..)方法,都需要傳入空接口類型(interface{})的數(shù)據(jù)data。實(shí)際調(diào)用方傳入?yún)?shù)時(shí),對(duì)于編碼既可以傳值,也可以傳地址,因?yàn)榫幋a時(shí)data是“讀”狀態(tài);對(duì)于解碼只能傳地址,因?yàn)榻獯a時(shí)data是“寫”狀態(tài)。這個(gè)道理和C語(yǔ)言scanf函數(shù)傳地址,printf傳值是一樣的——只是golang空接口類型具有動(dòng)態(tài)類型和動(dòng)態(tài)值,從而“讀”時(shí)既可以是值形式,也可以地址形式,因?yàn)槭强战涌?,?nèi)部用反射機(jī)制來(lái)獲得運(yùn)行時(shí)類型。

關(guān)于結(jié)構(gòu)體、接口和空接口,可以參考?golang學(xué)習(xí)隨便記4-類型:map、結(jié)構(gòu)體_sjg20010414的博客-CSDN博客

golang學(xué)習(xí)隨便記8-接口_sjg20010414的博客-CSDN博客

golang Interface_golang interface{}_jenrain的博客-CSDN博客

用數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)

我們終于來(lái)到用數(shù)據(jù)庫(kù)存儲(chǔ)數(shù)據(jù)的了解。書上是使用 PostgreSQL 數(shù)據(jù)庫(kù),我打算把例子改寫成使用 MariaDB數(shù)據(jù)庫(kù)。

啟動(dòng) mariadb 10.3數(shù)據(jù)庫(kù) (我是安裝在docker中,用 ./start_mariadb.sh? bash即可啟動(dòng)并進(jìn)入容器內(nèi)終端),mysql -u root -p 登錄,CREATE DATABASE gwp DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; 創(chuàng)建數(shù)據(jù)庫(kù),GRANT ALL ON gwp.* TO 'gwp'@'%' IDENTIFIED BY 'dbpassword';? 創(chuàng)建用戶并授權(quán)。用下面的語(yǔ)句創(chuàng)建表

MariaDB [gwp]> CREATE TABLE post (
    -> id int NOT NULL AUTO_INCREMENT,
    -> content text,
    -> author varchar(255),
    -> PRIMARY KEY (id)
    -> );

添加驅(qū)動(dòng):GitHub - go-sql-driver/mysql: Go MySQL Driver is a MySQL driver for Go's (golang) database/sql package

sjg@sjg-PC:~/go/src/db_store1$ go get -u github.com/go-sql-driver/mysql
go: downloading github.com/go-sql-driver/mysql v1.7.1
go get: added github.com/go-sql-driver/mysql v1.7.1

改寫書上這部分代碼有一點(diǎn)點(diǎn)障礙,一個(gè)是書上使用$1、$2、$3等占位符報(bào)錯(cuò),無(wú)論是查閱別人帖子還是golang官網(wǎng)例子代碼(sql package - database/sql - Go Packages),占位符都是?。另一個(gè)是 mariadb 10.3 版本不夠高,因此和mysql一樣(不清楚高版本mysql情況)不支持插入時(shí) RETURNING id值,我們需要額外工作來(lái)獲取id (還好 mariadb/mysql? 有 LAST_INSERT_ID() 函數(shù)):

package main

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

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

type Post struct {
	Id      int
	Content string
	Author  string
}

var Db *sql.DB

func init() { // 此 init 不顯式調(diào)用,自動(dòng)隱式調(diào)用,實(shí)現(xiàn)初始化全局變量 Db
	var err error
	Db, err = sql.Open("mysql", "gwp:dbpassword@tcp(172.17.0.1:3306)/gwp?charset=utf8mb4,utf8")
	if err != nil {
		panic(err)
	}
}

func Posts(limit int) (posts []Post, err error) {
	rows, err := Db.Query("SELECT id, content, author FROM post LIMIT ?", limit) // Query(..) 預(yù)期返回多行結(jié)果集
	if err != nil {
		return
	}
	for rows.Next() { // 用循環(huán)遍歷多行結(jié)果集
		post := Post{}
		err = rows.Scan(&post.Id, &post.Content, &post.Author) // Scan(..) 將結(jié)果集當(dāng)前列值綁定到變量
		if err != nil {
			return
		}
		posts = append(posts, post) // 結(jié)果依次放入切片 posts
	}
	rows.Close() // 關(guān)閉結(jié)果集,清理內(nèi)存
	return
}

func GetPost(id int) (post Post, err error) {
	post = Post{}
	err = Db.QueryRow("SELECT id, content, author FROM post WHERE id = ?", id). // QueryRow(..) 預(yù)期返回單行結(jié)果集
											Scan(&post.Id, &post.Content, &post.Author) // pgsql 可以 RETURNING id
	return
}

func (post *Post) Create() (err error) {
	sql := "INSERT INTO post (content, author) VALUES (?, ?)"
	stmt, err := Db.Prepare(sql) // 對(duì)于插入使用準(zhǔn)備語(yǔ)句
	if err != nil {
		log.Fatal(err)
		return
	}
	defer stmt.Close()

	// err = stmt.QueryRow(post.Content, post.Author).Scan(&post.Id)  // pgsql 可以一步設(shè)置 post.id
	if result, err := stmt.Exec(post.Content, post.Author); err != nil { // Exec(..)返回執(zhí)行結(jié)果
		log.Fatal(err)
	} else {
		if last_insert_id, err := result.LastInsertId(); err != nil {
			log.Fatal(err)
		} else {
			post.Id = int(last_insert_id) // Mariadb/MySQL應(yīng)該支持執(zhí)行結(jié)果的 LastInsertId()
		}
	}
	return
}

func (post *Post) Update() (err error) {
	_, err = Db.Exec("UPDATE post SET content = ?, author = ? WHERE id = ?",
		post.Content, post.Author, post.Id)
	return
}

func (post *Post) Delete() (err error) {
	_, err = Db.Exec("DELETE FROM post WHERE id = ?", post.Id)
	return
}

func main() {
	post := Post{Content: "你好, C++", Author: "李四"}

	fmt.Println(post) // 插入記錄前
	post.Create()
	fmt.Println(post) // 插入記錄后

	post_read, _ := GetPost(post.Id)
	fmt.Println(post_read) // 獲取剛剛插入的記錄

	post_read.Content = "你好, Java"
	post_read.Author = "趙六"
	post_read.Update()

	posts, _ := Posts(5)
	fmt.Println(posts) // 獲取所有記錄

	post_read.Delete() // 刪除記錄
}

輸出結(jié)果:

sjg@sjg-PC:~/go/src/db_store1$ go run .
{0 你好, C++ 李四}
{1 你好, C++ 李四}
{1 你好, C++ 李四}
[{1 你好, Java 趙六}]
sjg@sjg-PC:~/go/src/db_store1$ go run .
{0 你好, C++ 李四}
{2 你好, C++ 李四}
{2 你好, C++ 李四}
[{2 你好, Java 趙六}]

值得注意的是,Db變量的類型 *sql.DB,其實(shí)不是數(shù)據(jù)庫(kù)連接的意義,它是一個(gè)數(shù)據(jù)庫(kù)句柄,它代表包含0個(gè)或者多個(gè)數(shù)據(jù)庫(kù)連接的連接池,因此,有些代碼會(huì)命名為pool。

代碼的頭部使用了匿名導(dǎo)入,另外,代碼中使用了包的init()函數(shù)用來(lái)初始化Db變量,可以參考??golang學(xué)習(xí)隨便記14-包和工具_(dá)sjg20010414的博客-CSDN博客golang中的init初始化函數(shù)_golang init函數(shù)_六月的的博客-CSDN博客

Golang中有context的概念(context包),database/sql包支持context,可以實(shí)現(xiàn)超時(shí)控制、性能日志等功能,具體表現(xiàn)是很多函數(shù)有2個(gè)版本,例如DB類型有Prepare(query)方法和PrepareContext(ctx, query)方法。關(guān)于context可以參考?詳解golang中的context - 知乎

要執(zhí)行事務(wù),并不復(fù)雜,大致步驟是:調(diào)用 Db.Begin() 返回事務(wù)對(duì)象tx,Tx類型具有和DB相似的一些方法,因此,原來(lái)用 Db 的地方換成tx,然后就是提交事務(wù)。我們把 Create() 改成事務(wù)方式,大致如下:

func (post *Post) Create() (err error) {
	sql := "INSERT INTO post (content, author) VALUES (?, ?)"
	tx, err := Db.Begin() // 啟動(dòng)事務(wù) tx
	if err != nil {
		log.Fatal(err)
		return
	}
	defer tx.Rollback() // 事務(wù)被提交后此句無(wú)效

	// stmt, err := Db.Prepare(sql)
	stmt, err := tx.Prepare(sql) // Tx 類型 有和 DB 類型相似的一些方法
	if err != nil {
		log.Fatal(err)
		return
	}
	defer stmt.Close()

	// err = stmt.QueryRow(post.Content, post.Author).Scan(&post.Id)  // pgsql 可以一步設(shè)置 post.id
	if result, err := stmt.Exec(post.Content, post.Author); err != nil {
		log.Fatal(err)
	} else {
		if last_insert_id, err := result.LastInsertId(); err != nil {
			log.Fatal(err)
		} else {
			post.Id = int(last_insert_id) // Mariadb/MySQL應(yīng)該支持執(zhí)行結(jié)果的 LastInsertId()
		}
	}

	if err := tx.Commit(); err != nil { // 提交事務(wù) tx
		log.Fatal(err)
	}
	return
}

我們來(lái)看看帶關(guān)聯(lián)表時(shí)如何操作數(shù)據(jù)庫(kù)。用下面的語(yǔ)句創(chuàng)建關(guān)聯(lián)表 comment

MariaDB [gwp]> CREATE TABLE comment (
    -> id int NOT NULL AUTO_INCREMENT,
    -> content text,
    -> author varchar(255),
    -> post_id int,
    -> PRIMARY KEY (id),
    -> FOREIGN KEY (post_id) REFERENCES post(id)
    -> );

新建一個(gè)項(xiàng)目 db_store2,編寫如下代碼(大量代碼和前述相同,就省略了):

package main

import (
	"database/sql"
	"errors"
	"fmt"
	_ "github.com/go-sql-driver/mysql"
	"log"
	"time"
)

type Post struct {
	Id       int
	Content  string
	Author   string
	Comments []Comment
}

type Comment struct {
	Id      int
	Content string
	Author  string
	Post    *Post
}

var Db *sql.DB

func init() { // 此 init 不顯式調(diào)用,自動(dòng)隱式調(diào)用,實(shí)現(xiàn)初始化全局變量 Db
// ..................
}

func (comment *Comment) Create() (err error) {
	if comment.Post == nil {
		err = errors.New("帖子未找到")
		return
	}
	var result sql.Result
	result, err = Db.Exec(`INSERT INTO comment (content, author, post_id) 
		VALUES (?, ?, ?)`, comment.Content, comment.Author, comment.Post.Id)
	if err != nil {
		return
	}
	var last_insert_id int64
	last_insert_id, err = result.LastInsertId()
	if err != nil {
		return
	}
	comment.Id = int(last_insert_id)
	return
}

func Posts(limit int) (posts []Post, err error) {
// .................................
}

func GetPost(id int) (post Post, err error) {
	post = Post{}
	post.Comments = []Comment{}
	err = Db.QueryRow("SELECT id, content, author FROM post WHERE id = ?", id). // QueryRow(..) 預(yù)期返回單行結(jié)果集
											Scan(&post.Id, &post.Content, &post.Author) // pgsql 可以 RETURNING id
	rows, err := Db.Query("SELECT id, content, author FROM comment")
	if err != nil {
		return
	}
	for rows.Next() {
		comment := Comment{Post: &post}
		err = rows.Scan(&comment.Id, &comment.Content, &comment.Author)
		if err != nil {
			return
		}
		post.Comments = append(post.Comments, comment)
	}
	rows.Close()
	return
}

func (post *Post) Create() (err error) {
// ......................................
}

func (post *Post) Update() (err error) {
// ......................................
}

func (post *Post) Delete() (err error) {
// ......................................
}

func main() {
	post := Post{Content: "你好, C++! " + time.Now().Format("15:04:05"), Author: "李四"}
	post.Create()

	comment := Comment{Content: "C++確實(shí)好,就是太難學(xué)" + time.Now().Format("15:04:05"), Author: "張三", Post: &post}
	comment.Create()

	post_read, _ := GetPost(post.Id)

	fmt.Println(post_read)                  // 獲取帖子
	fmt.Println(post_read.Comments)         // 獲取帖子的評(píng)論
	fmt.Println(post_read.Comments[0].Post) // 驗(yàn)證帖子第一條評(píng)論對(duì)應(yīng)的帖子是否為自身
}

顯示結(jié)果如下:

sjg@sjg-PC:~/go/src/db_store2$ go run .
{3 你好, C++! 15:54:29 李四 [{1 C++確實(shí)好,就是太難學(xué)15:54:29 張三 0xc000032140}]}
[{1 C++確實(shí)好,就是太難學(xué)15:54:29 張三 0xc000032140}]
&{3 你好, C++! 15:54:29 李四 [{1 C++確實(shí)好,就是太難學(xué)15:54:29 張三 0xc000032140}]}

我們從代碼發(fā)現(xiàn),要構(gòu)建一對(duì)多關(guān)系,就在代表“一”的結(jié)構(gòu)體里,添加代表“多”的切片(切片本質(zhì)上是指針);反過(guò)來(lái),在代表“多”的結(jié)構(gòu)體里,也添加一個(gè)指向“多”的指針成員??梢哉J(rèn)為,post有一個(gè)指針指向comments列表,列表成員有一個(gè)指針指向post,這么設(shè)計(jì)和yii2中的Model對(duì)關(guān)系的處理是類似的。文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-461927.html

到了這里,關(guān)于golang web學(xué)習(xí)隨便記4-內(nèi)存、文件、數(shù)據(jù)庫(kù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來(lái)自互聯(lián)網(wǎng)用戶投稿,該文觀點(diǎn)僅代表作者本人,不代表本站立場(chǎng)。本站僅提供信息存儲(chǔ)空間服務(wù),不擁有所有權(quán),不承擔(dān)相關(guān)法律責(zé)任。如若轉(zhuǎn)載,請(qǐng)注明出處: 如若內(nèi)容造成侵權(quán)/違法違規(guī)/事實(shí)不符,請(qǐng)點(diǎn)擊違法舉報(bào)進(jìn)行投訴反饋,一經(jīng)查實(shí),立即刪除!

領(lǐng)支付寶紅包贊助服務(wù)器費(fèi)用

相關(guān)文章

  • 041-WEB攻防-ASP應(yīng)用&HTTP.SYS&短文件&文件解析&Access注入&數(shù)據(jù)庫(kù)泄漏

    041-WEB攻防-ASP應(yīng)用&HTTP.SYS&短文件&文件解析&Access注入&數(shù)據(jù)庫(kù)泄漏

    1、ASP-SQL注入-Access數(shù)據(jù)庫(kù) 2、ASP-默認(rèn)安裝-數(shù)據(jù)庫(kù)泄漏下載 3、ASP-IIS-CVE短文件解析寫入 演示案例: ?ASP-默認(rèn)安裝-MDB數(shù)據(jù)庫(kù)泄漏下載 ?ASP-中間件-CVE短文件解析寫權(quán)限 ?ASP-SQL注入-SQLMAP使用ACCESS注入 由于大部分 ASP程序與ACCESS數(shù)據(jù)庫(kù)搭建 ,但ACCESS無(wú)需連接 在== 腳本文件中定義

    2024年04月13日
    瀏覽(21)
  • .net 6 web api項(xiàng)目添加日志(Serilog)管理,將日志輸出到控制臺(tái)、文件、數(shù)據(jù)庫(kù)

    .net 6 web api項(xiàng)目添加日志(Serilog)管理,將日志輸出到控制臺(tái)、文件、數(shù)據(jù)庫(kù)

    1.在nuget安裝下面幾個(gè)包 Serilog Serilog.AspNetCore //用于日志輸出到控制臺(tái) Serilog.Formatting.Compact //用于日志輸出到mysql數(shù)據(jù)庫(kù) Serilog.Sinks.MySQL //用于日志輸出到文件 Serilog.Sinks.RollingFile 2.在Program.cs文件配置日志參數(shù),依賴注入 別忘了在appsettings.json添加數(shù)據(jù)庫(kù)連接字符串 3. 使用日志

    2024年02月10日
    瀏覽(127)
  • Go語(yǔ)言(Golang)數(shù)據(jù)庫(kù)編程

    要想連接到 SQL 數(shù)據(jù)庫(kù),首先需要加載目標(biāo)數(shù)據(jù)庫(kù)的驅(qū)動(dòng),驅(qū)動(dòng)里面包含著于該數(shù)據(jù)庫(kù)交互的邏輯。 sql.Open() 數(shù)據(jù)庫(kù)驅(qū)動(dòng)的名稱 數(shù)據(jù)源名稱 得到一個(gè)指向 sql.DB 這個(gè) struct 的指針 sql.DB 是用來(lái)操作數(shù)據(jù)庫(kù)的,它代表了0個(gè)或者多個(gè)底層連接的池,這些連接由sql 包來(lái)維護(hù),sql 包會(huì)

    2024年02月03日
    瀏覽(93)
  • MySQL數(shù)據(jù)庫(kù)內(nèi)存配置與性能優(yōu)化:合理分配內(nèi)存,提升數(shù)據(jù)庫(kù)性能

    MySQL數(shù)據(jù)庫(kù)內(nèi)存配置與性能優(yōu)化:合理分配內(nèi)存,提升數(shù)據(jù)庫(kù)性能

    ???????? 引言 :MySQL是廣泛使用的關(guān)系型數(shù)據(jù)庫(kù)管理系統(tǒng),而合理配置數(shù)據(jù)庫(kù)的內(nèi)存是保障其高性能運(yùn)行的關(guān)鍵之一.本文將介紹如何根據(jù)MySQL數(shù)據(jù)庫(kù)內(nèi)存值大小來(lái)定義,以及這樣配置如何影響數(shù)據(jù)庫(kù)的性能 ? 內(nèi)存配置的基本原則 : innodb_buffer_pool_size :該參數(shù)定義了InnoDB存儲(chǔ)引擎

    2024年02月22日
    瀏覽(25)
  • golang 連接 oracle 數(shù)據(jù)庫(kù) 增刪改查

    ?1,golang 連接 oracle 數(shù)據(jù)庫(kù) ?2,增刪改查

    2024年02月09日
    瀏覽(32)
  • golang中給數(shù)據(jù)庫(kù)datetime格式賦值

    1、定義數(shù)據(jù)庫(kù)表映射結(jié)構(gòu)體如上,create_time字段在表里面是datetime格式。 2、如果CreateTime不給值,在存庫(kù)時(shí),create_time字段的值為NULL。 3、賦值時(shí),如下代碼

    2024年02月09日
    瀏覽(33)
  • golang操作數(shù)據(jù)庫(kù)--gorm框架、redis

    ①引入 ②初始化 ③增刪改查 官網(wǎng): http://gorm.io/ ①引入 ②初始化 ③增刪改查 說(shuō)明:Debug()可以查看執(zhí)行的sql語(yǔ)句。 ④gorm gen的使用 a.先安裝 (會(huì)安裝到gopath的bin目錄下,windows電腦,需要將該路徑加入到系統(tǒng)路徑) eg : b.舉例: 說(shuō)明1:windows電腦go install之后,把exe添加到系統(tǒng)路

    2024年02月10日
    瀏覽(26)
  • 內(nèi)存數(shù)據(jù)庫(kù)如何發(fā)揮內(nèi)存優(yōu)勢(shì)?

    與以磁盤存儲(chǔ)為主的普通數(shù)據(jù)庫(kù)相比,內(nèi)存數(shù)據(jù)庫(kù)的數(shù)據(jù)訪問(wèn)速度可以高出幾個(gè)數(shù)量級(jí),能大幅提高運(yùn)算性能,更適合高并發(fā)、低延時(shí)的業(yè)務(wù)場(chǎng)景。 不過(guò),當(dāng)前大部分內(nèi)存數(shù)據(jù)庫(kù)仍然采用 SQL 模型,而 SQL 缺乏一些必要的數(shù)據(jù)類型和運(yùn)算,不能充分利用內(nèi)存的特征實(shí)現(xiàn)某些高

    2024年02月03日
    瀏覽(23)
  • Golang 程序漏洞檢測(cè)利器 govulncheck(二):漏洞數(shù)據(jù)庫(kù)詳解

    上一篇文章詳細(xì)介紹了 Golang 程序漏洞掃描工具 govulncheck 的使用方法,govulncheck 強(qiáng)大功能的背后,離不開(kāi) Go 漏洞數(shù)據(jù)庫(kù)(Go vulnerability database)的支持,接下來(lái)詳細(xì)講解下 Go 漏洞數(shù)據(jù)庫(kù)相關(guān)的知識(shí)。 在當(dāng)今數(shù)字化的世界中,軟件安全是至關(guān)重要的。隨著 Golang 在開(kāi)發(fā)領(lǐng)域的日

    2024年02月10日
    瀏覽(26)
  • Redis內(nèi)存數(shù)據(jù)庫(kù)

    Redis內(nèi)存數(shù)據(jù)庫(kù) NoSQL數(shù)據(jù)庫(kù)簡(jiǎn)介 Redis簡(jiǎn)介 Redis應(yīng)用場(chǎng)景 windows下安裝和使用Redis 在linux下安裝redis Redis數(shù)據(jù)可視化RedisDesktopManager Redis配置 Redis 數(shù)據(jù)類型 Redis 字符串(String) Redis 哈希(Hash) Redis 列表(List) Redis 集合(Set) Redis 有序集合(sorted set) Redis key命令 Redis連接命令 Redis服務(wù)器命令

    2024年02月09日
    瀏覽(24)

覺(jué)得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請(qǐng)作者喝杯咖啡吧~博客贊助

支付寶掃一掃領(lǐng)取紅包,優(yōu)惠每天領(lǐng)

二維碼1

領(lǐng)取紅包

二維碼2

領(lǐng)紅包