首先我们建立一个新的数据库cofoxdb和数据包user:

新增管理员
golang 访问Mysql数据库增删改查和连接池及空字段处理 - 图1

切换tab
golang 访问Mysql数据库增删改查和连接池及空字段处理 - 图2

设置用户权限
golang 访问Mysql数据库增删改查和连接池及空字段处理 - 图3

新建数据库 cofoxdb
golang 访问Mysql数据库增删改查和连接池及空字段处理 - 图4

双击数据库成为当前库,点击图标后写入SQL建表脚本
golang 访问Mysql数据库增删改查和连接池及空字段处理 - 图5

建表SQL脚本

  1. drop TABLE if exists `user`;
  2. CREATE TABLE `user` (
  3. `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '流水号',
  4. `userName` varchar(45) NOT NULL COMMENT '用户名【不可更改】',
  5. `password` varchar(255) NOT NULL COMMENT '密码',
  6. `nickName` varchar(45) NOT NULL COMMENT '昵称',
  7. `registTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '用户注册时间',
  8. `lastTimeLogin` datetime DEFAULT NULL COMMENT '上次登录时间',
  9. `newLoginTime` datetime DEFAULT NULL COMMENT '最新登录时间(当前登录时间)',
  10. `bak` varchar(1000) DEFAULT NULL COMMENT '备注',
  11. `online` char(1) DEFAULT 'N' COMMENT '当前在线,Y/N\nY:在线\nN:不在线',
  12. `createTime` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '记录创建时间',
  13. `creator` varchar(45) DEFAULT NULL COMMENT '记录创建人',
  14. `updateTime` datetime DEFAULT NULL COMMENT '记录修改时间',
  15. `updator` varchar(45) DEFAULT NULL COMMENT '记录修改人',
  16. PRIMARY KEY (`id`,`userName`,`nickName`)
  17. ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8 COMMENT='All Registered users';

由于在一个应用中会有多处代码需要链接数据库,所以我们准备一个全局变量,供所有需要者调用。同时声明的也有error变量。

  1. var db *sql.DB
  2. var err error

需要给db实例化,建立一个init()函数,这样,在main()函数执行前就可以把数据库链接完成初始化了。

  1. func init() {
  2. db, err = sql.Open("mysql", "cofox:Q1w2e3r4@tcp(127.0.0.1:3306)/cofoxdb?charset=utf8")
  3. check(err)
  4. db.SetMaxOpenConns(2000)
  5. db.SetMaxIdleConns(1000)
  6. check(db.Ping())
  7. }
  • db.SetMaxOpenConns(2000)是设置这个连接池最大连接数是2000个

  • db.SetMaxIdleConns(1000)设置的是连接池内最低保存1000个待用连接。这样当有需要访问的程序请求时,就可以从连接池内分配一条已有的链接。提供访问效率。

  • db.Ping()是为了让程序和数据库进行真正的连接。(sql.Open并没有建立真正的连接关系,只是初始化)。

插入数据

直接使用db.Prepare,因为db已经被初始化了。
res.LastInsertId()执行后返回最新的id。如果是批量数据插入的话,这个会返回第一条记录额id。

  1. func insert() {
  2. stmt, err := db.Prepare(`INSERT user (userName, password, nickName) VALUES (?, ?, ?)`)
  3. check(err)
  4. res, err := stmt.Exec("cofox_1","123456","冷静的狐狸")
  5. check(err)
  6. id, err := res.LastInsertId()
  7. check(err)
  8. fmt.Println(id)
  9. stmt.Close()
  10. }

修改数据

也是直接使用db。res.RowsAffected()提交执行,返回修改了的记录数。

  1. func update() {
  2. stmt, err := db.Prepare("UPDATE user set nickName=?, updateTime=?, updator=?, bak=? WHERE id=?")
  3. check(err)
  4. res, err := stmt.Exec("厚土火焰山",time.Now().Format("2006-01-02 15:04:05"),"root","测试更新\r\ngo直连数据库", 1)
  5. check(err)
  6. num, err := res.RowsAffected()
  7. check(err)
  8. fmt.Println(num)
  9. stmt.Close()
  10. }

删除数据

res.RowsAffected()提交执行,返回删除了的记录数。

  1. func remove() {
  2. stmt, err := db.Prepare("DELETE FROM cofoxdb WHERE id=?")
  3. check(err)
  4. res, err := stmt.Exec(7)
  5. check(err)
  6. num, err := res.RowsAffected()
  7. check(err)
  8. fmt.Println(num)
  9. stmt.Close()
  10. }

查询数据

因为表字段较多,很多字段在新增后或许仍然没有写入相应的数据,这些字段如果没有默认值的话,就会是NULL值。
NULL值在go语言中是不能写入stirng time.Time的。所以这里我们使用”database/sql”提供的dql.NullString类型。当然NULL**还有很多NULLInt64、NULLFloat64、NULLBool

  1. var id int
  2. var userName string
  3. var password string
  4. var nickName string
  5. var registTime string
  6. var lastTimeLogin sql.NullString
  7. var newLoginTime sql.NullString
  8. var bak sql.NullString
  9. var online sql.NullString
  10. var createTime sql.NullString
  11. var creator sql.NullString
  12. var updateTime sql.NullString
  13. var updator sql.NullString

我们使用这个类型来处理字段有可能为NULL的数据。这样就可以正常读取记录值了。
这些NullString的类型结构是这样的

  1. type NullString struct {
  2. String string
  3. Valid bool // Valid is true if String is not NULL
  4. }

都是有两个字段在里面。而String字段就是我们最终想要的东西。所以,在输出或使用的时候,我们这样组织代码

  1. lastTimeLogin.String, newLoginTime.String, bak.String, online.String, createTime.String, creator.String, updateTime.String, updator.String

执行insert()后,我们在执行query2(),得到如下结果

  1. id = "3", userName = "cofox_1", password = "123456", nickName = "冷静的狐狸", registTime = "2017-09-07 17:39:02", lastTimeLogin = "", newLoginTime = "", bak = "", online = "N", createTime = "2017-09-07 17:39:02", creator = "", updateTime = "", updator = ""

完整的代码示例

  1. package main
  2. import (
  3. "database/sql"
  4. _"github.com/go-sql-driver/mysql"
  5. "fmt"
  6. "log"
  7. "time"
  8. )
  9. var db *sql.DB
  10. var err error
  11. func init() {
  12. db, err = sql.Open("mysql", "cofox:Q1w2e3r4@tcp(127.0.0.1:3306)/cofoxdb?charset=utf8")
  13. check(err)
  14. db.SetMaxOpenConns(2000)
  15. db.SetMaxIdleConns(1000)
  16. check(db.Ping())
  17. }
  18. func main() {
  19. //query()
  20. query2()
  21. //insert()
  22. //update()
  23. //remove()
  24. }
  25. //查询数据
  26. func query() {
  27. rows, err := db.Query("SELECT * FROM user")
  28. check(err)
  29. for rows.Next() {
  30. columns, _ := rows.Columns()
  31. scanArgs := make([]interface{}, len(columns))
  32. values := make([]interface{}, len(columns))
  33. for i := range values {
  34. scanArgs[i] = &values[i]
  35. }
  36. //将数据保存到 record 字典
  37. err = rows.Scan(scanArgs...)
  38. record := make(map[string]string)
  39. for i, col := range values {
  40. if col != nil {
  41. record[columns[i]] = string(col.([]byte))
  42. }
  43. }
  44. fmt.Println(record)
  45. }
  46. rows.Close()
  47. }
  48. func query2() {
  49. rows, err := db.Query("SELECT id, userName, password, nickName, registTime, lastTimeLogin, newLoginTime, bak, online, createTime, creator, updateTime, updator FROM user")
  50. check(err)
  51. for rows.Next(){
  52. var id int
  53. var userName string
  54. var password string
  55. var nickName string
  56. var registTime string
  57. var lastTimeLogin sql.NullString
  58. var newLoginTime sql.NullString
  59. var bak sql.NullString
  60. var online sql.NullString
  61. var createTime sql.NullString
  62. var creator sql.NullString
  63. var updateTime sql.NullString
  64. var updator sql.NullString
  65. //注意这里的Scan括号中的参数顺序,和 SELECT 的字段顺序要保持一致。
  66. if err := rows.Scan(&id, &userName, &password, &nickName, &registTime, &lastTimeLogin, &newLoginTime, &bak, &online, &createTime, &creator, &updateTime, &updator); err != nil {
  67. log.Fatal(err)
  68. }
  69. fmt.Printf("id = \"%d\", userName = \"%s\", password = \"%s\", nickName = \"%s\", registTime = \"%s\", lastTimeLogin = \"%s\", newLoginTime = \"%s\", bak = \"%s\", online = \"%s\", createTime = \"%s\", creator = \"%s\", updateTime = \"%s\", updator = \"%s\"\n",id, userName, password, nickName, registTime, lastTimeLogin.String, newLoginTime.String, bak.String, online.String, createTime.String, creator.String, updateTime.String, updator.String)
  70. }
  71. if err := rows.Err(); err != nil {
  72. log.Fatal(err)
  73. }
  74. rows.Close()
  75. }
  76. //插入数据
  77. func insert() {
  78. stmt, err := db.Prepare(`INSERT user (userName, password, nickName) VALUES (?, ?, ?)`)
  79. check(err)
  80. res, err := stmt.Exec("cofox_1","123456","冷静的狐狸")
  81. check(err)
  82. id, err := res.LastInsertId()
  83. check(err)
  84. fmt.Println(id)
  85. stmt.Close()
  86. }
  87. //修改数据
  88. func update() {
  89. stmt, err := db.Prepare("UPDATE user set nickName=?, updateTime=?, updator=?, bak=? WHERE id=?")
  90. check(err)
  91. res, err := stmt.Exec("厚土火焰山",time.Now().Format("2006-01-02 15:04:05"),"root","测试更新\r\ngo直连数据库", 1)
  92. check(err)
  93. num, err := res.RowsAffected()
  94. check(err)
  95. fmt.Println(num)
  96. stmt.Close()
  97. }
  98. //删除数据
  99. func remove() {
  100. stmt, err := db.Prepare("DELETE FROM cofoxdb WHERE id=?")
  101. check(err)
  102. res, err := stmt.Exec(7)
  103. check(err)
  104. num, err := res.RowsAffected()
  105. check(err)
  106. fmt.Println(num)
  107. stmt.Close()
  108. }
  109. func check(err error) {
  110. if err != nil{
  111. fmt.Println(err)
  112. panic(err)
  113. }
  114. }

golang 访问Mysql数据库增删改查和连接池及空字段处理 - 图6