当前位置: 首页 > 科技观察

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

时间:2023-03-15 22:57:52 科技观察

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方法执行时自动写入,之后保持不变。//插入`user`(`name`,`created_at`,`updated_at`)VALUES('john',`2020-06-0621:00:00`,`2020-06-0621:00:00`)g.Model("user").Data(g.Map{"name":"john"}).Insert()//INSERTIGNOREINTO`user`(`uid`,`name`,`created_at`,`updated_at`)VALUES(10000,'john',`2020-06-0621:00:00`,`2020-06-0621:00:00`)g.Model("user").Data(g.Map{"uid":10000,"name":"john"}).InsertIgnore()//替换为`user`(`uid`,`name`,`created_at`,`updated_at`)VALUES(10000,'john',`2020-06-0621:00:00`,`2020-06-0621:00:00`)g.Model("user").Data(g.Map{"uid":10000,"name":"john"}).Replace()//插入`user`(`uid`,`name`,`created_at`,`updated_at`)VALUES(10001,'john',`2020-06-0621:00:00`,`2020-06-0621:00:00`)重复键更新`uid`=VALUES(`uid`),`name`=VALUES(`name`),`updated_at`=VALUES(`updated_at`)g.Model("user").Data(g.Map{"uid":10001,"name":"john"}).Save()需要注意的是,替换方法也是这个字段会被更新,因为这个操作相当于删除了the现有的旧数据和改写一段数据。updated_at执行Insert/InsertIgnore/BatchInsert/BatchInsertIgnore方法时自动写入更新时间,执行Save/Update时更新时间(注意updated_at时间会在写入数据时更新存在,不更新created_at时间)。//UPDATE`user`SET`name`='johnguo',`updated_at`='2020-06-0621:00:00'WHEREname='john'g.Model("user").Data(g.Map{"name":"johnguo"}).Where("name","john").Update()//UPDATE`user`SET`status`=1,`updated_at`='2020-06-0621:00:00'ORDERBY`login_time`ascLIMIT10g.Model("user").Data("status",1).Order("login_timeasc").Limit(10).Update()//INSERTINTO`user`(`id`,`name`,`update_at`)VALUES(1,'johnguo','2020-12-2920:16:14')ONDUPLICATEKEYUPDATE`id`=VALUES(`id`),`name`=VALUES(`name`),`update_at`=VALUES(`update_at`)g.Model("user").Data(g.Map{"id":1,"name":"johnguo"}).Save()需要注意的是,Replace方法也会更新这个字段,因为这个操作相当于删除已有的旧数据,重写一段数据。deleted_at数据软删除软删除稍微复杂一点。当存在软删除时,所有的查询语句都会自动加上deleted_at条件。//UPDATE`user`SET`deleted_at`='2020-06-0621:00:00'WHEREuid=10g.Model("user").Where("uid",10).Delete()query一些变化会出现,例如://SELECT*FROM`user`WHEREuid>1AND`deleted_at`ISNULLg.Model("user").Where("uid>?",1).All()时可以看到deleted_at字段存在于数据表中,所有涉及该表的查询操作都会自动添加deleted_atISNULL条件连接表查询场景。如果在关联查询中对多个表启用了软删除功能,会发生以下情况,条件语句会增加对所有相关表的软删除时间判断。//SELECT*FROM`user`AS`u`LEFTJOIN`user_detail`AS`ud`ON(ud.uid=u.uid)WHEREu.uid=10AND`u`.`deleted_at`ISNULLAND`ud`.`deleteat`是NULLLIMIT1g.Model("user","u").LeftJoin("user_detail","ud","ud.uid=u.uid").Where("u.uid",10).One()UnscopedignoresthetimefeatureUnscoped用于忽略链式操作中的时间自动更新特性,如上例,添加Unscoped方法后://SELECT*FROM`user`WHEREuid>1g。Model("user").Unscoped().Where("uid>?",1).All()//SELECT*FROM`user`AS`u`LEFTJOIN`user_detail`AS`ud`ON(ud.uid=u.uid)WHEREu.uid=10LIMIT1g.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软删除和物理删除的区别Soft删除也叫标记删除,通过字段标记DB中的记录是否被删除:例如le,通过is_delete字段进行标记,默认为0,删除时设置为1,或者使用deleted_at字段标记删除时间,默认为null物理删除,即直接删除如何优雅的实现软删除删除DB中的记录如果你详细看过ORM链运行时维护,你心里一定有答案。结合商业项目的需求,有哪些容易踩的坑?需要根据实际情况决定是使用物理删除还是软删除。下面的例子比较有用:1、比如在管理后台删除轮播图等操作,建议使用软删除。因为有误操作的可能,软删除可以及时找回;而且轮播中的数据往往不多,所以冗余存储没有问题。2、又如用户删除收藏文章的记录,建议物理删除。原因是保存文章、取消收藏等操作比较随意,没有任何风险。另外这类数据量比较大,软删除没有意义,反而会增加采集操作的逻辑压力和DB压力。本文转载自微信公众号《程序员的升级打怪之旅》,作者“王中阳围棋”,可通过以下二维码关注。转载本文请联系《程序员升级打怪之旅》公众号。