使用Golang操作PostgreSQL資料庫的增刪改查 CRUD Of PostgreSQL By Golang
PG驅動庫包github.com/lib/pq
該驅動包沒有提供建立PG表結構的函式,因此需要手動建立。SQL檔案如下:
node_infos.sql
--------------------------- ---postgresql SQL by Chen Jian --------------------------- drop table if exists "node_infos"; CREATE TABLE "node_infos"( "node_name" varchar(45) PRIMARY KEY, "node_ip" varchar(45) NOT NULL, "node_port" varchar(45) NOT NULL, "node_username" varchar(45) NOT NULL, "node_password" varchar(255) NOT NULL ); COMMENT ON COLUMN "node_infos"."node_name" is '節點名稱'; COMMENT ON COLUMN "node_infos"."node_ip" is '節點IP地址'; COMMENT ON COLUMN "node_infos"."node_port" is '節點埠號'; COMMENT ON COLUMN "node_infos"."node_username" is '節點使用者名稱'; COMMENT ON COLUMN "node_infos"."node_password" is '節點密碼'; INSERT INTO node_infos(node_name, node_ip, node_port, node_username, node_password) VALUES ('chen', '10.16.11.92', '22', 'root', 'xxxx'); INSERT INTO node_infos(node_name, node_ip, node_port, node_username, node_password) VALUES ('jian', '10.16.11.94', '22', 'root', 'xxxx'); INSERT INTO node_infos(node_name, node_ip, node_port, node_username, node_password) VALUES ('blabla', '10.16.11.95', '22', 'root', 'xxxx');
PGs資料庫的簡單操作
# 進入PG資料庫 psql -U postgres # 檢視當前資料庫: \l; <<'COMMENT' List of databases Name|Owner| Encoding |Collate|Ctype|Access privileges -----------+----------+----------+------------+------------+----------------------- postgres| postgres | UTF8| en_US.utf8 | en_US.utf8 | template0 | postgres | UTF8| en_US.utf8 | en_US.utf8 | =c/postgres+ ||||| postgres=CTc/postgres template1 | postgres | UTF8| en_US.utf8 | en_US.utf8 | =c/postgres+ ||||| postgres=CTc/postgres (3 rows) COMMENT # 連結資料庫postgres \c postgres; <<'COMMENT' You are now connected to database "postgres" as user "postgres". COMMENT # 建立表 \i node_infos.sql; # 結果輸出 psql:node_infos.sql:4: NOTICE:table "node_infos" does not exist, skipping DROP TABLE CREATE TABLE COMMENT COMMENT COMMENT COMMENT COMMENT INSERT 0 1 INSERT 0 1 INSERT 0 1 # 檢視當前表 \dt; <<'COMMENT' List of relations Schema |Name| Type|Owner --------+------------+-------+---------- public | node_infos | table | postgres (1 row) COMMENT # 查看錶結構 \d node_infos; <<'COMMENT' Table "public.node_infos" Column|Type| Modifiers ---------------+------------------------+----------- node_name| character varying(45)| not null node_ip| character varying(45)| not null node_port| character varying(45)| not null node_username | character varying(45)| not null node_password | character varying(255) | not null Indexes: "node_infos_pkey" PRIMARY KEY, btree (node_name) COMMENT # 查看錶中所有資料 select * from node_infos; <<'COMMENT' node_name |node_ip| node_port | node_username | node_password -----------+-------------+-----------+---------------+--------------- chen| 10.16.11.92 | 22| root| xxxx jian| 10.16.11.94 | 22| root| xxxx blabla| 10.16.11.95 | 22| root| xxxx (3 rows) COMMENT # 刪除表 drop table node_infos; <<'COMMENT' DROP TABLE COMMENT # 退出PG資料庫 \q;
CRUD程式碼
package main /* Author: Chen Jian Blog:https://www.o-my-chenjian.com Date:2018-11-20 */ import ( "fmt" "log" "database/sql" _ "github.com/lib/pq" ) var db *sql.DB var err error // PGs資料庫資訊 const ( pg_host= "10.16.11.95" pg_port= 5432 pg_user= "postgres" pg_password = "postgres" pg_dbname= "postgres" ) func InsertNodeInfo() error { stmt, err := db.Prepare("INSERT INTO \"node_infos\"(\"node_name\", \"node_ip\", \"node_port\", \"node_username\", \"node_password\") VALUES ($1, $2, $3, $4, $5)") if err != nil { log.Fatal("PG Statements Wrong: ", err) } res, err := stmt.Exec("nicai", "10.51.42.66", "9999", "nicai", "gophdddeer") if err != nil { log.Fatal("PG Statements Exec Wrong: ", err) } id, err := res.RowsAffected() if err != nil { log.Fatal("PG Affecte Wrong: ", err) } fmt.Println(id) return nil } func DeleteNodeInfo() error { stmt, err := db.Prepare("DELETE FROM \"node_infos\" WHERE \"node_name\" = $1") if err != nil { log.Fatal("PG Statements Wrong: ", err) } res, err := stmt.Exec("nicai") if err != nil { log.Fatal("PG Statements Exec Wrong: ", err) } id, err := res.RowsAffected() if err != nil { log.Fatal("PG Affecte Wrong: ", err) } fmt.Println(id) return nil } func SelectAllNodeInfo() error { rows, err := db.Query("SELECT * FROM\"node_infos\"") if err != nil { log.Fatal("PG Statements Wrong: ", err) } for rows.Next() { var nodename string var nodeip string var nodeport string var nodeusername string var nodepassword string if err := rows.Scan(&nodename, &nodeip, &nodeport, &nodeusername, &nodepassword); err != nil { log.Fatal("PG Rows Scan Failed: ", err) } fmt.Printf("node_name = \"%s\", "+ "node_ip = \"%s\", "+ "node_port = \"%s\", "+ "node_username = \"%s\", "+ "node_password = \"%s\"\n", nodename, nodeip, nodeport, nodeusername, nodepassword) } if err := rows.Err(); err != nil { log.Fatal("PG Query Failed: ", err) } rows.Close() db.Close() return nil } func UpdateNodeInfo() error { stmt, err := db.Prepare("UPDATE \"node_infos\" SET \"node_username\" = $1 WHERE \"node_name\" = $2") if err != nil { log.Fatal("PG Statements Wrong: ", err) } res, err := stmt.Exec("blabla", "blabla") if err != nil { log.Fatal("PG Statements Exec Wrong: ", err) } id, err := res.RowsAffected() if err != nil { log.Fatal("PG Affecte Wrong: ", err) } fmt.Println(id) return nil } func main() { // 連結PostgreSQL資料庫 log.Println("Connecting PostgreSQL....") psqlInfo := fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", pg_host, pg_port, pg_user, pg_password, pg_dbname) db, err = sql.Open("postgres", psqlInfo) if err != nil { log.Fatal("Connect PG Failed: ", err) } db.SetMaxOpenConns(2000) db.SetMaxIdleConns(1000) defer db.Close() err = db.Ping() if err != nil { log.Fatal("Ping GP Failed: ", err) } fmt.Println("PG Successfull Connected!") // 插入資料 //err := InsertNodeInfo() //if err != nil { //log.Fatal("Insert Data Failed: ", err) //} // 刪除資料 //err := DeleteNodeInfo() //if err != nil { //log.Fatal("Delete Data Failed: ", err) //} // 查詢所有資料 //err := SelectAllNodeInfo() //if err != nil { //log.Fatal("Select All Data Failed: ", err) //} // 更新某一資料 err := UpdateNodeInfo() if err != nil { log.Fatal("Update Data Failed: ", err) } }
PG驅動庫包github.com/lib/pq
採用github.com/lib/pq
主要是其提供建立資料庫表的方法。
package main /* Author: Chen Jian Blog:https://www.o-my-chenjian.com Date:2018-11-20 */ import ( "fmt" "log" "github.com/go-pg/pg" "github.com/go-pg/pg/orm" ) // PGs資料庫資訊 const ( pg_addr= "10.16.11.95:5432" pg_user= "postgres" pg_password = "postgres" pg_dbname= "postgres" ) // 定義表結構 type NodeInfo struct { NodeNamestring `sql:"type:varchar(45),unique,notnull,pk"` NodeIpstring `sql:"type:varchar(45),notnull"` NodePortstring `sql:"type:varchar(45),notnull"` NodeUsername string `sql:"type:varchar(45),notnull"` NodePassword string `sql:"type:varchar(255),notnull"` } func CreateTable(db *pg.DB) error { for _, model := range []interface{}{(*NodeInfo)(nil)} { err := db.CreateTable(model, &orm.CreateTableOptions{ IfNotExists:true, FKConstraints: true, }) if err != nil { return err } } return nil } func DeleteTable(db *pg.DB) error { err := db.DropTable(&NodeInfo{}, &orm.DropTableOptions{ IfExists: true, Cascade:true, }) return err } func InsertNodeInfo(db *pg.DB) error { // 插入資料方法一 //nodeinfodata := &NodeInfo{ //NodeName:"chenjian", //NodeIp:"10.0.0.5", //NodePort:"2222", //NodeUsername: "chenjian", //NodePassword: "1234321", //} //err := db.Insert(nodeinfodata) //if err!=nil { //return err //} // 插入資料方法二 err := db.Insert(&NodeInfo{ NodeName:"chenjian", NodeIp:"10.0.0.5", NodePort:"2222", NodeUsername: "chenjian", NodePassword: "1234321", }) if err != nil { return err } return nil } func SelectAllNodeInfo(db *pg.DB) error { var nodeinfodata []NodeInfo err := db.Model(&nodeinfodata).Select() if err != nil { return err } fmt.Println(nodeinfodata) return nil } func SelectNodeInfo(db *pg.DB) error { nodeinfodata := &NodeInfo{ NodeName: "chenjian", } err := db.Select(nodeinfodata) if err != nil { return err } fmt.Println(nodeinfodata) return nil } func UpdateNodeInfo(db *pg.DB) error { var nodeinfodata []NodeInfo updatedata := &NodeInfo{ NodeName:"chenjian", NodeIp:"10.0.0.5", NodePort:"3333", NodeUsername: "chenjian", NodePassword: "1234321", } _, err := db.Model(&nodeinfodata). Set("node_port = ?", updatedata.NodePort). Where("node_name = ?", updatedata.NodeName). Returning("*"). Update() if err != nil { return err } return nil } func main() { // 連結PostgreSQL資料庫 log.Println("Connecting PostgreSQL....") db := pg.Connect(&pg.Options{ Addr:pg_addr, User:pg_user, Password: pg_password, Database: pg_dbname, }) defer db.Close() fmt.Println("Successfull Connected!") // 建立表 //err := CreateTable(db) //if err != nil { //log.Fatal("Create Table Failed: ",err) //} // 刪除表 //err := DeleteTable(db) //if err != nil { //log.Fatal("Delete Table Failed: ", err) //} // 插入資料 //err := InsertNodeInfo(db) //if err != nil { //log.Fatal("Insert Data Failed: ", err) //} // 查詢所有資料 //err := SelectAllNodeInfo(db) //if err != nil { //log.Fatal("Select All Data Failed: ", err) //} // 查詢某一資料 //err := SelectNodeInfo(db) //if err != nil { //log.Fatal("Select Data Failed: ", err) //} // 更新某一資料 err := UpdateNodeInfo(db) if err != nil { log.Fatal("Update Data Failed: ", err) } }
govendor依賴管理工具
通過govendor
可以很方便的管理專案中所有的依賴包。例如將依賴包放到專案路徑下,便於專案的傳遞,從而不需再一次下載依賴包。
govendor的安裝
go get -u github.com/kardianos/govendor # 無法下載成功,可以下載原始碼,進行編譯 mkdir -p ${GOPATH}/src/github.com/kardianos cd ${GOPATH}/src/github.com/kardianos git clone https://github.com/kardianos/govendor.git govendor
govendor的操作
# 進入專案路徑 cd ${GOPATH}/src/chenjian # 初始化govendor。隨後會生成一個vender資料夾,裡面有個vender.json,記錄著依賴包的資訊 govendor init # 檢視專案中所需依賴列表,狀態內容如下 govendor list # 檢視正在使用的依賴包 govendor list -v fmt # 下載missing的依賴包,下載完後,+missing變為+external狀態 govendor get k8s.io/klog # 下載特定版本的依賴包 govendor fetch golang.org/x/net/[email protected] # Get latest v1.*.* tag or branch. govendor fetch golang.org/x/net/[email protected] # Get the tag or branch named "v1". govendor fetch golang.org/x/net/[email protected]=v1 # 將+external狀態的依賴包歸到govender管理 govendor add k8s.io/klog # 批量add govendor add +e
- vender.json
{ "comment": "", "ignore": "test", "package": [ { "checksumSHA1": "asksIwylfIjaYsF2nMY69jTyxC0=", "path": "github.com/lib/pq", "revision": "9eb73efc1fcc404148b56765b0d3f61d9a5ef8ee", "revisionTime": "2018-10-16T16:26:27Z" } ], "rootPath": "chenjian" }
- 依賴包狀態
狀態 | 縮寫 | 含義 |
---|---|---|
+local | l | 在專案中的包 |
+external | e | 外部包,即被 $GOPATH 管理,但不在 vendor 目錄下 |
+vendor | v | 已被 govendor 管理,即在 vendor 目錄下 |
+std | s | 標準庫中的包 |
+unused | u | 未使用的包,即包在 vendor 目錄下,但專案並沒有用到 |
+missing | m | 程式碼引用了依賴包,但該包並沒有找到 |
+program | p | 主程式包,意味著可以編譯為執行檔案 |
+outside | 外部包和缺失的包 | |
+all | 所有的包 |