上篇文章把数据存进了文件,这篇文章将把数据存入MySQL数据库。数据库的使用是每一个开发者必备的技能,因此本篇文章咱们使用Golang操做数据库。Golang没有内置的驱动支持任何的数据库,可是Go定义了database/sql接口,开发者能够基于驱动接口开发相应数据库的驱动。固然如今各类数据库驱动生态已经很稳定了,能够直接使用。mysql
我在实际开发工做中通常不直接用数据库驱动(如github.com/go-sql-driver/mysql),而是用ORM。ORM有三大优势:git
因此使用ORM能提升开发效率,下降开发成本,可是缺点是ORM的封装是有成本的,会稍微影响到性能,不过我认为这点性能损耗微乎其微。github
目前Golang世界里面最受欢迎的ORM叫作gorm,咱们就使用它,先安装它:golang
❯ go get -u github.com/jinzhu/gorm
❯ go get -u github.com/go-sql-driver/mysql # 也要安装对应数据库驱动
复制代码
gorm用的MySQL驱动其实就是go-sql-driver/mysql
,但一般这么import:sql
import (
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/mysql"
)
复制代码
有时候对于某个包,不须要把整个包都导入进来,只是执行他的init函数。可使用import _
这样的写法,不过要注意,这种方式没法经过包名来调用包中的其余函数。数据库
接着咱们声明Model:安全
type Movie struct {
ID int
Title string `gorm:"type:varchar(100);unique_index"`
}
复制代码
这个结构体叫作Movie,模型有2个字段ID和Title。Title后面有个反引号,这个部分叫作成员变量标签(Tag),当须要用到Tag中的内容时可使用反射包(reflect)中的方法来获取,这是gorm支持的用法。它表示定义title资格字段的长度是100,而且有惟一索引。其余支持的标签能够看官方文档。bash
若是看文档或者不少文章,常常能看到继承了gorm.Model
的模型,以下面这个:函数
type Movie struct {
gorm.Model
Title string `gorm:"type:varchar(100);unique_index"`
}
复制代码
gorm.Model 自带了ID, CreatedAt, UpdatedAt, DeletedAt这么4个字段,在咱们这里彻底没有必要。性能
在main函数里面链接数据库,并建立表:
func main() {
start := time.Now()
ch := make(chan bool)
db, err := gorm.Open("mysql", "root:@/test?charset=utf8")
defer db.Close()
checkError(err)
db.DropTableIfExists(&Movie{})
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&Movie{})
for i := 0; i < 11; i++ {
go parseUrls("https://movie.douban.com/top250?start="+strconv.Itoa(25*i), ch, db)
}
for i := 0; i < 11; i++ {
<-ch
}
elapsed := time.Since(start)
log.Printf("Took %s", elapsed)
}
复制代码
gorm.Open的第一个参数是数据库驱动名字,第二个就是具体的db uri,我这里用了默认的test库,用户名root,密码为空,字符集为utf-8。
为了每次都初始化表,因此先用DropTableIfExists
删除表,再用AutoMigrate
建立表。Migrate是迁移的意思,自动迁移仅仅会建立表,缺乏列和索引,而且不会改变现有列的类型或删除未使用的列以保护数据。这样能够更新表结构,通常不会直接用CreateTable建立表了。db.Set是为了建立表时添加表后缀。
parseUrls的最后一个参数db是*gorm.DB类型的。
好了,运行一下:
❯ go run doubanCrawler.go
复制代码
执行结束能够用MySQL CLI看到数据了:
mysql> select * from movies order by id desc limit 3;
+----------|-----------------------------+
| id | title |
+----------|-----------------------------+
| 30170448 | 何觉得家 |
| 27191492 | 四个春天 |
| 26799731 | 请以你的名字呼唤我 |
+----------|-----------------------------+
3 rows in set (0.00 sec)
复制代码
上面用到的只是db.Create建立记录,接着看看怎么查询(按行注释):
func main() {
db, err := gorm.Open("mysql", "root:@/test?charset=utf8")
defer db.Close()
checkError(err)
var movie Movie
var movies []Movie
db.First(&movie, 30170448) // 查询ID为30170448的记录,只支持主键
log.Println(movie)
log.Println(movie.ID, movie.Title) // 能够得到对应属性
db.Order("id").Limit(3).Find(&movies) // 按ID升序排,取前三个记录赋值给movies
log.Println(movies)
log.Println(movies[0].ID)
db.Order("id desc").Limit(3).Offset(1).Find(&movies) // Order也支持desc选择降序, offset表示对结果集从第2个记录开始
log.Println(movies)
db.Select("title").First(&movies, "title = ?", "四个春天") // 用Select能够限定只返回那些字段,First也支持条件
log.Println(movie)
var count int64
db.Where("id = ?", 30170448).Or("title = ?", "四个春天").Find(&movies).Count(&count) // Where后加条件,在这里是id为30170448或者title为"四个春天"2个条件符合之一便可,最后用Count算一下符合的记录数
log.Println(count)
}
复制代码
执行一下:
❯ go run doubanCrawler2.go
2019/07/13 21:16:24 {30170448 何觉得家}
2019/07/13 21:16:24 30170448 何觉得家
2019/07/13 21:16:24 [{1291543 功夫} {1291545 大鱼} {1291546 霸王别姬}]
2019/07/13 21:16:24 1291543
2019/07/13 21:16:24 [{27191492 四个春天} {26799731 请以你的名字呼唤我} {26787574 奇迹男孩}]
2019/07/13 21:16:24 [{0 何觉得家}]
2019/07/13 21:16:24 {30170448 何觉得家}
2019/07/13 21:16:24 2
复制代码
更新和删除用法就不展现了,看文档便可。
完整代码能够在这个地址找到。