• 【Go电商实战03】如何使用ORM链式操作?如何优雅的实现软删除?


    我会把Go语言中的知识点结合商业项目,让大家理论联系实践,融会贯通。

    上期回顾

    上一篇内容分享了【Go电商实战02】如何借助工具快速生成代码?新手容易踩的这些坑一定要避开。

    如果你第一次看我【电商实战】系列的文章,建议先看【Go电商实战01】先看这里:适合人群&课程大纲&开源地址&视频合集&一起学习

    看过的朋友请忽略,继续往下看:

    本期重点

    用到的知识点包括:

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

    本期内容除了在CSDN发布文章,也在B站发布了视频版。欢迎大家三连关注一波# 【B站视频教程-电商实战03】链式操作_软删除_优雅的时间管理_删除轮播图

    下面重点介绍一下ORM链式操作-时间维护的知识点,看完这部分再看视频效果更好。

    ORM链式操作-时间维护

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

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

    • 字段应当设置允许值为null

    • 字段的类型必须为时间类型,如:date, datetime, timestamp。不支持数字类型字段,如int

    • 字段的名称不支持自定义设置,并且固定名称约定为:

      • created_at用于记录创建时更新,仅会写入一次。
      • updated_at用于记录修改时更新,每次记录变更时更新。
      • deleted_at用于记录的软删除特性,只有当记录删除时会写入一次。

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

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

    特性的启用

    当数据表包含created_atupdated_atdeleted_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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    需要注意的是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()
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    需要注意的是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()
    
    • 1
    • 2

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

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

    可以看到当数据表中存在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()
    
    • 1
    • 2

    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()
    
    • 1
    • 2
    • 3
    • 4
    • 5

    软删除和物理删除的区别

    1. 软删除也叫标记删除,通过字段标记纪录是否被删除:
    • 比如通过is_delete字段标记,默认为0,删除时设置为1
    • 或者和视频内容一样,使用deleted_at字段纪录删除的时间,默认为null
    1. 物理删除,就是直接将DB中的记录删掉

    如何优雅的实现软删除

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

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

    1. 结合实际情况决定使用物理删除还是软删除
    2. 比如管理后台删除轮播图这种操作建议使用软删除。因为可能出现误操作的情况,软删除可以及时找回;而且轮播图的数据往往不多,冗余保存也是没有问题的。
    3. 再比如用户移除收藏文章的记录,建议物理删除。原因是收藏文章,取消收藏这类操作比较随意,没有任何风险。再者这类数据量比较庞大,软删除没有意义,反而会增加收藏操作的逻辑压力和DB压力。

    一起学习

    欢迎使用CSDN的私信功能联系我,或者关注下方的公众号联系我。

  • 相关阅读:
    基于ssm零食商城管理系统(maven版本)
    three.js纹理贴图褪色失真问题解决
    Allegro基本规则设置指导书
    经典算法试题(一)
    第18章linux系统-备份与恢复
    VS Code 在线运行:code-server部署(系列一)
    强大博客搭建全过程(1)-hexo博客搭建保姆级教程
    CAD进阶练习(四)
    tomcat乱码解决
    clockid_to_kclock
  • 原文地址:https://blog.csdn.net/w425772719/article/details/127843099