以下的示例中,我们默认示例中的数据表均包含了created_atupdated_atdeleted_at这3个字段,并且字段类型为datetime

示例SQL

这是后续示例代码中用到的MySQL表结构。

  1. CREATE TABLE `user` (
  2. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  3. `name` varchar(45) NOT NULL,
  4. `status` tinyint DEFAULT 0,
  5. `created_at` datetime DEFAULT NULL,
  6. `updated_at` datetime DEFAULT NULL,
  7. `deleted_at` datetime DEFAULT NULL,
  8. PRIMARY KEY (`id`)
  9. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
  10. CREATE TABLE IF NOT EXISTS `user_detail` (
  11. `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
  12. `address` varchar(45) NOT NULL,
  13. PRIMARY KEY (`id`)
  14. ) ENGINE=InnoDB DEFAULT CHARSET=utf8;

时间维护-基本使用 - 图1提示

  • 如果您选择使用时间字段类型,那么您需要将该字段设置为允许为NULL,这样软删除才能起作用。
  • 如果您尝试测试查看ORM操作执行的SQL语句,建议您打开debug模式(相关文档:调试模式),SQL语句将会自动打印到日志输出。

created_at 写入时间

在执行 Insert/InsertIgnore/BatchInsert/BatchInsertIgnore 方法时自动写入该时间,随后的更新/删除操作不会引起created_at字段内容的改变。

时间维护-基本使用 - 图2注意

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

  1. // INSERT INTO `user`(`name`,`created_at`,`updated_at`) VALUES('john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`)
  2. g.Model("user").Data(g.Map{"name": "john"}).Insert()
  3. // INSERT IGNORE INTO `user`(`id`,`name`,`created_at`,`updated_at`) VALUES(10000,'john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`)
  4. g.Model("user").Data(g.Map{"id": 10000, "name": "john"}).InsertIgnore()
  5. // REPLACE INTO `user`(`id`,`name`,`created_at`,`updated_at`) VALUES(10000,'john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`)
  6. g.Model("user").Data(g.Map{"id": 10000, "name": "john"}).Replace()
  7. // INSERT INTO `user`(`id`,`name`,`created_at`,`updated_at`) VALUES(10001,'john', `2020-06-06 21:00:00`, `2020-06-06 21:00:00`) ON DUPLICATE KEY UPDATE `id`=VALUES(`id`),`name`=VALUES(`name`),`updated_at`=VALUES(`updated_at`)
  8. g.Model("user").Data(g.Map{"id": 10001, "name": "john"}).Save()

deleted_at 数据软删除

当软删除存在时(即deleted_at字段存在时),所有的查询语句都将会自动加上 deleted_at 的条件。

  1. // UPDATE `user` SET `deleted_at`='2020-06-06 21:00:00' WHERE id=10 AND `deleted_at` IS NULL
  2. g.Model("user").Where("id", 10).Delete()

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

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

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

updated_at 更新时间

在执行 Save/Update 方法时自动写入该时间。

时间维护-基本使用 - 图3注意

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

  1. // UPDATE `user` SET `name`='john guo',`updated_at`='2020-06-06 21:00:00' WHERE name='john' AND `deleted_at` IS NULL
  2. g.Model("user").Data(g.Map{"name" : "john guo"}).Where("name", "john").Update()
  3. // UPDATE `user` SET `status`=1,`updated_at`='2020-06-06 21:00:00' WHERE `deleted_at` IS NULL ORDER BY `id` ASC LIMIT 10
  4. g.Model("user").Data("status", 1).OrderAsc("id").Limit(10).Update()
  5. // 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`)
  6. g.Model("user").Data(g.Map{"id": 1, "name": "john guo"}).Save()

联表查询的场景

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

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

Unscoped 忽略时间特性

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

  1. // SELECT * FROM `user` WHERE id>1
  2. g.Model("user").Unscoped().Where("id>?", 1).All()
  3. // SELECT * FROM `user` AS `u` LEFT JOIN `user_detail` AS `ud` ON (ud.id=u.id) WHERE u.id=10 LIMIT 1
  4. g.Model("user", "u").LeftJoin("user_detail", "ud", "ud.id=u.id").Where("u.id", 10).Unscoped().One()