溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Go 語言如何操作常見的數(shù)據(jù)庫

發(fā)布時間:2020-08-08 09:19:46 來源:ITPUB博客 閱讀:205 作者:hj8828 欄目:數(shù)據(jù)庫

使用MySQL數(shù)據(jù)庫

目前 Internet 上流行的網(wǎng)站構(gòu)架方式是 LAMP/LNMP,其中的 M 即 MySQL, 作為數(shù)據(jù)庫,MySQL 以免費(fèi)、開源、使用方便為優(yōu)勢成為了很多Web開發(fā)的后端數(shù)據(jù)庫存儲引擎。

Go中支持MySQL的驅(qū)動目前比較多,有如下幾種,有些是支持database/sql標(biāo)準(zhǔn),而有些是采用了自己的實(shí)現(xiàn)接口,常用的有如下幾種:

  • https://github.com/go-sql-driver/mysql 支持database/sql,全部采用go寫。

  • https://github.com/ziutek/mymysql 支持database/sql,也支持自定義的接口,全部采用go寫。

  • https://github.com/Philio/GoMySQL 不支持database/sql,自定義接口,全部采用go寫。

接下來的例子主要以第一個驅(qū)動為例,推薦主要理由是:

  • 這個驅(qū)動比較新,維護(hù)的比較好;

  • 完全支持database/sql接口;

  • 支持keepalive,保持長連接。

接下來的幾個小節(jié)里面我們都將采用同一個數(shù)據(jù)庫表結(jié)構(gòu):數(shù)據(jù)庫test,用戶表userinfo,關(guān)聯(lián)用戶信息表userdetail。



 1


CREATE

 

TABLE

 

`userinfo`

 (

2      `uid`   INT ( 10 NOT   NULL  AUTO_INCREMENT,
3      `username`   VARCHAR ( 64 NULL   DEFAULT   NULL ,
4      `departname`   VARCHAR ( 64 NULL   DEFAULT   NULL ,
5      `created`   DATE   NULL   DEFAULT   NULL ,
6     PRIMARY  KEY  ( `uid` )
7 );
8
9 CREATE   TABLE   `userdetail`  (
10      `uid`   INT ( 10 NOT   NULL   DEFAULT   '0' ,
11      `intro`   TEXT   NULL ,
12      `profile`   TEXT   NULL ,
13     PRIMARY  KEY  ( `uid` )
14 )

如下示例將示范如何使用database/sql接口對數(shù)據(jù)庫表進(jìn)行增刪改查操作:



 1


// 示例代碼11-15


2 package  main
3
4 import  (
5      "database/sql"
6      "fmt"
7      //"time"
8
9     _  "github.com/go-sql-driver/mysql"
10 )
11
12 func   main ()  {
13     db, err := sql.Open( "mysql" "zuolan:zuolan@/test?charset=utf8" )
14     checkErr(err)
15
16      //插入數(shù)據(jù)
17     stmt, err := db.Prepare( "INSERT userinfo SET username=?,departname=?,created=?" )
18     checkErr(err)
19
20     res, err := stmt.Exec( "張三" "研發(fā)部門" "2017-09-09" )
21     checkErr(err)
22
23     id, err := res.LastInsertId()
24     checkErr(err)
25
26     fmt.Println(id)
27      //更新數(shù)據(jù)
28     stmt, err = db.Prepare( "update userinfo set username=? where uid=?" )
29     checkErr(err)
30
31     res, err = stmt.Exec( "zuolanupdate" , id)
32     checkErr(err)
33
34     affect, err := res.RowsAffected()
35     checkErr(err)
36
37     fmt.Println(affect)
38
39      //查詢數(shù)據(jù)
40     rows, err := db.Query( "SELECT * FROM userinfo" )
41     checkErr(err)
42
43      for  rows.Next() {
44          var  uid  int
45          var  username  string
46          var  department  string
47          var  created  string
48         err = rows.Scan(&uid, &username, &department, &created)
49         checkErr(err)
50         fmt.Println(uid)
51         fmt.Println(username)
52         fmt.Println(department)
53         fmt.Println(created)
54     }
55
56      //刪除數(shù)據(jù)
57     stmt, err = db.Prepare( "delete from userinfo where uid=?" )
58     checkErr(err)
59
60     res, err = stmt.Exec(id)
61     checkErr(err)
62
63     affect, err = res.RowsAffected()
64     checkErr(err)
65
66     fmt.Println(affect)
67
68     db.Close()
69
70 }
71
72 func   checkErr (err error)  {
73      if  err !=  nil  {
74          panic (err)
75     }
76 }

通過上面的代碼我們可以看出,Go操作MySQL數(shù)據(jù)庫是很方便的。

sql.Open()函數(shù)用來打開一個注冊過的數(shù)據(jù)庫驅(qū)動,go-sql-driver中注冊了mysql這個數(shù)據(jù)庫驅(qū)動,第二個參數(shù)是DSN(Data Source Name),它是go-sql-driver定義的一些數(shù)據(jù)庫鏈接和配置信息。它支持如下格式:



1


user

@

unix

(/

path

/

to

/

socket

)/

dbname

?

charset

=

utf8


2 user:password@tcp(localhost: 5555 )/dbname?charset=utf8
3 user:password@/dbname
4 user:password@tcp([de:ad:be:ef::ca:fe]: 80 )/dbname

db.Prepare()函數(shù)用來返回準(zhǔn)備要執(zhí)行的sql操作,然后返回準(zhǔn)備完畢的執(zhí)行狀態(tài)。

db.Query()函數(shù)用來直接執(zhí)行Sql返回Rows結(jié)果。

stmt.Exec()函數(shù)用來執(zhí)行stmt準(zhǔn)備好的SQL語句

我們可以看到我們傳入的參數(shù)都是=?對應(yīng)的數(shù)據(jù),這樣做的方式可以一定程度上防止SQL注入。

使用SQLite數(shù)據(jù)庫

SQLite是一個開源的嵌入式關(guān)系數(shù)據(jù)庫,實(shí)現(xiàn)自包容、零配置、支持事務(wù)的SQL數(shù)據(jù)庫引擎。其特點(diǎn)是高度便攜、使用方便、結(jié)構(gòu)緊湊、高效、可靠。與其他數(shù)據(jù)庫管理系統(tǒng)不同,SQLite的安裝和運(yùn)行非常簡單,在大多數(shù)情況下,只要確保SQLite的二進(jìn)制文件存在即可開始創(chuàng)建、連接和使用數(shù)據(jù)庫。

如果您正在尋找一個嵌入式數(shù)據(jù)庫項(xiàng)目或解決方案,SQLite是絕對值得考慮。SQLite可以是說開源的Access。

Go支持sqlite的驅(qū)動也比較多,但是很多都不支持database/sql接口:

  • https://github.com/mattn/go-sqlite3 支持database/sql接口,基于cgo(關(guān)于cgo的知識請參看官方文檔)。

  • https://github.com/feyeleanor/gosqlite3 不支持database/sql接口,基于cgo。

  • https://github.com/phf/go-sqlite3 不支持database/sql接口,基于cgo。

目前支持database/sql的SQLite數(shù)據(jù)庫驅(qū)動比較少,采用標(biāo)準(zhǔn)接口有利于以后出現(xiàn)更好的驅(qū)動的時候做遷移,因此本節(jié)后面都采用第一個驅(qū)動。

示例的數(shù)據(jù)庫表結(jié)構(gòu)如下所示,相應(yīng)的建表SQL:



 1


CREATE

 

TABLE

 

`userinfo`

 (

2      `uid`   INTEGER  PRIMARY  KEY  AUTOINCREMENT,
3      `username`   VARCHAR ( 64 NULL ,
4      `departname`   VARCHAR ( 64 NULL ,
5      `created`   DATE   NULL
6 );
7
8 CREATE   TABLE   `userdeatail`  (
9      `uid`   INT ( 10 NULL ,
10      `intro`   TEXT   NULL ,
11      `profile`   TEXT   NULL ,
12     PRIMARY  KEY  ( `uid` )
13 );

看下面Go程序是如何操作數(shù)據(jù)庫表,進(jìn)行數(shù)據(jù)增刪改查的:



 1


// 示例代碼11-16


2 package  main
3
4 import  (
5      "database/sql"
6      "fmt"
7      "time"
8
9     _  "github.com/mattn/go-sqlite3"
10 )
11
12 func   main ()  {
13     db, err := sql.Open( "sqlite3" "./demo.db" )
14     checkErr(err)
15
16      //插入數(shù)據(jù)
17     stmt, err := db.Prepare( "INSERT INTO userinfo(username, departname, created) values(?,?,?)" )
18     checkErr(err)
19
20     res, err := stmt.Exec( "張三" "研發(fā)部門" "2017-09-09" )
21     checkErr(err)
22
23     id, err := res.LastInsertId()
24     checkErr(err)
25
26     fmt.Println(id)
27      //更新數(shù)據(jù)
28     stmt, err = db.Prepare( "update userinfo set username=? where uid=?" )
29     checkErr(err)
30
31     res, err = stmt.Exec( "zuolanupdate" , id)
32     checkErr(err)
33
34     affect, err := res.RowsAffected()
35     checkErr(err)
36
37     fmt.Println(affect)
38
39      //查詢數(shù)據(jù)
40     rows, err := db.Query( "SELECT * FROM userinfo" )
41     checkErr(err)
42
43      for  rows.Next() {
44          var  uid  int
45          var  username  string
46          var  department  string
47          var  created time.Time
48         err = rows.Scan(&uid, &username, &department, &created)
49         checkErr(err)
50         fmt.Println(uid)
51         fmt.Println(username)
52         fmt.Println(department)
53         fmt.Println(created)
54     }
55
56      //刪除數(shù)據(jù)
57     stmt, err = db.Prepare( "delete from userinfo where uid=?" )
58     checkErr(err)
59
60     res, err = stmt.Exec(id)
61     checkErr(err)
62
63     affect, err = res.RowsAffected()
64     checkErr(err)
65
66     fmt.Println(affect)
67
68     db.Close()
69
70 }
71
72 func   checkErr (err error)  {
73      if  err !=  nil  {
74          panic (err)
75     }
76 }

我們可以看到上面的代碼和MySQL例子里面的代碼幾乎是一模一樣的,唯一改變的就是導(dǎo)入的驅(qū)動改變了,然后調(diào)用sql.Open是采用了SQLite的方式打開。

使用PostgreSQL數(shù)據(jù)庫

PostgreSQL是一個自由的對象-關(guān)系數(shù)據(jù)庫服務(wù)器(數(shù)據(jù)庫管理系統(tǒng)),它在靈活的BSD風(fēng)格許可證下發(fā)行。它提供了相對其他開放源代碼數(shù)據(jù)庫系統(tǒng)(比如MySQL和Firebird),和對專有系統(tǒng)比如Oracle、Sybase、IBM的DB2和Microsoft SQL Server的一種選擇。

PostgreSQL和MySQL比較,它更加龐大一點(diǎn),因?yàn)樗怯脕硖娲鶲racle而設(shè)計(jì)的。所以在企業(yè)應(yīng)用中采用PostgreSQL是一個明智的選擇。

MySQL被Oracle收購之后正在逐步的封閉(自MySQL 5.5.31以后的所有版本將不再遵循GPL協(xié)議),鑒于此,將來我們也許會選擇PostgreSQL而不是MySQL作為項(xiàng)目的后端數(shù)據(jù)庫。

Go實(shí)現(xiàn)的支持PostgreSQL的驅(qū)動也很多,因?yàn)閲夂芏嗳嗽陂_發(fā)中使用了這個數(shù)據(jù)庫。

  • https://github.com/lib/pq 支持database/sql驅(qū)動,純Go寫的;

  • https://github.com/jbarham/gopgsqldriver 支持database/sql驅(qū)動,純Go寫的;

  • https://github.com/lxn/go-pgsql 支持database/sql驅(qū)動,純Go寫的。

在下面的示例中采用第一個驅(qū)動,因?yàn)樗壳笆褂玫娜俗疃?,在Github上也比較活躍。

數(shù)據(jù)庫建表語句:



 1


CREATE

 

TABLE

 userinfo

2 (
3     uid  serial   NOT   NULL ,
4     username  character   varying ( 100 NOT   NULL ,
5     departname  character   varying ( 500 NOT   NULL ,
6     Created  date ,
7      CONSTRAINT  userinfo_pkey PRIMARY  KEY  (uid)
8 )
9 WITH  (OIDS= FALSE );
10
11 CREATE   TABLE  userdeatail
12 (
13     uid  integer ,
14     intro  character   varying ( 100 ),
15     profile  character   varying ( 100 )
16 )
17 WITH (OIDS= FALSE );

看下面這個Go如何操作數(shù)據(jù)庫表,進(jìn)行數(shù)據(jù)的增刪改查:



 1


// 示例代碼11-17


2 package  main
3
4 import  (
5      "database/sql"
6      "fmt"
7
8     _  "github.com/lib/pq"
9 )
10
11 func   main ()  {
12     db, err := sql.Open( "postgres" "user=zuolan password=zuolan dbname=test sslmode=disable" )
13     checkErr(err)
14
15      //插入數(shù)據(jù)
16     stmt, err := db.Prepare( "INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) RETURNING uid" )
17     checkErr(err)
18
19     res, err := stmt.Exec( "張三" "研發(fā)部門" "2017-09-09" )
20     checkErr(err)
21
22      // pg不支持這個函數(shù),因?yàn)樗麤]有類似MySQL的自增ID
23      // id, err := res.LastInsertId()
24      // checkErr(err)
25      // fmt.Println(id)
26
27      var  lastInsertId  int
28     err = db.QueryRow( "INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) returning uid;" "zuolan" "研發(fā)部門" "2017-09-09" ).Scan(&lastInsertId)
29     checkErr(err)
30     fmt.Println( "最后插入id =" , lastInsertId)
31
32
33      //更新數(shù)據(jù)
34     stmt, err = db.Prepare( "update userinfo set username=$1 where uid=$2" )
35     checkErr(err)
36
37     res, err = stmt.Exec( "zuolanupdate" 1 )
38     checkErr(err)
39
40     affect, err := res.RowsAffected()
41     checkErr(err)
42
43     fmt.Println(affect)
44
45      //查詢數(shù)據(jù)
46     rows, err := db.Query( "SELECT * FROM userinfo" )
47     checkErr(err)
48
49      for  rows.Next() {
50          var  uid  int
51          var  username  string
52          var  department  string
53          var  created  string
54         err = rows.Scan(&uid, &username, &department, &created)
55         checkErr(err)
56         fmt.Println(uid)
57         fmt.Println(username)
58         fmt.Println(department)
59         fmt.Println(created)
60     }
61
62      //刪除數(shù)據(jù)
63     stmt, err = db.Prepare( "delete from userinfo where uid=$1" )
64     checkErr(err)
65
66     res, err = stmt.Exec( 1 )
67     checkErr(err)
68
69     affect, err = res.RowsAffected()
70     checkErr(err)
71
72     fmt.Println(affect)
73
74     db.Close()
75
76 }
77
78 func   checkErr (err error)  {
79      if  err !=  nil  {
80          panic (err)
81     }
82 }

從上面的代碼我們可以看到,PostgreSQL是通過 1, 2這種方式來指定要傳遞的參數(shù),而不是MySQL中的?,另外在sql.Open中的dsn信息的格式也與MySQL的驅(qū)動中的dsn格式不一樣,所以在使用時請注意它們的差異。

還有pg不支持LastInsertId函數(shù),因?yàn)镻ostgreSQL內(nèi)部沒有實(shí)現(xiàn)類似MySQL的自增ID返回,其他的代碼幾乎是一模一樣。

NoSQL數(shù)據(jù)庫操作

NoSQL(Not Only SQL),指的是非關(guān)系型的數(shù)據(jù)庫。隨著Web2.0的興起,傳統(tǒng)的關(guān)系數(shù)據(jù)庫在應(yīng)付Web2.0網(wǎng)站,特別是超大規(guī)模和高并發(fā)的SNS類型的Web2.0純動態(tài)網(wǎng)站已經(jīng)顯得力不從心,暴露了很多難以克服的問題,而非關(guān)系型的數(shù)據(jù)庫則由于其本身的特點(diǎn)得到了非常迅速的發(fā)展。

而Go語言作為21世紀(jì)的C語言,對NOSQL的支持也是很好,目前流行的NOSQL主要有redis、mongoDB、Cassandra和Membase等。這些數(shù)據(jù)庫都有高性能、高并發(fā)讀寫等特點(diǎn),目前已經(jīng)廣泛應(yīng)用于各種應(yīng)用中。

1. Redis

redis是一個key-value存儲系統(tǒng)。和Memcached類似,它支持存儲的value類型相對更多,包括string(字符串)、list(鏈表)、set(集合)和zset(有序集合)。

目前應(yīng)用redis最廣泛的應(yīng)該是新浪微博平臺,其次還有Facebook收購的圖片社交網(wǎng)站instagram。Go目前支持redis的驅(qū)動有如下:

  • https://github.com/garyburd/redigo

  • https://github.com/go-redis/redis

  • https://github.com/hoisie/redis

  • https://github.com/alphazero/Go-Redis

  • https://github.com/simonz05/godis

推薦使用第一個,用法上和上面驅(qū)動沒有太大區(qū)別,限于篇幅不再展開。

2. mongoDB

MongoDB是一個高性能,開源,無模式的文檔型數(shù)據(jù)庫,是一個介于關(guān)系數(shù)據(jù)庫和非關(guān)系數(shù)據(jù)庫之間的產(chǎn)品,是非關(guān)系數(shù)據(jù)庫當(dāng)中功能最豐富,最像關(guān)系數(shù)據(jù)庫的。他支持的數(shù)據(jù)結(jié)構(gòu)非常松散,采用的是類似json的bjson格式來存儲數(shù)據(jù),因此可以存儲比較復(fù)雜的數(shù)據(jù)類型。Mongo最大的特點(diǎn)是他支持的查詢語言非常強(qiáng)大,其語法有點(diǎn)類似于面向?qū)ο蟮牟樵冋Z言,幾乎可以實(shí)現(xiàn)類似關(guān)系數(shù)據(jù)庫單表查詢的絕大部分功能,而且還支持對數(shù)據(jù)建立索引。

目前Go支持mongoDB最好的驅(qū)動就是mgo(http://labix.org/mgo),這個驅(qū)動目前最有可能成為官方的pkg。安裝mgo的命令為:

1go get gopkg.in/mgo.v2


向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI