go-gorp 一款轻量级的 orm 框架搭配 mysql 的实践

go-gorp 是一款 go orm 框架,它可以节省您的时间,最大程度地减少将数据移入和移出数据库的麻烦,并帮助您的代码专注于算法,而不是基础架构。要参考更加详细的文档,请移步仓库源码:https://github.com/go-gorp/gorp
  1. 结构体字段与数据库列绑定
  2. 支持事务
  3. 支持sql语句打印
  4. 支持增删改的钩子方法
  5. 支持更新删除乐观锁
  6. 支持防止sql注入的参数化

安装


go get gopkg.in/gorp.v2

 

建表


CREATE TABLE `posts` (
  `post_id` int(11) NOT NULL AUTO_INCREMENT,
  `Created` int(11) DEFAULT NULL,
  `Title` varchar(200) DEFAULT NULL,
  `article_body` varchar(1024) DEFAULT NULL,
  PRIMARY KEY (`post_id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8
 

源码样例


代码从官方文档直接翻译过来,将官方的 sqlite3 改成 mysql,包含增删改查,单值(整型,字符串)查询 ,单行查询返回一个结构体,多行查询返回一个结构体 slice,每个方法使用前都给出了注释,如下代码所示:
package main

import (
   "database/sql"
   _ "github.com/go-sql-driver/mysql"
   "gopkg.in/gorp.v2"
   "log"
   "time"
)

func main() {
   // 初始化 DbMap
   dbmap := initDb()
   defer dbmap.Db.Close()

   // 删除所有数据,这样可以使得自增的数字从新从 1 开始
   err := dbmap.TruncateTables()
   checkErr(err, "TruncateTables failed")

   // 创建两个话题,无需给 Id 赋值,因为 Id 是自增列
   p1 := newPost("go-gorp 是一个 orm 框架", "我们使用 gorp 在我们的 web 项目中")
   p2 := newPost("gorp  mysql 的使用样例", "gorp 是一款流行的 go orm 框架")

   // 插入上面两条数据,Id 是自增,无需赋值
   err = dbmap.Insert(&p1, &p2)
   checkErr(err, "Insert failed")

   // SelectInt 获取整型单值
   count, err := dbmap.SelectInt("select count(*) from posts")
   checkErr(err, "select count(*) failed")
   log.Println("Rows after inserting:", count)

   // 更新值
   p2.Title = "go-gorp 更新值,按照 id 指定的更新了"
   count, err = dbmap.Update(&p2)
   checkErr(err, "Update failed")
   log.Println("Rows updated:", count)

   // 获取一行,注意 “post_id” 代替 “Id”,它是一个别名
   err = dbmap.SelectOne(&p2, "select * from posts where post_id=?", p2.Id)
   checkErr(err, "SelectOne failed")
   log.Println("p2 row:", p2)

   // 获取所有行,这里最体现 orm 的特点,它会自动对应结构体的字段,
   // 注意结构体的字段必须不能少于数据库返回的字段,否则会报错
   // 返回的每个字段均不能为空,否则会报错
   var posts []Post
   _, err = dbmap.Select(&posts, "select * from posts order by post_id")
   checkErr(err, "Select failed")
   log.Println("All rows:")
   for x, p := range posts {
      log.Printf("    %d: %v\n", x, p)
   }

   // 根据主键删除数据
   count, err = dbmap.Delete(&p1)
   checkErr(err, "Delete failed")
   log.Println("Rows deleted:", count)

   // 删除行通过 exec
   _, err = dbmap.Exec("delete from posts where post_id=?", p2.Id)
   checkErr(err, "Exec failed")

   // 确定表中已无数据
   count, err = dbmap.SelectInt("select count(*) from posts")
   checkErr(err, "select count(*) failed")
   log.Println("Row count - should be zero:", count)

   log.Println("Done!")
}

type Post struct {
   Id      int64 `db:"post_id"`
   Created int64
   Title   string `db:",size:50"`
   Body    string `db:"article_body,size:1024"`
}

func newPost(title, body string) Post {
   return Post{
      Created: time.Now().UnixNano(),
      Title:   title,
      Body:    body,
   }
}

func initDb() *gorp.DbMap {
   // 使用标准的 Go database/sql API 建立连接
   db, err := sql.Open("mysql", "root:pwd123456@tcp(192.168.111.151:3306)/hrefs?charset=utf8")
   checkErr(err, "sql.Open failed")

   // 创建一个结构
   dbmap := &gorp.DbMap{Db: db, Dialect: gorp.MySQLDialect{}}

   // 添加一个表,设置表名“posts”,指定一个主键为“Id”true 表示自增
   dbmap.AddTableWithName(Post{}, "posts").SetKeys(true, "Id")

   return dbmap
}

func checkErr(err error, msg string) {
   if err != nil {
      log.Fatalln(msg, err)
   }
}

跟踪 SQL 日志


// 将下面语句放在初始化函数中
// 运行时将记录所有的 sql 语言
// 第一个参数是一个前缀,后面是一个 GorpLogger 接口,实现 GorpLogger 接口都可以
dbmap.TraceOn("[gorp]", log.New(os.Stdout, "[SQL]:", log.Lmicroseconds))
 
输出的 sql 日志如下所示
Posted by 何敏 on 2020-02-17 05:38:43