四诗茎、GO Web編程示例 - MySQL數(shù)據(jù)庫

簡介

此示例將研究GO語言中MySQL數(shù)據(jù)庫訪問的基礎(chǔ)知識工坊,創(chuàng)建數(shù)據(jù)庫表,存儲和讀取數(shù)據(jù)敢订。

安裝go-sql-driver / mysql軟件包

Go編程語言附帶了一個名為database / sql的軟件包王污,用于查詢各種SQL數(shù)據(jù)庫。 這很有用楚午,因為它將所有通用SQL功能抽象為一個API供你使用昭齐,但 Go不包括數(shù)據(jù)庫驅(qū)動程序。 在Go中矾柜,數(shù)據(jù)庫驅(qū)動程序是一個用于實現(xiàn)特定數(shù)據(jù)庫底層細節(jié)的軟件包(本例為MySQL)阱驾。由于無法預(yù)見哪些數(shù)據(jù)庫將來都會投入使用,而支持每個可能的數(shù)據(jù)庫將需要大量維護工作怪蔑,因此Go語言未包含數(shù)據(jù)庫驅(qū)動程序里覆,需要額外進行安裝。
要安裝MySQL數(shù)據(jù)庫驅(qū)動程序缆瓣,只需要在終端中執(zhí)行以下操作:

go get -u github.com/go-sql-driver/mysql

連接到MySQL數(shù)據(jù)庫

安裝所有必需的軟件包后喧枷,需要檢查的第一件事是,是否可以成功連接到MySQL數(shù)據(jù)庫弓坞。 如果尚未運行MySQL數(shù)據(jù)庫服務(wù)器隧甚,可以通過Docker輕松的啟動一個實例。 這是MySQL的映像的官方Docker鏡像:https://hub.docker.com/_/mysql
要檢查是否可以連接到數(shù)據(jù)庫昼丑,請導(dǎo)入數(shù)據(jù)庫/ sql和go-sql-driver / mysql軟件包呻逆,并按如下所示打開連接:

import "database/sql"
import _ "go-sql-driver/mysql"



// Configure the database connection (always check errors)
db, err := sql.Open("mysql", "username:password@(127.0.0.1:3306)/dbname?parseTime=true")


// Initialize the first connection to the database, to see if everything works correctly.
// Make sure to check the error.
err := db.Ping()

創(chuàng)建第一個數(shù)據(jù)庫表

我們數(shù)據(jù)庫中的每個數(shù)據(jù)條目都存儲在一個特定的表中。 數(shù)據(jù)庫表由列和行組成菩帝。 這些列為每個數(shù)據(jù)條目提供一個標簽并指定其類型咖城。 這些行是插入的數(shù)據(jù)值。 在我們的第一個示例中呼奢,我們想要創(chuàng)建一個像這樣的表:

id username password created_at
1 johndoe secret 2019-08-10 12:30:00

創(chuàng)建表格的SQL命令如下:

CREATE TABLE users (
    id INT AUTO_INCREMENT,
    username TEXT NOT NULL,
    password TEXT NOT NULL,
    created_at DATETIME,
    PRIMARY KEY (id)
);

現(xiàn)在有了SQL命令宜雀,可以使用database/sql包在MySQL數(shù)據(jù)庫中創(chuàng)建表:

query := `
    CREATE TABLE users (
        id INT AUTO_INCREMENT,
        username TEXT NOT NULL,
        password TEXT NOT NULL,
        created_at DATETIME,
        PRIMARY KEY (id)
    );`

// Executes the SQL query in our database. Check err to ensure there was no error.
_, err := db.Exec(query)

插入第一個用戶

如果你熟悉SQL,向表中插入新數(shù)據(jù)就像創(chuàng)建表一樣容易握础。 需要注意的一件事是:默認情況下辐董,Go使用準備好的語句將動態(tài)數(shù)據(jù)插入SQL查詢語句中,這是一種將用戶提供的數(shù)據(jù)安全地傳遞到數(shù)據(jù)庫的方式禀综,而不會造成任何損壞简烘。 在Web編程的早期苔严,程序員將帶有查詢的數(shù)據(jù)直接傳遞到數(shù)據(jù)庫,這導(dǎo)致了巨大的漏洞孤澎,并可能破壞整個Web應(yīng)用程序届氢,請不要那樣做。
要將第一個用戶插入數(shù)據(jù)庫表覆旭,創(chuàng)建一個如下的SQL查詢退子。此處省略了id列,因為它是由MySQL自動設(shè)置的型将。 問號告訴SQL驅(qū)動程序寂祥,它們是實際數(shù)據(jù)的占位符。 在這里可以看到準備好的語句七兜。

INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)

現(xiàn)在可以在Go中使用此語句插入用戶丸凭。

import "time"

username := "johndoe"
password := "secret"
createdAt := time.Now()

// Inserts our data into the users table and returns with the result and a possible error.
// The result contains information about the last inserted id (which was auto-generated for us) and the count of rows this query affected.
result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)

要獲取用戶在數(shù)據(jù)庫中最新創(chuàng)建的ID,只需按以下方式獲染:

userID, err := result.LastInsertId()

查詢用戶表

現(xiàn)在表中有一個用戶贮乳,我們想查詢它并獲取其所有信息。 在Go中有兩種查詢表的方法恬惯。 db.Query可以迭代查詢多行;還有db.QueryRow只查詢特定的行亚茬。
查詢特定行的工作原理基本上與之前介紹的所有其他SQL命令一樣酪耳。
SQL命令通過其ID查詢單個用戶,如下所示:

SELECT id, username, password, created_at FROM users WHERE id = ?

在Go中首先聲明一些變量來存儲數(shù)據(jù)刹缝,然后查詢單個數(shù)據(jù)庫行碗暗,如下所示:

var (
    id        int
    username  string
    password  string
    createdAt time.Time
)

// Query the database and scan the values into out variables. Don't forget to check for errors.
query := `SELECT id, username, password, created_at FROM users WHERE id = ?`
err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt)

查詢所有用戶

前面的部分介紹了如何查詢單個用戶行。 而許多應(yīng)用程序都有查詢所有用戶的應(yīng)用梢夯。 這與上面的示例相似言疗,只是涉及更多的編碼。
我們可以使用上面示例中的SQL命令并修改WHERE子句颂砸。 這樣可以查詢所有用戶噪奄。

SELECT id, username, password, created_at FROM users

在Go中首先聲明一些變量來存儲數(shù)據(jù),然后查詢單個數(shù)據(jù)庫行人乓,如下所示:

type user struct {
  id        int
  username  string
  password  string
  createdAt time.Time
}

rows, err := db.Query(`SELECT id, username, password, created_at FROM users`) // check err
defer rows.Close()

var users []user
for rows.Next() {
  var u user
  err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt) // check err
  users = append(users, u)
}
err := rows.Err() // check err

user切片現(xiàn)在包含的內(nèi)容如下:

users {
    user {
        id:        1,
        username:  "johndoe",
        password:  "secret",
        createdAt: time.Time{wall: 0x0, ext: 63701044325, loc: (*time.Location)(nil)},
    },
    user {
        id:        2,
        username:  "alice",
        password:  "bob",
        createdAt: time.Time{wall: 0x0, ext: 63701044622, loc: (*time.Location)(nil)},
    },
}

刪除用戶

最后勤篮,從表中刪除用戶與上述各節(jié)中的.Exec一樣簡單:

_, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1) // check err

代碼

package main

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

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

func main() {
    db, err := sql.Open("mysql", "root:root@(127.0.0.1:3306)/root?parseTime=true")
    if err != nil {
        log.Fatal(err)
    }
    if err := db.Ping(); err != nil {
        log.Fatal(err)
    }

    { // Create a new table
        query := `
            CREATE TABLE users (
                id INT AUTO_INCREMENT,
                username TEXT NOT NULL,
                password TEXT NOT NULL,
                created_at DATETIME,
                PRIMARY KEY (id)
            );`

        if _, err := db.Exec(query); err != nil {
            log.Fatal(err)
        }
    }

    { // Insert a new user
        username := "johndoe"
        password := "secret"
        createdAt := time.Now()

        result, err := db.Exec(`INSERT INTO users (username, password, created_at) VALUES (?, ?, ?)`, username, password, createdAt)
        if err != nil {
            log.Fatal(err)
        }

        id, err := result.LastInsertId()
        fmt.Println(id)
    }

    { // Query a single user
        var (
            id        int
            username  string
            password  string
            createdAt time.Time
        )

        query := "SELECT id, username, password, created_at FROM users WHERE id = ?"
        if err := db.QueryRow(query, 1).Scan(&id, &username, &password, &createdAt); err != nil {
            log.Fatal(err)
        }

        fmt.Println(id, username, password, createdAt)
    }

    { // Query all users
        type user struct {
            id        int
            username  string
            password  string
            createdAt time.Time
        }

        rows, err := db.Query(`SELECT id, username, password, created_at FROM users`)
        if err != nil {
            log.Fatal(err)
        }
        defer rows.Close()

        var users []user
        for rows.Next() {
            var u user

            err := rows.Scan(&u.id, &u.username, &u.password, &u.createdAt)
            if err != nil {
                log.Fatal(err)
            }
            users = append(users, u)
        }
        if err := rows.Err(); err != nil {
            log.Fatal(err)
        }

        fmt.Printf("%#v", users)
    }

    {
        _, err := db.Exec(`DELETE FROM users WHERE id = ?`, 1)
        if err != nil {
            log.Fatal(err)
        }
    }
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市色罚,隨后出現(xiàn)的幾起案子碰缔,更是在濱河造成了極大的恐慌,老刑警劉巖戳护,帶你破解...
    沈念sama閱讀 218,451評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件金抡,死亡現(xiàn)場離奇詭異瀑焦,居然都是意外死亡,警方通過查閱死者的電腦和手機梗肝,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,172評論 3 394
  • 文/潘曉璐 我一進店門榛瓮,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人统捶,你說我怎么就攤上這事榆芦。” “怎么了喘鸟?”我有些...
    開封第一講書人閱讀 164,782評論 0 354
  • 文/不壞的土叔 我叫張陵匆绣,是天一觀的道長。 經(jīng)常有香客問我什黑,道長崎淳,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,709評論 1 294
  • 正文 為了忘掉前任愕把,我火速辦了婚禮拣凹,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘恨豁。我一直安慰自己嚣镜,他們只是感情好,可當(dāng)我...
    茶點故事閱讀 67,733評論 6 392
  • 文/花漫 我一把揭開白布橘蜜。 她就那樣靜靜地躺著菊匿,像睡著了一般。 火紅的嫁衣襯著肌膚如雪计福。 梳的紋絲不亂的頭發(fā)上跌捆,一...
    開封第一講書人閱讀 51,578評論 1 305
  • 那天,我揣著相機與錄音象颖,去河邊找鬼佩厚。 笑死,一個胖子當(dāng)著我的面吹牛说订,可吹牛的內(nèi)容都是我干的抄瓦。 我是一名探鬼主播,決...
    沈念sama閱讀 40,320評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼克蚂,長吁一口氣:“原來是場噩夢啊……” “哼闺鲸!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起埃叭,我...
    開封第一講書人閱讀 39,241評論 0 276
  • 序言:老撾萬榮一對情侶失蹤摸恍,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體立镶,經(jīng)...
    沈念sama閱讀 45,686評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡壁袄,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,878評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了媚媒。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片嗜逻。...
    茶點故事閱讀 39,992評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖缭召,靈堂內(nèi)的尸體忽然破棺而出栈顷,到底是詐尸還是另有隱情,我是刑警寧澤嵌巷,帶...
    沈念sama閱讀 35,715評論 5 346
  • 正文 年R本政府宣布萄凤,位于F島的核電站,受9級特大地震影響搪哪,放射性物質(zhì)發(fā)生泄漏靡努。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,336評論 3 330
  • 文/蒙蒙 一晓折、第九天 我趴在偏房一處隱蔽的房頂上張望惑朦。 院中可真熱鬧,春花似錦漓概、人聲如沸漾月。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,912評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽栅屏。三九已至,卻和暖如春堂鲜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背护奈。 一陣腳步聲響...
    開封第一講書人閱讀 33,040評論 1 270
  • 我被黑心中介騙來泰國打工缔莲, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人霉旗。 一個月前我還...
    沈念sama閱讀 48,173評論 3 370
  • 正文 我出身青樓痴奏,卻偏偏與公主長得像,于是被迫代替她去往敵國和親厌秒。 傳聞我的和親對象是個殘疾皇子读拆,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,947評論 2 355