Golang連接PostgreSQL基本操作的實(shí)現(xiàn)
前言:本篇文章對(duì)如何使用golang連接并操作postgre數(shù)據(jù)庫進(jìn)行了簡要說明。文中使用到的主要工具:DBeaver21、VSCode,Golang1.17。
以用戶,文章,評(píng)論三個(gè)表作為例子,下面是數(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ū)動(dòng)有很多,我們選用了github.com/lib/pq
。下面看連接的方法。我們引入pq
包時(shí)使用了_
進(jìn)行匿名加載,而不是直接使用驅(qū)動(dòng)包。在對(duì)數(shù)據(jù)庫的操作仍然是使用自帶的sql
包。另外,postgre默認(rèn)使用的是public
模式(schema),我們創(chuàng)建的表也是在這個(gè)模式下的??梢灾苯釉跀?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ù)庫進(jìn)行修改 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ù)庫連接,而是一個(gè)go中的一個(gè)數(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
時(shí)并不會(huì)創(chuàng)建新的連接,而可以認(rèn)為是拿到了一個(gè)數(shù)據(jù)庫連接池,只有在執(zhí)行數(shù)據(jù)庫操作(如Ping()操作)時(shí)才會(huì)自動(dòng)生成一個(gè)連接并連接數(shù)據(jù)庫。在連接操作執(zhí)行完畢后應(yīng)該及時(shí)地釋放。此處說的釋放是指釋放連接而不是sql.DB
連接,通常來說一個(gè)sql.DB
應(yīng)該像全局變量一樣長期保存,而不要在某一個(gè)小函數(shù)中都進(jìn)行Open()
和Close()
操作,否則會(huì)引起資源耗盡的問題。
增刪改查
下面代碼實(shí)現(xiàn)對(duì)數(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ù)后會(huì)返回一個(gè)sql.Result
即上面的res
變量接收到的返回值,它提供了LastInserId() (int64, error)
和RowsAffected() (int64, error)
分別獲取執(zhí)行語句返回的對(duì)應(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) } }
可以看到使用到的幾個(gè)關(guān)鍵函數(shù)rows.Close()
,rows.Next()
,rows.Scan()
。其中rows.Next()
用來遍歷從數(shù)據(jù)庫中獲取到的結(jié)果集,隨用用rows.Scan()
來將每一列結(jié)果賦給我們的結(jié)構(gòu)體。
需要強(qiáng)調(diào)的是rows.Close()
。每一個(gè)打開的rows
都會(huì)占用系統(tǒng)資源,如果不能及時(shí)的釋放那么會(huì)耗盡系統(tǒng)資源。defer
語句類似于java中的finally
,功能就是在函數(shù)結(jié)束前執(zhí)行后邊的語句。換句話說,在函數(shù)結(jié)束前不會(huì)執(zhí)行后邊的語句,因此在耗時(shí)長的函數(shù)中不建議使用這種方式釋放rows
連接。如果要在循環(huán)中重發(fā)查詢和使用結(jié)果集,那么應(yīng)該在處理完結(jié)果后顯式調(diào)用rows.Close()
。
db.Query()
實(shí)際上等于創(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) }
到此這篇關(guān)于Golang連接PostgreSQL基本操作的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Golang連接PostgreSQL內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Go語言Swagger實(shí)現(xiàn)為項(xiàng)目生成 API 文檔
Swagger 是一個(gè)基于 OpenAPI 規(guī)范設(shè)計(jì)的工具,用于為 RESTful API 生成交互式文檔,下面小編就來介紹一下如何在 Go 項(xiàng)目中集成 Swagger,特別是結(jié)合 Gin 框架生成 API 文檔2025-03-03基于gin的golang web開發(fā)之認(rèn)證利器jwt
這篇文章主要介紹了基于gin的golang web開發(fā)之認(rèn)證利器jwt,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12基于go中fyne gui的通達(dá)信數(shù)據(jù)導(dǎo)出工具詳解
這篇文章主要介紹了基于go中fyne gui的通達(dá)信數(shù)據(jù)導(dǎo)出工具,這是一個(gè)用 Go 語言開發(fā)的通達(dá)信數(shù)據(jù)導(dǎo)出工具,可以將通達(dá)信的本地?cái)?shù)據(jù)導(dǎo)出為多種格式,方便用戶進(jìn)行數(shù)據(jù)分析和處理,需要的朋友可以參考下2024-12-12Go操作各大消息隊(duì)列教程(RabbitMQ、Kafka)
消息隊(duì)列是一種異步的服務(wù)間通信方式,適用于無服務(wù)器和微服務(wù)架構(gòu),本文主要介紹了Go操作各大消息隊(duì)列教程(RabbitMQ、Kafka),需要的朋友可以了解一下2024-02-02