3

如何使用ORM链式操作?如何优雅的实现软删除?

 1 year ago
source link: https://www.51cto.com/article/722501.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

会带大家完成【电商实战项目】的轮播图删除功能,用到的知识点包括:

  • ORM链式操作
  • 如何优雅的进行时间维护
  • 软删除和物理删除的区别
  • 如何优雅的实现软删除
  • 结合商业项目需求,有哪些容易踩的坑?

ORM链式操作-时间维护

需要注意,该特性仅对链式操作有效。

gdb模块支持对数据记录的写入、更新、删除时间自动填充,提高开发维护效率。为了便于时间字段名称、类型的统一维护,如果使用该特性,我们约定:

  • 字段应当设置允许值为null。
  • 字段的类型必须为时间类型,如:date​,  datetime​,  timestamp​。不支持数字类型字段,如int。
  • 字段的名称不支持自定义设置,并且固定名称约定为:

created_at用于保存记录的创建时间,仅会写入一次。

updated_at用于保存记录的修改时间,每次记录变更时更新。

deleted_at用于保存记录的软删除特性,只有当记录删除时会写入一次。

字段名称其实不区分大小写,也会忽略特殊字符,例如CreatedAt​,  UpdatedAt​,  DeletedAt​也是支持的。此外,时间字段名称可以通过配置文件进行自定义修改,并可使用TimeMaintainDisabled配置完整关闭该特性,具体请参考 ORM使用配置 章节。

对时间类型的固定其实是为了形成一种规范。

特性的启用

当数据表包含created_at、updated_at、deleted_at任意一个或多个字段时,该特性自动启用。

以下的示例中,我们默认示例中的数据表均包含了这3个字段。

​created_at​​写入时间

在执行Insert/InsertIgnore/BatchInsert/BatchInsertIgnore方法时自动写入该时间,随后保持不变。

// INSERT INTO `user`(`name`,`created_at`,`updated_at`) VALUES('john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`)
g.Model("user").Data(g.Map{"name": "john"}).Insert()

// INSERT IGNORE INTO `user`(`uid`,`name`,`created_at`,`updated_at`) VALUES(10000,'john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`)
g.Model("user").Data(g.Map{"uid": 10000, "name": "john"}).InsertIgnore()

// REPLACE INTO `user`(`uid`,`name`,`created_at`,`updated_at`) VALUES(10000,'john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`)
g.Model("user").Data(g.Map{"uid": 10000, "name": "john"}).Replace()

// INSERT INTO `user`(`uid`,`name`,`created_at`,`updated_at`) VALUES(10001,'john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`) ON DUPLICATE KEY UPDATE `uid`=VALUES(`uid`),`name`=VALUES(`name`),`updated_at`=VALUES(`updated_at`)
g.Model("user").Data(g.Map{"uid": 10001, "name": "john"}).Save()

需要注意的是Replace方法也会更新该字段,因为该操作相当于删除已存在的旧数据并重新写一条数据。

​updated_at​​更新时间

在执行Insert/InsertIgnore/BatchInsert/BatchInsertIgnore​方法时自动写入该时间,在执行Save/Update​时更新该时间(注意当写入数据存在时会更新updated_at​时间,不会更新created_at时间)。

// UPDATE `user` SET `name`='john guo',`updated_at`='2020-06-06 21:00:00' WHERE name='john'
g.Model("user").Data(g.Map{"name" : "john guo"}).Where("name", "john").Update()

// UPDATE `user` SET `status`=1,`updated_at`='2020-06-06 21:00:00' ORDER BY `login_time` asc LIMIT 10
g.Model("user").Data("status", 1).Order("login_time asc").Limit(10).Update()

// INSERT INTO `user`(`id`,`name`,`update_at`) VALUES(1,'john guo','2020-12-29 20:16:14') ON DUPLICATE KEY UPDATE `id`=VALUES(`id`),`name`=VALUES(`name`),`update_at`=VALUES(`update_at`)
g.Model("user").Data(g.Map{"id": 1, "name": "john guo"}).Save()

需要注意的是Replace方法也会更新该字段,因为该操作相当于删除已存在的旧数据并重新写一条数据。

​deleted_at​​数据软删除

软删除会稍微比较复杂一些,当软删除存在时,所有的查询语句都将会自动加上deleted_at的条件。

// UPDATE `user` SET `deleted_at`='2020-06-06 21:00:00' WHERE uid=10
g.Model("user").Where("uid", 10).Delete()

查询的时候会发生一些变化,例如:

// SELECT * FROM `user` WHERE uid>1 AND `deleted_at` IS NULL
g.Model("user").Where("uid>?", 1).All()

可以看到当数据表中存在deleted_at​字段时,所有涉及到该表的查询操作都将自动加上deleted_at IS NULL的条件

联表查询的场景

如果关联查询的几个表都启用了软删除特性时,会发生以下这种情况,即条件语句中会增加所有相关表的软删除时间判断。

// SELECT * FROM `user` AS `u` LEFT JOIN `user_detail` AS `ud` ON (ud.uid=u.uid) WHERE u.uid=10 AND `u`.`deleted_at` IS NULL AND `ud`.`deleteat` IS NULL LIMIT 1
g.Model("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid").Where("u.uid", 10).One()

Unscoped忽略时间特性

Unscoped​用于在链式操作中忽略自动时间更新特性,例如上面的示例,加上Unscoped方法后:

// SELECT * FROM `user` WHERE uid>1
g.Model("user").Unscoped().Where("uid>?", 1).All()

// SELECT * FROM `user` AS `u` LEFT JOIN `user_detail` AS `ud` ON (ud.uid=u.uid) WHERE u.uid=10 LIMIT 1
g.Model("user", "u").LeftJoin("user_detail", "ud", "ud.uid=u.uid").Where("u.uid", 10).Unscoped().One()

以上内容来源自官方文档:https://goframe.org/pages/viewpage.action?pageId=1114139

软删除和物理删除的区别

  • 软删除也叫标记删除,通过字段标记DB中的纪录是否被删除:

比如通过is_delete字段标记,默认为0,删除时设置为1

或者和视频内容一样,使用deleted_at字段标记删除的时间,默认为null

  • 物理删除,就是直接将DB中的记录删掉

如何优雅的实现软删除

如果你详细看完了ORM链式操作-时间维护这部分内容,想必心中一定有了答案。

结合商业项目需求,有哪些容易踩的坑?

一定要结合实际情况决定使用物理删除还是软删除,下面的例子抛转引玉:

1. 比如管理后台删除轮播图这种操作建议使用软删除。因为可能出现误操作的情况,软删除可以及时找回;而且轮播图的数据往往不多,冗余保存也是没有问题的。

2. 再比如用户移除收藏文章的记录,建议物理删除。原因是收藏文章,取消收藏这类操作比较随意,没有任何风险。再者这类数据量比较庞大,软删除没有意义,反而会增加收藏操作的逻辑压力和DB压力。

本文转载自微信公众号「 程序员升级打怪之旅」,作者「王中阳Go」,可以通过以下二维码关注。

5976b853988fdc4c423700dcd26300c87b979c.jpg

转载本文请联系「 程序员升级打怪之旅」公众号。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK