Golang連接并操作PostgreSQL數(shù)據(jù)庫基本操作
前言:
本篇文章對如何使用golang連接并操作postgre數(shù)據(jù)庫進行了簡要說明。文中使用到的主要工具:DBeaver21、VSCode,Golang1.17。
以用戶,文章,評論三個表作為例子,下面是數(shù)據(jù)庫建表sql:
CREATE TABLE public.user_info (
u_id serial4 NOT NULL,
user_name varchar NULL,
create_time date NULL,
CONSTRAINT user_info_pk PRIMARY KEY (u_id)
);
CREATE TABLE public.user_info (
u_id serial4 NOT NULL,
user_name varchar NULL,
create_time date NULL,
CONSTRAINT user_info_pk PRIMARY KEY (u_id)
);
CREATE TABLE public."comment" (
c_id serial4 NOT NULL,
"content" varchar NULL,
CONSTRAINT comment_pk PRIMARY KEY (c_id)
);
連接數(shù)據(jù)庫
連接postgre數(shù)據(jù)庫的驅(qū)動有很多,我們選用了github.com/lib/pq。下面看連接的方法。我們引入pq包時使用了_進行匿名加載,而不是直接使用驅(qū)動包。在對數(shù)據(jù)庫的操作仍然是使用自帶的sql包。另外,postgre默認(rèn)使用的是public模式(schema),我們創(chuàng)建的表也是在這個模式下的。可以直接在數(shù)據(jù)庫中修改默認(rèn)模式或者在連接url中添加currentSchema=myschema來指定默認(rèn)的模式,當(dāng)然也可以在sql中使用myschema.TABLE來指定要訪問的模式。
package main
import (
"database/sql"
"fmt"
_ "github.com/lib/pq"
)
var db *sql.DB
func DbOpen() {
var err error
//參數(shù)根據(jù)自己的數(shù)據(jù)庫進行修改
db, err = sql.Open("postgres", "host=localhost port=5432 user=angelhand password=2222 dbname=ahdb sslmode=disable")
checkError(err)
err = db.Ping()
checkError(err)
}
sql.DB
需要注意的是,sql.DB并不是數(shù)據(jù)庫連接,而是一個go中的一個數(shù)據(jù)結(jié)構(gòu):
type DB struct {
// Atomic access only. At top of struct to prevent mis-alignment
// on 32-bit platforms. Of type time.Duration.
waitDuration int64 // Total time waited for new connections.
connector driver.Connector
// numClosed is an atomic counter which represents a total number of
// closed connections. Stmt.openStmt checks it before cleaning closed
// connections in Stmt.css.
numClosed uint64
mu sync.Mutex // protects following fields
freeConn []*driverConn
connRequests map[uint64]chan connRequest
nextRequest uint64 // Next key to use in connRequests.
numOpen int // number of opened and pending open connections
// Used to signal the need for new connections
// a goroutine running connectionOpener() reads on this chan and
// maybeOpenNewConnections sends on the chan (one send per needed connection)
// It is closed during db.Close(). The close tells the connectionOpener
// goroutine to exit.
openerCh chan struct{}
closed bool
dep map[finalCloser]depSet
lastPut map[*driverConn]string // stacktrace of last conn's put; debug only
maxIdleCount int // zero means defaultMaxIdleConns; negative means 0
maxOpen int // <= 0 means unlimited
maxLifetime time.Duration // maximum amount of time a connection may be reused
maxIdleTime time.Duration // maximum amount of time a connection may be idle before being closed
cleanerCh chan struct{}
waitCount int64 // Total number of connections waited for.
maxIdleClosed int64 // Total number of connections closed due to idle count.
maxIdleTimeClosed int64 // Total number of connections closed due to idle time.
maxLifetimeClosed int64 // Total number of connections closed due to max connection lifetime limit.
stop func() // stop cancels the connection opener.
}
在拿到sql.DB時并不會創(chuàng)建新的連接,而可以認(rèn)為是拿到了一個數(shù)據(jù)庫連接池,只有在執(zhí)行數(shù)據(jù)庫操作(如Ping()操作)時才會自動生成一個連接并連接數(shù)據(jù)庫。在連接操作執(zhí)行完畢后應(yīng)該及時地釋放。此處說的釋放是指釋放連接而不是sql.DB連接,通常來說一個sql.DB應(yīng)該像全局變量一樣長期保存,而不要在某一個小函數(shù)中都進行Open()和Close()操作,否則會引起資源耗盡的問題。
增刪改查
下面代碼實現(xiàn)對數(shù)據(jù)簡單的增刪改查操作。
插入數(shù)據(jù)
func insert() {
stmt, err := db.Prepare("INSERT INTO user_info(user_name,create_time) VALUES($1,$2)")
if err != nil {
panic(err)
}
res, err := stmt.Exec("ah", time.Now())
if err != nil {
panic(err)
}
fmt.Printf("res = %d", res)
}
使用Exec()函數(shù)后會返回一個sql.Result即上面的res變量接收到的返回值,它提供了LastInserId() (int64, error)和RowsAffected() (int64, error)分別獲取執(zhí)行語句返回的對應(yīng)的id和語句執(zhí)行所影響的行數(shù)。
更新數(shù)據(jù)
func update() {
stmt, err := db.Prepare("update user_info set user_name=$1 WHERE u_id=$2")
if err != nil {
panic(err)
}
res, err := stmt.Exec("angelhand", 1)
if err != nil {
panic(err)
}
fmt.Printf("res = %d", res)
}
查詢數(shù)據(jù)
結(jié)構(gòu)體如下:
type u struct {
id int
user_name string
create_time time.Time
}
接下來是查詢的代碼
func query() {
rows, err := db.Query("select u_id, user_name, create_time from user_info where user_name=$1", "ah")
if err != nil {
panic(err)
}
//延遲關(guān)閉rows
defer rows.Close()
for rows.Next() {
user := u{}
err := rows.Scan(&user.id, &user.user_name, &user.create_time)
if err != nil {
panic(err)
}
fmt.Printf("id = %v, name = %v, time = %v\n", user.id, user.user_name, user.create_time)
}
}
可以看到使用到的幾個關(guān)鍵函數(shù)rows.Close(),rows.Next(),rows.Scan()。其中rows.Next()用來遍歷從數(shù)據(jù)庫中獲取到的結(jié)果集,隨用用rows.Scan()來將每一列結(jié)果賦給我們的結(jié)構(gòu)體。
需要強調(diào)的是rows.Close()。每一個打開的rows都會占用系統(tǒng)資源,如果不能及時的釋放那么會耗盡系統(tǒng)資源。defer語句類似于java中的finally,功能就是在函數(shù)結(jié)束前執(zhí)行后邊的語句。換句話說,在函數(shù)結(jié)束前不會執(zhí)行后邊的語句,因此在耗時長的函數(shù)中不建議使用這種方式釋放rows連接。如果要在循環(huán)中重發(fā)查詢和使用結(jié)果集,那么應(yīng)該在處理完結(jié)果后顯式調(diào)用rows.Close()。
db.Query()實際上等于創(chuàng)建db.Prepare(),執(zhí)行并關(guān)閉之三步操作。
還可以這樣來查詢單條記錄:
err := db.Query("select u_id, user_name, create_time from user_info where user_name=$1", "ah").Scan(&user.user_name)
刪除數(shù)據(jù)
func delete() {
stmt, err := db.Prepare("delete from user_info where user_name=$1")
if err != nil {
panic(err)
}
res, err := stmt.Exec("angelhand")
if err != nil {
panic(err)
}
fmt.Printf("res = %d", res)
}
總結(jié)
到此這篇關(guān)于Golang連接并操作PostgreSQL數(shù)據(jù)庫基本操作的文章就介紹到這了,更多相關(guān)Golang連接操作PostgreSQL內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Golang處理gRPC請求/響應(yīng)元數(shù)據(jù)的示例代碼
前段時間實現(xiàn)內(nèi)部gRPC框架時,為了實現(xiàn)在服務(wù)端攔截器中打印請求及響應(yīng)的頭部信息,便查閱了部分關(guān)于元數(shù)據(jù)的資料,因為中文網(wǎng)絡(luò)上對于該領(lǐng)域的信息較少,于是在這做了一些簡單的總結(jié),需要的朋友可以參考下2024-03-03
使用dep 配置golang 開發(fā)環(huán)境的操作方法
下面小編就為大家?guī)硪黄褂胐ep 配置golang 開發(fā)環(huán)境的操作方法。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2017-09-09
Mac下Vs code配置Go語言環(huán)境的詳細(xì)過程
這篇文章給大家介紹Mac下Vs code配置Go語言環(huán)境的詳細(xì)過程,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07

