数据库技术:Golang连接并操作PostgreSQL数据库基本操作

前言:本篇文章对如何使用golang连接并操作postgre数据库进行了简要说明。文中使用到的主要工具:dbeaver21、vscode,golang1.17。以用户,文章,评论三个表作为例子,下面是

前言:

本篇文章对如何使用golang连接并操作postgre数据库进行了简要说明。文中使用到的主要工具:dbeaver21、vscode,golang1.17。

以用户,文章,评论三个表作为例子,下面是数据库建表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)  );  

连接数据库

连接postgre数据库的驱动有很多,我们选用了github.com/lib/pq。下面看连接的方法。我们引入pq包时使用了_进行匿名加载,而不是直接使用驱动包。在对数据库的操作仍然是使用自带的sql包。另外,postgre默认使用的是public模式(schema),我们创建的表也是在这个模式下的。可以直接在数据库中修改默认模式或者在连接url中添加currentschema=myschema来指定默认的模式,当然也可以在sql中使用myschema.table来指定要访问的模式。

package main    import (      "database/sql"      "fmt"        _ "github.com/lib/pq"  )    var db *sql.db    func dbopen() {      var err error      //参数根据自己的数据库进行修改      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并不是数据库连接,而是一个go中的一个数据结构:

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时并不会创建新的连接,而可以认为是拿到了一个数据库连接池,只有在执行数据库操作(如ping()操作)时才会自动生成一个连接并连接数据库。在连接操作执行完毕后应该及时地释放。此处说的释放是指释放连接而不是sql.db连接,通常来说一个sql.db应该像全局变量一样长期保存,而不要在某一个小函数中都进行open()close()操作,否则会引起资源耗尽的问题。

增删改查

下面代码实现对数据简单的增删改查操作。

插入数据

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()函数后会返回一个sql.result即上面的res变量接收到的返回值,它提供了lastinserid() (int64, error)rowsaffected() (int64, error)分别获取执行语句返回的对应的id和语句执行所影响的行数。

更新数据

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)  }  

查询数据

结构体如下:

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)        }      //延迟关闭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 = %vn", user.id, user.user_name, user.create_time)      }  }  

可以看到使用到的几个关键函数rows.close()rows.next()rows.scan()。其中rows.next()用来遍历从数据库中获取到的结果集,随用用rows.scan()来将每一列结果赋给我们的结构体。

需要强调的是rows.close()。每一个打开的rows都会占用系统资源,如果不能及时的释放那么会耗尽系统资源。defer语句类似于java中的finally,功能就是在函数结束前执行后边的语句。换句话说,在函数结束前不会执行后边的语句,因此在耗时长的函数中不建议使用这种方式释放rows连接。如果要在循环中重发查询和使用结果集,那么应该在处理完结果后显式调用rows.close()

db.query()实际上等于创建db.prepare(),执行并关闭之三步操作。

还可以这样来查询单条记录:

err := db.query("select u_id, user_name, create_time from user_info where user_name=$1", "ah").scan(&user.user_name)

删除数据

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)  }  

总结

到此这篇关于golang连接并操作postgresql数据库基本操作的文章就介绍到这了,更多相关golang连接操作postgresql内容请搜索<猴子技术宅>以前的文章或继续浏览下面的相关文章希望大家以后多多支持<猴子技术宅>!

需要了解更多数据库技术:Golang连接并操作PostgreSQL数据库基本操作,都可以关注数据库技术分享栏目—猴子技术宅(www.ssfiction.com)

本文来自网络收集,不代表猴子技术宅立场,如涉及侵权请点击右边联系管理员删除。

如若转载,请注明出处:https://www.ssfiction.com/sqljc/1246497.html

(0)
上一篇 2天前
下一篇 2天前

精彩推荐

发表回复

您的电子邮箱地址不会被公开。