接着上文,实现了软删除。这里我们实现硬删除,并且定时清理这些无效数据。
上一章我们实现了软删除,好处是数据更新更快。
另一条是,数据是有价值的,软删除可以让误操作的数据恢复。
那么我们就需要另一套接口:
- 实现硬删除功能
- 定期清理无效数据
实现硬删除
在修改models目录下的tag.go文件如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
package models //Tag 标签 type Tag struct { Model Name string `json:"name"` CreatedBy string `json:"created_by"` ModifiedBy string `json:"modified_by"` State int `json:"state"` } //GetTags 获取标签 func GetTags( pageNum int, pageSize int, maps interface{}, ) (tags []Tag) { db.Where(maps).Where("deleted_on = ?", 0).Offset(pageNum).Limit(pageSize).Find(&tags) return } //GetTagTotal 获取标签总数 func GetTagTotal( maps interface{}, ) (count int64) { db.Model(&Tag{}).Where(maps).Where("deleted_on = ?", 0).Count(&count) return } //IsExistTagByName 判断标签是否存在 // name tag.Name string 标签名称 // ret: bool 如果标签存在返回true, 否则返回false func IsExistTagByName(name string) bool { var tag Tag db.Select("id").Where("name = ? AND deleted_on = ?", name, 0).First(&tag) return tag.ID > 0 } //IsExistTagByID 判断标签是否存在 // id tag.ID int 标签ID // ret: bool 如果标签存在返回true,否则返回false func IsExistTagByID(id int) bool { var tag Tag db.Select("id").Where("id = ? AND deleted_on = ?", id, 0).First(&tag) return tag.ID > 0 } //AddTag 新增标签 func AddTag( name string, state int, createdBy string, ) bool { err := db.Create(&Tag{ Name: name, State: state, CreatedBy: createdBy, }).Error return err == nil } //EditTag 修改标签 // 不做deleted_on判断,可以通过接口将deleted_on设置为0(恢复数据) func EditTag( id int, data interface{}, ) bool { err := db.Model(&Tag{}).Where("id = ?", id).Updates(data).Error return err == nil } //DeleteTag 删除标签 func DeleteTag( id int, ) bool { //实现软删除 err := db.Where("id = ?", id).Delete(&Tag{}).Error return err == nil } //CleanAllTag 清理标签 // 函数会清理所有已经被软删除的标签 func CleanAllTag() bool { err := db.Unscoped().Where("deleted_on != ?", 0).Delete(&Tag{}).Error return err == nil } |
这里的主要改动点:
- 增加 CleanAllTag 函数,它负责清理已经被软删除的Tag
- 相比之前提供的版本,增加了软删除字段的处理(上一章没有给出)
对应的给出 article.go 文件实现如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 |
package models //Article 文章 type Article struct { Model TagID int `json:"tag_id" gorm:"index"` Tag Tag `json:"tag"` Title string `json:"title"` Desc string `json:"desc"` Content string `json:"content"` CreatedBy string `json:"created_by"` ModifiedBy string `json:"Modified_by"` State int `json:"state"` } //IsExistArticleByID 判断文章是否存在 // id article.ID int 文章ID // ret: bool 如果文章存在返回true,否则返回false func IsExistArticleByID(id int) bool { var article Article db.Select("id").Where("id = ?", id).Where("deleted_on = ?", 0).First(&article) return article.ID > 0 } //GetArticleTotal 获取文章总数 func GetArticleTotal( maps interface{}, ) (count int64) { db.Model(&Article{}).Where(maps).Where("deleted_on = ?", 0).Count(&count) return } //GetArticels 获取文章 func GetArticels( pageNum int, pageSize int, maps interface{}, ) (articles []Article) { db.Preload("Tag").Where(maps).Where("deleted_on = ?", 0).Offset(pageNum).Limit(pageSize).Find(&articles) return } //GetArticle 获取文章 func GetArticle(id int) (article Article) { db.Preload("Tag").Where("id = ?", id).Where("deleted_on = ?", 0).First(&article) return } //EditArticle 更新文章 // 更新接口不判断deleted_on字段 func EditArticle( id int, data interface{}, ) bool { err := db.Model(&Article{}).Where("id = ?", id).Updates(data).Error return err == nil } //AddArticle 新增文章 func AddArticle( data map[string]interface{}, ) bool { err := db.Create(&Article{ TagID: data["tag_id"].(int), Title: data["title"].(string), Desc: data["desc"].(string), Content: data["content"].(string), CreatedBy: data["created_by"].(string), State: data["state"].(int), }).Error return err == nil } //DeleteArticle 删除文章 func DeleteArticle(id int) bool { err := db.Where("id = ?", id).Delete(Article{}).Error return err == nil } //CleanAllArticle 清理文章 func CleanAllArticle() bool { err := db.Unscoped().Where("deleted_on != ?", 0).Delete(Article{}).Error return err == nil } |
这里和tag修改的部分大致相同。
记得,如果你没给 blog_article 表增加 deleted_on字段,现在应加上了。
ALTER TABLE blog_article
ADD deleted_on
INT(10) UNSIGNED NULL DEFAULT ‘0’ COMMENT ‘软删除 删除时间’ AFTER modified_by
;
实现定时任务
这里我们使用cron库。
文档:https://godoc.org/github.com/robfig/cron
可以参考的链接:
https://www.cnblogs.com/jssyjam/p/11910851.html
https://www.cnblogs.com/zhichaoma/p/12509160.html
安装 cron v3
github上给出的版本已经是v3了。(P.s. 看最新Release已经是v3.0.1)
go get -u github.com/robfig/cron/v3
编写最简单的Cron
直接在项目根目录 ginBlog 建立文件夹 cron,文件夹下建立 cron.go 文件,文件内容如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
package main import ( "ginBlog/models" "log" cron "github.com/robfig/cron/v3" ) func newWithSeconds() *cron.Cron { secondParser := cron.NewParser( cron.SecondOptional | cron.Minute | cron.Hour | cron.Dom | cron.Month | cron.Dow | cron.Descriptor, ) return cron.New(cron.WithParser(secondParser), cron.WithChain()) } func main() { log.Println("[Cron] Starting...") c := newWithSeconds() spec := "*/5 * * * * *" //每5秒执行一次 c.AddFunc(spec, func() { log.Println("[Cron] Run models.CleanAllTag...") models.CleanAllTag() }) c.AddFunc(spec, func() { log.Println("[Cron] Run models.CleanAllArticle...") models.CleanAllArticle() }) c.Start() select {} } |
验证
执行定时任务
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
[xiong@AMDServer ginBlog]$ go run cron/cron.go 2020/09/14 10:32:53 [Cron] Starting... 2020/09/14 10:32:55 [Cron] Run models.CleanAllTag... 2020/09/14 10:32:55 [Cron] Run models.CleanAllArticle... DELETE FROM `blog_tag` WHERE deleted_on != ? DELETE FROM `blog_article` WHERE deleted_on != ? 2020/09/14 10:33:00 [Cron] Run models.CleanAllArticle... 2020/09/14 10:33:00 [Cron] Run models.CleanAllTag... DELETE FROM `blog_tag` WHERE deleted_on != ? DELETE FROM `blog_article` WHERE deleted_on != ? 2020/09/14 10:33:05 [Cron] Run models.CleanAllArticle... 2020/09/14 10:33:05 [Cron] Run models.CleanAllTag... DELETE FROM `blog_article` WHERE deleted_on != ? DELETE FROM `blog_tag` WHERE deleted_on != ? ^Csignal: interrupt |
对应的查看数据库前后内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
mysql> SELECT * FROM blog_tag; +----+---------+------------+------------+-------------+-------------+------------+-------+ | id | name | created_on | created_by | modified_on | modified_by | deleted_on | state | +----+---------+------------+------------+-------------+-------------+------------+-------+ | 7 | 3 | 1599022723 | root | 0 | | 0 | 1 | | 8 | create1 | 1599026312 | root | 0 | | 0 | 1 | | 11 | 6 | 1599671277 | root | 0 | | 0 | 1 | | 30 | 10 | 1600045437 | root | 0 | | 1600045504 | 1 | | 31 | 11 | 1600045440 | root | 0 | | 0 | 1 | | 32 | 12 | 1600045445 | root | 0 | | 0 | 1 | | 33 | 13 | 1600045447 | root | 0 | | 1600045519 | 1 | | 34 | 14 | 1600045449 | root | 0 | | 0 | 1 | | 35 | 15 | 1600045452 | root | 0 | | 0 | 1 | +----+---------+------------+------------+-------------+-------------+------------+-------+ 9 rows in set (0.00 sec) mysql> SELECT * FROM blog_tag; +----+---------+------------+------------+-------------+-------------+------------+-------+ | id | name | created_on | created_by | modified_on | modified_by | deleted_on | state | +----+---------+------------+------------+-------------+-------------+------------+-------+ | 7 | 3 | 1599022723 | root | 0 | | 0 | 1 | | 8 | create1 | 1599026312 | root | 0 | | 0 | 1 | | 11 | 6 | 1599671277 | root | 0 | | 0 | 1 | | 31 | 11 | 1600045440 | root | 0 | | 0 | 1 | | 32 | 12 | 1600045445 | root | 0 | | 0 | 1 | | 34 | 14 | 1600045449 | root | 0 | | 0 | 1 | | 35 | 15 | 1600045452 | root | 0 | | 0 | 1 | +----+---------+------------+------------+-------------+-------------+------------+-------+ 7 rows in set (0.00 sec) |
定时参数
本来想介绍下参数的…但是写的没别人好啊。
看这篇文章吧,https://www.cnblogs.com/zhichaoma/p/12509160.html
【Go】gin Blog项目(九) Cron定时任务