Files
build-web-application-with-…/zh-tw/05.4.md
2019-06-22 23:41:28 +08:00

135 lines
3.9 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 5.4 使用 PostgreSQL 資料庫
PostgreSQL 是一個自由的物件-關聯式資料庫伺服器(資料庫管理系統),它在靈活的 BSD-風格許可證下發行。它提供了相對其他開放原始碼資料庫系統(比如 MySQL 和 Firebird),和對專有系統比如 Oracle、Sybase、IBM 的 DB2 和 Microsoft SQL Server 的一種選擇。
PostgreSQL 和 MySQL 比較,它更加龐大一點,因為它是用來替代 Oracle 而設計的。所以在企業應用中採用 PostgreSQL 是一個明智的選擇。
MySQL 被 Oracle 收購之後正在逐步的封閉(自 MySQL 5.5.31 以後的所有版本將不再遵循 GPL 協議),鑑於此,將來我們也許會選擇 PostgreSQL 而不是 MySQL 作為專案的後端資料庫。
## 驅動
Go 實現的支援 PostgreSQL 的驅動也很多,因為國外很多人在開發中使用了這個資料庫。
- https://github.com/lib/pq 支援 database/sql 驅動,純 Go 寫的
- https://github.com/jbarham/gopgsqldriver 支援 database/sql 驅動,純 Go 寫的
- https://github.com/lxn/go-pgsql 支援 database/sql 驅動,純 Go 寫的
在下面的範例中我採用了第一個驅動,因為它目前使用的人最多,在 GitHub 上也比較活躍。
## 範例程式碼
資料庫建表語句:
```sql
CREATE TABLE userinfo
(
uid serial NOT NULL,
username character varying(100) NOT NULL,
department character varying(500) NOT NULL,
Created date,
CONSTRAINT userinfo_pkey PRIMARY KEY (uid)
)
WITH (OIDS=FALSE);
CREATE TABLE userdetail
(
uid integer,
intro character varying(100),
profile character varying(100)
)
WITH(OIDS=FALSE);
```
看下面這個 Go 如何操作資料庫表資料 : 增刪改查
```Go
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
func main() {
db, err := sql.Open("postgres", "user=astaxie password=astaxie dbname=test sslmode=disable")
checkErr(err)
//插入資料
stmt, err := db.Prepare("INSERT INTO userinfo(username,department,created) VALUES($1,$2,$3) RETURNING uid")
checkErr(err)
res, err := stmt.Exec("astaxie", "研發部門", "2012-12-09")
checkErr(err)
//pg 不支援這個函式,因為他沒有類似 MySQL 的自增 ID
// id, err := res.LastInsertId()
// checkErr(err)
// fmt.Println(id)
var lastInsertId int
err = db.QueryRow("INSERT INTO userinfo(username,departname,created) VALUES($1,$2,$3) returning uid;", "astaxie", "研發部門", "2012-12-09").Scan(&lastInsertId)
checkErr(err)
fmt.Println("最後插入 id =", lastInsertId)
//更新資料
stmt, err = db.Prepare("update userinfo set username=$1 where uid=$2")
checkErr(err)
res, err = stmt.Exec("astaxieupdate", 1)
checkErr(err)
affect, err := res.RowsAffected()
checkErr(err)
fmt.Println(affect)
//查詢資料
rows, err := db.Query("SELECT * FROM userinfo")
checkErr(err)
for rows.Next() {
var uid int
var username string
var department string
var created string
err = rows.Scan(&uid, &username, &department, &created)
checkErr(err)
fmt.Println(uid)
fmt.Println(username)
fmt.Println(department)
fmt.Println(created)
}
//刪除資料
stmt, err = db.Prepare("delete from userinfo where uid=$1")
checkErr(err)
res, err = stmt.Exec(1)
checkErr(err)
affect, err = res.RowsAffected()
checkErr(err)
fmt.Println(affect)
db.Close()
}
func checkErr(err error) {
if err != nil {
panic(err)
}
}
```
從上面的程式碼我們可以看到PostgreSQL 是透過`$1`,`$2`這種方式來指定要傳遞的參數,而不是 MySQL 中的`?`,另外在 sql.Open 中的 dsn 資訊的格式也與 MySQL 的驅動中的 dsn 格式不一樣,所以在使用時請注意它們的差異。
還有 pg 不支援 LastInsertId 函式,因為 PostgreSQL 內部沒有實現類似 MySQL 的自增 ID 回傳,其他的程式碼幾乎是一模一樣。
## links
* [目錄](<preface.md>)
* 上一節:[使用 SQLite 資料庫](<05.3.md>)
* 下一節:[使用 Beego orm 函式庫進行 ORM 開發](<05.5.md>)