如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段
本篇内容介绍了“如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!
驱动安装
执行以下命令安装postgresql驱动
gogetgithub.com/lib/pq
pq包支持的功能
SSL
作为驱动程序, 与database/sql结合处理连接相关操作
扫描时间time.Time类型, 如 timestamp[tz], time[tz], date
扫描二进制blobs对象(Blob是内存中的数据缓冲, 用来匹配strign类型的ID和字节切片), 如: bytea
PostgreSQL的hstore数据类型支持
支持COPY FROM
pq.ParseURL方法用来将urls转化为sql.Open的连接字符串
支持许多libpq库兼容的环境变量
支持Unix socket
支持通知Notifications, 如:LISTEN/NOTIFY
支持pgpass
GSS (Kerberos) 认证
连接字符串参数
pq包与libpq类似(libpq是用C编写的底层接口, 为其他高级语言比如C++,Perl,Python,Tcl和ECPG等提供底层PostgreSQL支持). 建立连接时需要提供连接参数, 一部分支持libpq的参数也支持pq, 额外的, pq允许在连接字符串中指定运行时参数(如:search_path或work_mem), libpq则不能在连接字符串中指定运行时参数, 只能在option参数中指定.
pq包为了兼容libpq包, 下面的连接参数都支持
*dbname-需要连接的数据库名*user-需要使用的用户名*password-该用户的密码*host-需要连接的postgresql主机,unix域名套接字以/开始,默认是localhost*port-postgresql绑定的端口(默认5432)*sslmode-是否使用SSL(默认是启用(require),libpq包默认不启用SSL)*fallback_application_name-失败时,可以提供一个应用程序名来跟踪.*connect_timeout-连接最大等待秒数,0或者不指定,表示不确定时间的等待*sslcert-证书文件位置,文件中必须包含PEM编码的数据*sslkey-密钥文件位置,文件中必须包含PEM编码的数据*sslrootcert-根证书文件位置,文件中必须包含PEM编码的数据
sslmode 支持一下模式
*disable-禁用SSL*require-总是使用SSL(跳过验证)*verify-ca-总是使用SSL(验证服务器提供的证书是由可信的CA签署的)*verify-full-总是使用SSL(验证服务器提供的证书是由受信任的CA签署的,并验证服务器主机名是否与证书中的主机名匹配)
更多连接字符串参数请参考官方文档
对包含空格的参数, 需要使用单引号, 如:
"user=pqgotestpassword='withspaces'"
使用反斜杠进行转义, 如:
"user=space\manpassword='it\'svalid'"
注意: 如果要设置client_encoding连接参数(用于设置连接的编码), 必须设置为"UTF8", 才能与Postgres匹配, 设置为其他值将会报错.
除了上面的参数, 在连接字符串中也可以通过后台设置运行时参数, 详细运行时参数, 请参考runtime-config
支持libpq的大部分环境变量也支持pq包, 详细环境变量请参考libpq-envars. 如果没有设置环境变量且连接字符串也没有提供该参数, 程序会panic崩溃退出, 字符串参数优先级高于环境变量.
完整"增删改查"示例代码
packagemainimport("database/sql""encoding/json""fmt"_"github.com/lib/pq""log")const(//Initializeconnectionconstants.HOST="172.16.xx.xx"PORT=31976DATABASE="postgres"USER="postgres"PASSWORD="xxx")funccheckError(errerror){iferr!=nil{panic(err)}}typeDbstruct{db*sql.DB}//创建表func(this*Db)CreateTable(){//以水果库存清单表inventory为例//Dropprevioustableofsamenameifoneexists.如果之前存在清单表,则删除该表_,err:=this.db.Exec("DROPTABLEIFEXISTSinventory;")checkError(err)fmt.Println("Finisheddroppingtable(ifexisted)")//Createtable.创建表,指定id,name,quantity(数量)字段,其中id为主键_,err=this.db.Exec("CREATETABLEinventory(idserialPRIMARYKEY,nameVARCHAR(50),quantityINTEGER);")checkError(err)fmt.Println("Finishedcreatingtable")}//删除表func(this*Db)DropTable(){//以水果库存清单表inventory为例//Dropprevioustableofsamenameifoneexists.如果之前存在清单表,则删除该表_,err:=this.db.Exec("DROPTABLEIFEXISTSinventory;")checkError(err)fmt.Println("Finisheddroppingtable(ifexisted)")}//增加数据func(this*Db)Insert(){//Insertsomedataintotable.插入3条水果数据sql_statement:="INSERTINTOinventory(name,quantity)VALUES($1,$2);"_,err:=this.db.Exec(sql_statement,"banana",150)checkError(err)_,err=this.db.Exec(sql_statement,"orange",154)checkError(err)_,err=this.db.Exec(sql_statement,"apple",100)checkError(err)fmt.Println("Inserted3rowsofdata")}//读数据/查数据func(this*Db)Read(){//读取数据//Readrowsfromtable.varidintvarnamestringvarquantityintsql_statement:="SELECT*frominventory;"rows,err:=this.db.Query(sql_statement)checkError(err)deferrows.Close()forrows.Next(){switcherr:=rows.Scan(&id,&name,&quantity);err{casesql.ErrNoRows:fmt.Println("Norowswerereturned")casenil:fmt.Printf("Datarow=(%d,%s,%d)\n",id,name,quantity)default:checkError(err)}}}//更新数据func(this*Db)Update(){//Modifysomedataintable.sql_statement:="UPDATEinventorySETquantity=$2WHEREname=$1;"_,err:=this.db.Exec(sql_statement,"banana",200)checkError(err)fmt.Println("Updated1rowofdata")}//删除数据func(this*Db)Delete(){//Deletesomedatafromtable.sql_statement:="DELETEFROMinventoryWHEREname=$1;"_,err:=this.db.Exec(sql_statement,"orange")checkError(err)fmt.Println("Deleted1rowofdata")}//数据序列化为Json字符串,便于人工查看funcData2Json(anyDatainterface{})string{JsonByte,err:=json.Marshal(anyData)iferr!=nil{log.Printf("数据序列化为json出错:\n%s\n",err.Error())return""}returnstring(JsonByte)}//多行数据解析funcQueryAndParseRows(Db*sql.DB,queryStrstring)[]map[string]string{rows,err:=Db.Query(queryStr)deferrows.Close()iferr!=nil{log.Printf("查询出错:\nSQL:\n%s,错误详情\n",queryStr,err.Error())returnnil}cols,_:=rows.Columns()//列名iflen(cols)>0{varret[]map[string]string//定义返回的映射切片变量retforrows.Next(){buff:=make([]interface{},len(cols))data:=make([][]byte,len(cols))//数据库中的NULL值可以扫描到字节中fori,_:=rangebuff{buff[i]=&data[i]}rows.Scan(buff...)//扫描到buff接口中,实际是字符串类型data中//将每一行数据存放到数组中dataKv:=make(map[string]string,len(cols))fork,col:=rangedata{//k是index,col是对应的值//fmt.Printf("%30s:\t%s\n",cols[k],col)dataKv[cols[k]]=string(col)}ret=append(ret,dataKv)}log.Printf("返回多元素数组:\n%s",Data2Json(ret))returnret}else{returnnil}}//单行数据解析查询数据库,解析查询结果,支持动态行数解析funcQueryAndParse(Db*sql.DB,queryStrstring)map[string]string{rows,err:=Db.Query(queryStr)deferrows.Close()iferr!=nil{log.Printf("查询出错:\nSQL:\n%s,错误详情\n",queryStr,err.Error())returnnil}//rows,_:=Db.Query("SHOWVARIABLESLIKE'%data%'")cols,_:=rows.Columns()iflen(cols)>0{buff:=make([]interface{},len(cols))//临时slicedata:=make([][]byte,len(cols))//存数据slicedataKv:=make(map[string]string,len(cols))fori,_:=rangebuff{buff[i]=&data[i]}forrows.Next(){rows.Scan(buff...)//...是必须的}fork,col:=rangedata{dataKv[cols[k]]=string(col)//fmt.Printf("%30s:\t%s\n",cols[k],col)}log.Printf("返回单行数据Map:\n%s",Data2Json(dataKv))returndataKv}else{returnnil}}funcmain(){//Initializeconnectionstring.初始化连接字符串,参数包含主机,端口,用户名,密码,数据库名,SSL模式(禁用),超时时间varconnectionStringstring=fmt.Sprintf("host=%sport=%duser=%spassword=%sdbname=%ssslmode=disableconnect_timeout=3",HOST,PORT,USER,PASSWORD,DATABASE)//Initializeconnectionobject.初始化连接对象,驱动名为postgresdb,err:=sql.Open("postgres",connectionString)deferdb.Close()checkError(err)postgresDb:=Db{db:db,}err=postgresDb.db.Ping()//连通性检查checkError(err)fmt.Println("Successfullycreatedconnectiontodatabase")postgresDb.CreateTable()//创建表postgresDb.Insert()//插入数据postgresDb.Read()//查询数据QueryAndParseRows(postgresDb.db,"SELECT*frominventory;")//直接查询和解析多行数据QueryAndParse(postgresDb.db,"SHOWDateStyle;")//直接查询和解析单行数据postgresDb.Update()//修改/更新数据postgresDb.Read()postgresDb.Delete()//删除数据postgresDb.Read()postgresDb.DropTable()}
执行 go run main.go运行结果如下:
SuccessfullycreatedconnectiontodatabaseFinisheddroppingtable(ifexisted)FinishedcreatingtableInserted3rowsofdataDatarow=(1,banana,150)Datarow=(2,orange,154)Datarow=(3,apple,100)2020/12/1522:13:33返回多元素数组:[{"id":"1","name":"banana","quantity":"150"},{"id":"2","name":"orange","quantity":"154"},{"id":"3","name":"apple","quantity":"100"}]2020/12/1522:13:33返回单行数据Map:{"DateStyle":"ISO,MDY"}Updated1rowofdataDatarow=(2,orange,154)Datarow=(3,apple,100)Datarow=(1,banana,200)Deleted1rowofdataDatarow=(3,apple,100)Datarow=(1,banana,200)Finisheddroppingtable(ifexisted)
“如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!
声明:本站所有文章资源内容,如无特殊说明或标注,均为采集网络资源。如若本站内容侵犯了原著者的合法权益,可联系本站删除。