我的编程空间,编程开发者的网络收藏夹
学习永远不晚

如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段

短信预约 -IT技能 免费直播动态提醒
省份

北京

  • 北京
  • 上海
  • 天津
  • 重庆
  • 河北
  • 山东
  • 辽宁
  • 黑龙江
  • 吉林
  • 甘肃
  • 青海
  • 河南
  • 江苏
  • 湖北
  • 湖南
  • 江西
  • 浙江
  • 广东
  • 云南
  • 福建
  • 海南
  • 山西
  • 四川
  • 陕西
  • 贵州
  • 安徽
  • 广西
  • 内蒙
  • 西藏
  • 新疆
  • 宁夏
  • 兵团
手机号立即预约

请填写图片验证码后获取短信验证码

看不清楚,换张图片

免费获取短信验证码

如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段

本篇内容介绍了“如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!

驱动安装

执行以下命令安装postgresql驱动

go get github.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=pqgotest password='with spaces'"

使用反斜杠进行转义, 如:

"user=space\ man password='it\'s valid'"

注意: 如果要设置client_encoding连接参数(用于设置连接的编码), 必须设置为"UTF8", 才能与Postgres匹配,  设置为其他值将会报错.

除了上面的参数, 在连接字符串中也可以通过后台设置运行时参数, 详细运行时参数, 请参考runtime-config

支持libpq的大部分环境变量也支持pq包, 详细环境变量请参考libpq-envars. 如果没有设置环境变量且连接字符串也没有提供该参数,  程序会panic崩溃退出, 字符串参数优先级高于环境变量.

完整"增删改查"示例代码

package main  import (   "database/sql"   "encoding/json"   "fmt"   _ "github.com/lib/pq"   "log" )  const (    // Initialize connection constants.   HOST     = "172.16.xx.xx"   PORT     = 31976   DATABASE = "postgres"   USER     = "postgres"   PASSWORD = "xxx" )  func checkError(err error) {   if err != nil {     panic(err)   } }  type Db struct {   db *sql.DB }  // 创建表 func (this *Db) CreateTable() {   // 以水果库存清单表inventory为例   // Drop previous table of same name if one exists.  如果之前存在清单表, 则删除该表   _, err := this.db.Exec("DROP TABLE IF EXISTS inventory;")   checkError(err)   fmt.Println("Finished dropping table (if existed)")    // Create table. 创建表, 指定id, name, quantity(数量)字段, 其中id为主键   _, err = this.db.Exec("CREATE TABLE inventory (id serial PRIMARY KEY, name VARCHAR(50), quantity INTEGER);")   checkError(err)   fmt.Println("Finished creating table") }  // 删除表 func (this *Db) DropTable() {   // 以水果库存清单表inventory为例   // Drop previous table of same name if one exists.  如果之前存在清单表, 则删除该表   _, err := this.db.Exec("DROP TABLE IF EXISTS inventory;")   checkError(err)   fmt.Println("Finished dropping table (if existed)") }  // 增加数据 func (this *Db) Insert() {   // Insert some data into table. 插入3条水果数据   sql_statement := "INSERT INTO inventory (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("Inserted 3 rows of data") }  // 读数据/查数据 func (this *Db) Read() {   //读取数据   // Read rows from table.   var id int   var name string   var quantity int    sql_statement := "SELECT * from inventory;"   rows, err := this.db.Query(sql_statement)   checkError(err)   defer rows.Close()    for rows.Next() {     switch err := rows.Scan(&id, &name, &quantity); err {     case sql.ErrNoRows:       fmt.Println("No rows were returned")     case nil:       fmt.Printf("Data row = (%d, %s, %d)\n", id, name, quantity)     default:       checkError(err)     }   } }   // 更新数据 func (this *Db) Update() {   // Modify some data in table.   sql_statement := "UPDATE inventory SET quantity = $2 WHERE name = $1;"   _, err := this.db.Exec(sql_statement, "banana", 200)   checkError(err)   fmt.Println("Updated 1 row of data") }  // 删除数据 func (this *Db) Delete() {   // Delete some data from table.   sql_statement := "DELETE FROM inventory WHERE name = $1;"   _, err := this.db.Exec(sql_statement, "orange")   checkError(err)   fmt.Println("Deleted 1 row of data") }  // 数据序列化为Json字符串, 便于人工查看 func Data2Json(anyData interface{}) string {   JsonByte, err := json.Marshal(anyData)   if err != nil {     log.Printf("数据序列化为json出错:\n%s\n", err.Error())     return ""   }   return string(JsonByte) }   //多行数据解析 func QueryAndParseRows(Db *sql.DB, queryStr string) []map[string]string {   rows, err := Db.Query(queryStr)   defer rows.Close()   if err != nil {     log.Printf("查询出错:\nSQL:\n%s, 错误详情\n", queryStr, err.Error())     return nil   }   cols, _ := rows.Columns() //列名   if len(cols) > 0 {     var ret []map[string]string //定义返回的映射切片变量ret     for rows.Next() {       buff := make([]interface{}, len(cols))       data := make([][]byte, len(cols)) //数据库中的NULL值可以扫描到字节中       for i, _ := range buff {         buff[i] = &data[i]       }       rows.Scan(buff...) //扫描到buff接口中,实际是字符串类型data中        //将每一行数据存放到数组中       dataKv := make(map[string]string, len(cols))       for k, col := range data { //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))     return ret   } else {     return nil   } }  //单行数据解析 查询数据库,解析查询结果,支持动态行数解析 func QueryAndParse(Db *sql.DB, queryStr string) map[string]string {   rows, err := Db.Query(queryStr)   defer rows.Close()    if err != nil {     log.Printf("查询出错:\nSQL:\n%s, 错误详情\n", queryStr, err.Error())     return nil   }   //rows, _ := Db.Query("SHOW VARIABLES LIKE '%data%'")    cols, _ := rows.Columns()   if len(cols) > 0 {     buff := make([]interface{}, len(cols)) // 临时slice     data := make([][]byte, len(cols))      // 存数据slice     dataKv := make(map[string]string, len(cols))     for i, _ := range buff {       buff[i] = &data[i]     }      for rows.Next() {       rows.Scan(buff...) // ...是必须的     }      for k, col := range data {       dataKv[cols[k]] = string(col)       //fmt.Printf("%30s:\t%s\n", cols[k], col)     }     log.Printf("返回单行数据Map:\n%s", Data2Json(dataKv))     return dataKv   } else {     return nil   } }   func main() {   // Initialize connection string. 初始化连接字符串, 参数包含主机,端口,用户名,密码,数据库名,SSL模式(禁用),超时时间   var connectionString string = fmt.Sprintf("host=%s  port=%d user=%s password=%s dbname=%s sslmode=disable connect_timeout=3", HOST, PORT, USER, PASSWORD, DATABASE)    // Initialize connection object. 初始化连接对象, 驱动名为postgres   db, err := sql.Open("postgres", connectionString)   defer db.Close()   checkError(err)   postgresDb := Db{     db: db,   }   err = postgresDb.db.Ping() //连通性检查   checkError(err)   fmt.Println("Successfully created connection to database")    postgresDb.CreateTable()         //创建表   postgresDb.Insert()              //插入数据   postgresDb.Read()                //查询数据   QueryAndParseRows(postgresDb.db, "SELECT * from inventory;") //直接查询和解析多行数据   QueryAndParse(postgresDb.db, "SHOW DateStyle;") //直接查询和解析单行数据   postgresDb.Update()              //修改/更新数据   postgresDb.Read()   postgresDb.Delete()              //删除数据   postgresDb.Read()   postgresDb.DropTable() }

执行 go run main.go运行结果如下:

Successfully created connection to database Finished dropping table (if existed) Finished creating table Inserted 3 rows of data Data row = (1, banana, 150) Data row = (2, orange, 154) Data row = (3, apple, 100) 2020/12/15 22:13:33 返回多元素数组: [{"id":"1","name":"banana","quantity":"150"},{"id":"2","name":"orange","quantity":"154"},{"id":"3","name":"apple","quantity":"100"}] 2020/12/15 22:13:33 返回单行数据Map: {"DateStyle":"ISO, MDY"} Updated 1 row of data Data row = (2, orange, 154) Data row = (3, apple, 100) Data row = (1, banana, 200) Deleted 1 row of data Data row = (3, apple, 100) Data row = (1, banana, 200) Finished dropping table (if existed)

“如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段”的内容就介绍到这里了,感谢大家的阅读。如果想了解更多行业相关的知识可以关注亿速云网站,小编将为大家输出更多高质量的实用文章!

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

如何理解Golang牵手PostgreSQL增删改查+不写结构快速扫描字段

下载Word文档到电脑,方便收藏和打印~

下载Word文档

编程热搜

  • Python 学习之路 - Python
    一、安装Python34Windows在Python官网(https://www.python.org/downloads/)下载安装包并安装。Python的默认安装路径是:C:\Python34配置环境变量:【右键计算机】--》【属性】-
    Python 学习之路 - Python
  • chatgpt的中文全称是什么
    chatgpt的中文全称是生成型预训练变换模型。ChatGPT是什么ChatGPT是美国人工智能研究实验室OpenAI开发的一种全新聊天机器人模型,它能够通过学习和理解人类的语言来进行对话,还能根据聊天的上下文进行互动,并协助人类完成一系列
    chatgpt的中文全称是什么
  • C/C++中extern函数使用详解
  • C/C++可变参数的使用
    可变参数的使用方法远远不止以下几种,不过在C,C++中使用可变参数时要小心,在使用printf()等函数时传入的参数个数一定不能比前面的格式化字符串中的’%’符号个数少,否则会产生访问越界,运气不好的话还会导致程序崩溃
    C/C++可变参数的使用
  • css样式文件该放在哪里
  • php中数组下标必须是连续的吗
  • Python 3 教程
    Python 3 教程 Python 的 3.0 版本,常被称为 Python 3000,或简称 Py3k。相对于 Python 的早期版本,这是一个较大的升级。为了不带入过多的累赘,Python 3.0 在设计的时候没有考虑向下兼容。 Python
    Python 3 教程
  • Python pip包管理
    一、前言    在Python中, 安装第三方模块是通过 setuptools 这个工具完成的。 Python有两个封装了 setuptools的包管理工具: easy_install  和  pip , 目前官方推荐使用 pip。    
    Python pip包管理
  • ubuntu如何重新编译内核
  • 改善Java代码之慎用java动态编译

目录