如何优雅的处理 Tag 的 CRUD

2017-10-04 09:36:17 +08:00
 cevincheung

如 Blog 的 Tag、帖子的 Tag 等多对多的存储关系。

新增的时候

# 看看哪些存在?
tags = Tags.query.filter(Tags.tag_name.in_(('tag1','tagN'))).all()
# 不存在的入库?
# 存在的更新 relation ?

修改 Blog/帖子的时候再原样处理一次?

还有更加优雅的处理方法吗?

3615 次点击
所在节点    MySQL
6 条回复
hwding
2017-10-04 10:05:01 +08:00
我也是这样的,首先处理 Tags,再保存 Blog。

当然你需要一个 mapper 表来保存对应关系。

只新建没有的 Tags。

public List<Tag> saveWithMetas(String[] metas) {
List<Tag> tags = Arrays.asList(metas)
.parallelStream()
.map(name -> {
Tag thisTag = findTagByName(name);
return thisTag == null ? new Tag().setName(name) : thisTag;
})
.distinct()
.collect(Collectors.toList());
return tagRepository.save(tags);
}

目前没看到更好的方案,而且多对多有一个遗孤(Orphan)的问题,不能自动清除掉没用的 Tags...
Sight4
2017-10-04 10:10:16 +08:00
1. 部分 rmdbs/nosql 提供 insert...update...语句,例如 mysql 的 insert..on duplicate key update 或者 postgresql 的 insert...on conflict update 都支持类似的方案,插入时重复时更新或者忽略
2. 触发器或者存储过程解决
cevincheung
2017-10-04 10:10:19 +08:00
@hwding #1
有个中间表还好,每次编辑都直接删掉当前对象的所有关联然后重建。
cevincheung
2017-10-04 10:12:58 +08:00
@Sight4 #2 触发器存储过程会不会在后端数据库集群多 Master 情况下有问题。
Sight4
2017-10-04 10:30:20 +08:00
@cevincheung 这个要看你多 master 的配置方式,比如说主动-被动模式下的双主不存在这个问题,这种模式下其实就相当于热备,如果是主动-主动模式的就会出现问题了,同时允许多个 master 写入是件很高风险的事情
qiukun
2017-10-04 12:05:02 +08:00
API 纯 rest 的话是一系列 update 操作,不过也可以抽象一个 tags 资源,blog/id/tags update 即可。
实际实现,不考虑性能就是多对多,中间表。
考虑性能中间肯定顶一层 cache 了,读取全走 cache,写 db 的话异步写,这里有一致性的问题,如果用 redis 的话,就没有,建议用 redis,tag#{blog_id} -> set blog#{tag_id} -> set。
其实不考虑性能也用 redis 吧,每次改 blog 的 tags 你都不知道用户是不是改过原有的 tags,都是要走中间表查一次,虽然说写起来也无非就是 blog.tags.destory blog.tags.insert (这种操作看贵 ORM 了。。)

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/395362

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX