上篇文章把數據存進了文件,這篇文章將把數據存入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
複製代碼
更新和刪除用法就不展現了,看文檔便可。
完整代碼能夠在這個地址找到。