[习作] SpringBoot + MyBatis 实现的预排序遍历树算法无限级分类 ...

2019-12-16 20:55:25 +08:00
 Sunyanzi
最近一阵子我都在自己写 Java 玩 ... 也没人带 ... 就面向 Google 编程一点一点摸索 ... 还挺乐在其中的 ...

昨天写到一个无限级分类想用左右值法 ... 结果居然搜了一整天都没找到现成的轮子 ... 这就很奇怪 ...

在 php 领域 Modified Preorder Tree Traversal Algorithm 的实现满街都是 ... Java 领域居然一个没有 ...

我能找到的范围里大家都在用 parent_id 递归 ... 我不是很懂 ... 是 Java 有什么黑科技优化这种大量的递归查询吗 ..?

也罢了 ... 既然找不到只好自己写 ... 反正也不难 ...

刚才写完一寻思 ... 我这样一直闭门造车也不是个事儿 ... 只能停留在实现 ... 实现方式是对是错也没人能指导 ...

新写的这个东西第一 CURD 都占了 ... 第二是我真的没找到类似的东西 ... 第三我对 Java 的方式和思想确实不是很熟 ...

正好借这个契机放代码来求个 Code Review ... 主要是想知道以我这样的方式写一个 Java 的 Web 项目是否是正确的 ...

我没写任何基础算法之外的东西 ... 比如 parent_id 或者 depth 的组合一类的 ... 就是一个纯粹的 MPTT 算法 ...

[ github.com/qex/Springboot-MPTTA ] ... 代码量很小 ... 望占用您些许时间斧正一二 ...
4912 次点击
所在节点    分享创造
28 条回复
huijiewei
2019-12-16 21:28:45 +08:00
直接取出所有记录根据 parentId 生成树放缓存就是了

https://github.com/huijiewei/agile-boot

里面的 agile-core-shop ShopCategory 就是个树
Sunyanzi
2019-12-16 23:59:34 +08:00
@huijiewei 感谢回复 ... 我也读了一下代码 ...

我大概理解的意思是 ... 因为在 Spring 里有 Cacheable 与 CacheEvict 的存在 ...

所以 SQL 其实可以随便写 ... 优化算法并不是很重要 ... 因为只有第一次才连库之后就走缓存了 ...

以及我顺带一问因为看您在用 JPA 操作数据库 ... 选择用 JPA 而不是别的方式的理由是 ..?
gz911122
2019-12-17 00:00:40 +08:00
怎么一搜"无限级分类"出来的都是 php 的...
gz911122
2019-12-17 00:05:11 +08:00
看了一下大致明白了,但是我这搬砖这几年从来没用到过这个啊?
是在 php 上会很常用么?使用场景是什么啊?
secondwtq
2019-12-17 00:23:35 +08:00
这个中文名字里面的”预排序“是翻译夹的私货么
inhzus
2019-12-17 01:59:39 +08:00
(都是英文省略号看得真心有些心累
arYUWang
2019-12-17 02:41:49 +08:00
Preorder Traversal 应该是前序遍历把。。
Cbdy
2019-12-17 08:00:49 +08:00
接口首字母 I,你以前是写 C#的吗?
Sunyanzi
2019-12-17 08:53:52 +08:00
@gz911122 我也很意外... Java 关于无限级分类的资料就很少 ... 我能找到的都是用 parent_id 的 ...

以及我没明白「常用」是对什么而言的 ... 是无限级分类是否常用 ... 还是这个左右值实现是否常用 ..?

@secondwtq @eugenewangfw 讲道理这个算法的中文名应该叫「改进的前序树遍历算法」 ...

但我用 MPTT 作为关键字搜百度的时候 ... 得到的中文资料都翻译为「预排序遍历树」 ... 我就 ... 随大流了 ...
Sunyanzi
2019-12-17 09:01:29 +08:00
@Cbdy 我认真想了一下 ... 大概是个不知道什么时候养成的习惯 ... 也不知道是好是坏 ...

Service 层我一般有两种写法 ... 一种是直接一个类搞定不区分接口和实现 ... 那样直接就叫 ooService ...

另一种就是例子这样 ... 对外写接口 ... Impl 只对内 ... 这时候就区分 IooService 和 ooServiceImpl 了 ...

我也不知道这样是不是对的 ... 还是说 Java 并不推荐在接口名字里标记当前对象是个接口 ..?
huijiewei
2019-12-17 09:06:46 +08:00
@Sunyanzi jpa 是 Spring 的默认解决方案
nobt
2019-12-17 09:12:22 +08:00
@Sunyanzi 其实大概是看你使用什么代理,比如默认使用接口+实现类模式的 CGLIB 代理,那这样的话就不必对接口名特殊标记了,比如 package.user.service 下面放的是接口 UserService 就是接口,package.user.service.impl 下面放的是实现类 UserServiceImpl

如果使用的 JDK 动态代理就不采用接口+实现类了了,也就是不需要写接口,注入的是实现类,原理是注入了个子类吧
gz911122
2019-12-17 09:38:09 +08:00
@Sunyanzi #9 无限级分类是否常用
Cbdy
2019-12-17 09:45:14 +08:00
@Sunyanzi 为什么不参考一下 JDK 是怎么写的呢?
glaucus
2019-12-17 09:48:58 +08:00
@Sunyanzi #10 我以为薛之谦搞 IT 了
Sunyanzi
2019-12-17 10:09:15 +08:00
@huijiewei 那那 ... 那我有个关于 JPA 的问题 ... 因为我也是用了好久的 JPA 才接触的 MyBatis ...

在使用 JPA 的时候 ... 是推荐能用 JPQL 完成的内容不使用 nativeQuery 还是反之 ..? 或者只是随个人喜好 ..?

以及 ... 在 JPA 里面所有 Modifying 操作都要标 Transactional ... 不管用不用得到事务都需要标 ...

想要优化掉这个在我知道的范围里就只能引 EntityManager ... 这样是正确的做法吗 ..?

@nobt 以我现在的水平 ... 还完全读不懂这段话 ... 我唯一用过 CGLIB 的地方就是个 Bean Map 转换 ...

以及代理的话 ... 我知道 Spring 的代理对象 ... 但也仅限于知道而已 ... 我如何能知道我用的是 ... 什么代理 ..?
Sunyanzi
2019-12-17 10:19:01 +08:00
@gz911122 无限级分类超常用 ... 基本上需求里涉及「要个分类」就等同于「要做个无限级分类」 ...

如果之前从没用到过这个的话 ... 那比如有需求说做个文章管理 ... 要能够添加总分类和子分类 ...

就类似于目录的感觉 ... 层级递进可以很深 ... 这样的需求你会如何做 ..?
huijiewei
2019-12-17 10:39:16 +08:00
@Sunyanzi 尽量少手写 SQL 语句就是了。你看我的项目里面,基本除了批量操作,都没有手写 SQL 语句的
gz911122
2019-12-17 11:28:07 +08:00
@Sunyanzi #17 了解了,没做过这种层级很深的分类,做的都是层级固定的... :P
不过感觉这种用 mysql 这种存储怪怪的... 无限追溯 pid 效率感觉不怎么好啊.

不过工作这 4,5 年还真没做过这种无限极分类的需求,挺有意思的
nobt
2019-12-17 11:38:08 +08:00
@Sunyanzi
你先定义一个接口,然后用实现类实现具体逻辑
public class CategoryServiceImpl implements ICategoryService

随后在 Controller 中这样写:
@Autowired
ICategoryService cSvc;

注入的是接口,而不是实现类 CategoryServiceImpl,故使用的是 CGLIB 代理

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

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

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

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

© 2021 V2EX