python 后端出身.
第一次写 go web. 然后照着网上的开源项目抄. 我觉得 controller service Model 三层还是可以的. 毕竟业务扔到 Service 里面逻辑更清晰一些.
然后和 Java 同事请教了一下. 令我困惑的是:
user_instance.check_passwork(request.Post['password'])
这样不行吗? 为什么一定要
1. get password from DB
2. checkpassword with request
DB.Where(map[string]interface{}{"user_id":666}).Count(&count)
这句话必须放在 DAO 层, 而不是直接在 Service 里写? 感觉好麻烦啊.
我的问题是:
谢谢
1
sutra 2021-09-09 14:19:22 +08:00
|
2
basefas 2021-09-09 14:28:16 +08:00
Go 没有严格的项目结构要求,严格来讲 Go 也不是面向对象语言,所以可以不完全按照 MVC 的架构来写。可以多看看其他的开源项目的写法。也可以看看我写的一个后台项目,以供参考。
https://github.com/basefas/admin-go |
3
usedname 2021-09-09 14:30:48 +08:00
只要你愿意, 你在 controller 里面写 SQL 也没有任何毛病
|
4
chendy 2021-09-09 14:37:00 +08:00 1
不懂 go 的 java 农表示:
项目简单的话,把所有逻辑放一个文件里也没事 项目复杂的话,分层可以降低理解难度,更容易维护 这套路哪来的我不知道,但是我觉得还挺合理的 有的时候一个不复杂的功能我也会老老实实分层,有时候一个很复杂的查询我会直接塞进 controller,具体情况具体分析吧 |
5
rickiey 2021-09-09 14:39:08 +08:00
你可把一个工程写进一个 main 文件也没事,想写那都可以,但是工程大了你就发现你把握不住了,前人根据经验把工程分层分类,就是为了避免这种情况的,当然你牛逼的话也可以尝试自己的结构
|
6
sy20030260 2021-09-09 14:40:54 +08:00 1
1. 考虑开闭原则,例如如果后续切换存储,要做到不修改上层的业务代码逻辑,分层是不是最简单直接的方式
2. Go 风格解构了很多传统面向对象方法论里的原则,但面向接口编程和开闭原则,Go 还是提倡的 3. 代码分层不是 Java 独有而是程序员们的经验沉淀,虽然不一定是最佳实践,但在大部分场景下稳定工作 |
7
cheng6563 2021-09-09 14:43:29 +08:00
Service 和 Model 可以看情况合并一起,但请务必与 controller 层分开。
|
8
abersheeran 2021-09-09 14:53:05 +08:00
Java 程序员写 Django 也会有 DAO 。我见过。纯粹是他们的个人习惯。
|
9
rimutuyuan 2021-09-09 14:55:53 +08:00 9
我的 go 项目目录都是和 open bilibili 学的
|
10
soupu626 2021-09-09 14:59:34 +08:00 5
面向接口,功能单一独立,dao 只提供数据查询的能力,不吃任何逻辑
如果不要 service 比如在 dao 里吃了密码校验的逻辑,那如果是加盐的密码,这个加盐过程要不要 dao 吃,如果前端传递过来也是有加密的,这个加密过程要不要 dao 吃,界限很难判定 如果不要 dao,数据查询逻辑和业务逻辑混杂,也不便维护 查询一个用户是否存在,现在判定下 userId 在数据库里有没有记录就行,如果某个场景要求 lv11 以上会员可参与,某个场景要求女性专场,某个场景要求未成年禁入,这种情况下,难道在 service 里写一坨一坨的 sql 么,dao 提供一个通用的用户查询接口,给一个查询参数对象,各个场景根据需要设置不同参数就行。就算现在能忍受数据查询和业务逻辑杂,要是下一步,要求用户中心独立,数据库查询要变成外调其他服务,这一堆堆的 sql 改起来可太费劲了。 这些工程实践,都是被真实业务场景锤出来的,工程上好维护的代码才是好代码,没有维护性的代码都是屎山 当然如果是个人项目,以上纯当放屁,怎么开心怎么来。 |
11
HelloWorld556 2021-09-09 15:01:43 +08:00 2
|
12
zhoudaiyu 2021-09-09 15:24:39 +08:00 via iPhone
@abersheeran 有 IxxxService 和 xxxServiceImpl 吗?
|
13
aliveyang 2021-09-09 15:35:24 +08:00 5
这个工程化的东西,跟语言无关吧
|
14
kxiaong 2021-09-09 15:36:57 +08:00 1
即使是 Django 项目,我也不太赞成 SQL 写在 service 层( views.py ).Django 的 Model 可以封装自己的 objects, 来定义通用的查询,基本等效于 java 的 DAO 。好处是对数据库的操作封闭,所有上层业务通过统一的接口修改数据。
多人协作的 Django 项目中,没法确定别人写的 service 中有没有 SQL 修改或影响到你要操作的数据。出问题不好定位。 |
15
PDX 2021-09-09 15:41:07 +08:00
这个应该和语言无关的吧,分层设计也是经过大量实践总结才定制出来的。
你觉得怎么舒服就怎么写,后期也是要不断优化重构的,说不定最后你自己会设计出一套层次结构呢。 |
16
wfd0807 2021-09-09 15:59:38 +08:00
dao 层的存在是封装持久层,隔离业务逻辑与存储对象,比如说从 MYSQL 切换到 PostgreSQL 可以不影响业务逻辑
service 层是 spring 项目早起设计出来的,实际作用是配合切面实现事务控制,你可以把 service 层理解成事务脚本 至于你的项目需要不需要,根据以上两点自行考虑 |
17
Jooooooooo 2021-09-09 16:01:37 +08:00
分层还真的和语言无关.
分层想解决的问题也是独立于语言的. |
18
Macv1994 2021-09-09 16:04:18 +08:00
个人习惯吧
|
19
chaleaoch OP @soupu626 #10
如果某个场景要求 lv11 以上会员可参与,某个场景要求女性专场,某个场景要求未成年禁入,这种情况下,难道在 service 里写一坨一坨的 sql 么,dao 提供一个通用的用户查询接口,给一个查询参数对象,各个场景根据需要设置不同参数就行。 =================== 谢谢, 再次基础上 我们把业务更加的复杂化. 有时候我们需要 lv11 + 有孩子的女性. 是否有孩子 是从另一张关联表读取并且他们之间没有数据库层面的外键关系. 像这样的场景是不是就应该把方法放到 Service 里面而不是 DAO 里了? 所以想请教, DAO 里面可以带业务吗? |
21
hihanley 2021-09-09 18:06:38 +08:00
@rimutuyuan 我也想学习一下,兄弟有地址吗
|
22
libook 2021-09-09 18:28:56 +08:00
这个问题不应该是 XX 语言要不要写 DAO,而是当前的项目情况上来评估加一层 DAO 是否有收益。
Java 的开发者群体是极其庞大的,也同时是良莠不齐的,很多水平不高的 Java 工程师习惯在各种项目上套用相同的架构,真正的架构师回去评估系统特点以及架构设计上的收益和成本。 架构上的思想都是工具,能在特定场景解决特定问题,所以不管用什么语言、框架,只要觉得某个架构思想适合用来解决问题,就可以拿来用。但同时,工具不是用来制造问题的,所以如果用起来会徒增成本,那么就没必要硬上。 |
23
soupu626 2021-09-09 20:03:26 +08:00 1
@chaleaoch DAO 不带业务,就是对单表的数据查询访问,如果想要一个数据层的简单业务封装,比如逻辑删除、不可见订单的过滤,多表的数据查询聚合,我们组的做法是,会抽一层 manager 出来,如果是专职数据访问的 manager,有时候会命名为 DAC
service 之下 dao 之上再区分一层 manager 出来,在有些情况下可以提高内聚性,还是具体问题具体分析,当然如果有公司或者组内规约,还是按规约来,不然也许哪天被人在注释里一顿狂喷。。。 |
24
zjsxwc 2021-09-09 20:16:20 +08:00 via Android 2
写 java 时会有 dao 层我个人认为是受了 mybatis 的影响,用了 mybatis 那些 xml 或者 注解 非原生代码 方案的,你是不得不用 dao 层,君不见 springboot 的 jpa 方案就没有 dao 而是用了 repository 模式, 因为 repository 是原生代码实现所以甚至可以在 repository 里注入别的业务对象,而 dao 的 xml 或者注解都只是文本字符串,根本不能注入原生语言的对象,于是迫不得已,只能在套个 dao 对象来搞良。
题外话,绝大部分项目没有切换数据库如 mysql 换 pg 的需求, 有很小很小部分项目有换 orm 轮子的需求,比如 beego 自带的 orm 换 gorm 。 |
25
sanyuedev 2021-09-09 20:31:58 +08:00
个人觉得 DAO 可以去掉
|
26
wangbenjun5 2021-09-09 20:36:16 +08:00
一般 controller 、service 、model 3 层,model 就是 db 层,负责和数据库交互,这个少不了。
service 层的话,其实很多简单的业务确实多余,用不上,硬是搞这一层闲的繁琐,其实可以去掉! |
28
sujin190 2021-09-09 20:54:33 +08:00
java 感觉逻辑就是,分层、结构、解耦、扩展好维护,要考虑流量上来了团队壮大了如何如何,结果现实情况加班加点做完每三个月项目黄了,其实光是上半年就倒闭了数十万家公司,能做起来的少之又少,想这么多都是有的没的,特别是 mybatis 这一套,小公司使用场景来看设计的简直神经病一样的,所以依据自己现实和工程方法,选择合适的方案就可以了,没必要硬套这些东西
|
29
yrj 2021-09-09 21:53:01 +08:00 via iPad 1
我的方式,直接 gorm 写 service 里,不用 dao 。
|
30
zand 2021-09-09 22:04:36 +08:00
@kxiaong 赞同,python 不背这个锅,使用 Django 的项目也应该有良好的分层,一味求简单只是给后来人挖坑。
比如需要分库分表时,满山遍野的 objects 真的让人崩溃。 |
31
fiypig 2021-09-09 22:35:08 +08:00 via iPhone
分控制层跟模型层
|
34
forbreak 2021-09-10 09:07:57 +08:00
分不分层是自己决定的,跟语言无关,跟工程化有关。实际项目你想咋写咋写,没有语言会限制你。
|
35
anonydmer 2021-09-10 09:19:32 +08:00
楼主先前 django 写那个密码验证没有写单元测试吧
|
36
jetyang 2021-09-10 09:31:32 +08:00
楼主说到 java web 程序员的痛处了
|
37
anonydmer 2021-09-10 09:32:35 +08:00 3
忍不住想说两句
1. DAO 是个很古老的东西,不是伴随 mybatis,hibernete 这些产生的;事实上,早在 EJB 时代就有它了 2. DAO 全称是 Data Access Object, 不是 Database Access Object ;所以把它狭隘的理解成适配多个数据库是不好的;事实上,这一层可以从数据库获取数据,也可以从文件系统获取数据,还可以从网络远程获取数据; 3. 除了适配不同持久层之外,DAO 还有个重要的作用的是做持久化数据和模型直接的转换,比如存储字段和模型字段的差异,一些特殊格式的处理;这也是在实际工作中经常需要用到的 至于用不用 DAO 或者类似 Repository 这一层,如果说项目只需要考虑一个数据库,没有任何模型和存储的格式差异,很多人选择不要这一层;不过咱们可以不用,但是得知道为什么不需要用。 不过我相信没用这一层的同学,大多数业务层代码肯定没有写单元测试吧。 |
38
basefas 2021-09-10 09:42:49 +08:00
@hihanley #20 对的,所以项目中,internal 包是全局可以访问的,但是当别人 import 你的项目时,就不能调用 internal 中的方法,如果你不在意这些,就完全可以不用这个命名,起个你喜欢的名字
|
39
cslive 2021-09-10 09:49:35 +08:00
工程规范而已,java 你可以直接在 jsp 里写,全部业务逻辑,sql,html,js 都在 jsp 里写,这样我估计你自己也不想看
|
40
ElmerZhang 2021-09-10 10:23:45 +08:00
项目小了怎么写都行,项目大了要找适合这个项目的写法。写 web 服务或者 api 服务,controller service Model 三层结构的适用性是最广的,但并不一定适用于你的项目。
先写吧,写着写着可能就会发现怎样怎样写更好一些,然后再重构呗。 我个人经验经验是这样的:某个 model 自身有些特定逻辑,并且在多个 service 中都会用到,那么可能需要抽出一个 dao 层来做。 另外如果针对 model 有缓存的话,service 和 model 之间可能也要加一层,叫 manager 之类的。 简单来说,当你在同一层的多个文件中经常 copy&paste 代码的时候,就要考虑提出一层或者提个 util 出来了。 |
41
ytll21 2021-09-10 10:54:59 +08:00 1
说明楼主平时不怎么写单元测试,或者在单元测试里,是把业务逻辑和持久逻辑放在一块做测试的。
|
42
onion83 2021-09-10 11:27:16 +08:00
杠精:微服务我来了!一个表一个 RPC 服务,再加一个数据组装层,完美!
|
43
zjsxwc 2021-09-10 12:08:36 +08:00
@anonydmer 2 小时 28 分钟前
基于历史缘故,我明白你的意思, 但 DAO 如果还是定义成 Data Access Object 这个理解, 那么 service 和 DAO 有什么区别呢, 只要是返回数据 Data 的对象都可以被称为 DAO, 很少存在业务代码不使用数据的, 那么按照这个理解一切皆 DAO ! 我也见过,在一个 foo DAO 通过多个不同 RPC 调用别的 service 对象,这些 service 对象再通过自己的 DAO 获取数据,foo DAO 再组装这些 rpc 数据返回的合成一个数据,这时候这个 foo DAO 如果按你的理解当然可以被称为 DAO,但我更愿意称呼他为 service 。 |
44
zjsxwc 2021-09-10 12:11:10 +08:00
最后 DAO 就被滥用成 现在这种局面,什么都能往 DAO 里套,
DAO 就是神,祂无所不能! |
45
leoskey 2021-09-10 12:15:03 +08:00
分层是为了提供系统可维护性。DAO 并不是为了可迁移到另一数据库而存在,而是在于让 Service 层更关注业务逻辑,无需关注 DAO 等底层。
|
46
brucedone 2021-09-10 12:54:02 +08:00
以前用 echo 或者 gin 的时候,常规的就三层,能 hold 的住小项目向中项目演变,后来用了 goframe,能 hold 的住小,中,大的项目需求,是否需要 dao,我感觉更多的是看需求增长量级,再好的项目架构,也没有办法适应海量的需求变化
|
47
jsuly 2021-09-10 13:12:12 +08:00
可以不考虑分层, 分模块
|
48
cassyfar 2021-09-13 04:36:33 +08:00
@zjsxwc
DAO 是去调用持久数据的,就是你服务器挂了,这些数据也会在。比如存在数据库里,存在本地磁盘文件里或者其他地方的数据。我个人理解 DAO 只是将你自己系统处理数据的逻辑,和如何存储这些数据的逻辑分离开( decouple )。这样比如你升级更换迁移数据的持久方案,也不会影响到你本身的服务。 |
49
HHAO2019 2021-09-14 09:01:22 +08:00 1
controller->service->manager->mapper 我这边项目是这样的 Java
|
50
chaleaochexist 2022-04-13 09:51:02 +08:00
|
51
chaleaochexist 2022-04-13 09:54:02 +08:00
@soupu626 #10 django 的加盐操作还真就是 model 也就是 dao 做的。
https://github.com/django/django/blob/1bb9bd972424771246022bcf2c61e0eb87a0f337/django/contrib/auth/models.py#L154 |
52
chaleaochexist 2022-04-13 09:55:33 +08:00
@wfd0807 #16 大佬,我其实也一直在查这个三层架构是从哪里来的。
“service 层是 spring 项目早起设计出来的” 这个有出处吗? |
53
chaleaochexist 2022-04-13 10:03:06 +08:00
@anonydmer #37 你说的这三点 django 中的 model 都能实现。
不过 django 中的 model 的功能 会更多一些, 譬如可能带一些 业务。 这又和 DAO 不一样了。 譬如 获取一个用户的多个 Role 这样的操作在 Java 里面 一般都在 service 里写。但是在 django 中可能就是一个 model 的方法了。 |
54
chaleaochexist 277 天前
@zjsxwc 时隔数年在看自己的问题. 有了新的理解.
大佬请教一下 repository 和 DAO 有什么区别? 我怎么感觉都差不多呢? 除了 1. 面向领域和面向数据. 2. entity 可以带方法. 能举个例子吗? |
55
chaleaochexist 277 天前
@abersheeran java 写 DAO 怎么写?
DAO 绑定一个 Model? |
56
chaleaochexist 277 天前
@soupu626 时隔多年又回到这个问题.
你说的我有一点点理解. 但是如果是 django 来作的话, 有一点点类似于 java 中的 entity/pojo 拥有一个方法去查询数据库. User user = new User() user.checkpasswd() 这样子. |
57
chaleaochexist 277 天前
@kxiaong
"Django 的 Model 可以封装自己的 objects, 来定义通用的查询,基本等效于 java 的 DAO" 只能说基本等效, 就像其他楼说的, 如果涉及到 Redis 操作或者其他 RPC 操作, 如果自己封装一层 DAO 更清晰. 还有就是换 ORM 的时候, 如果自己封装了一层 DAO, 那么 service 层真的一点都不用动. 但是如果 django orm --> 换别的 ORM. service 层要改动的地方还是挺多的. 说白了 还是面向接口编程 "多人协作的 Django 项目中,没法确定别人写的 service 中有没有 SQL 修改或影响到你要操作的数据。出问题不好定位" 即使是使用 DAO 也无法定位有没有 SQL 修改影响你的操作啊. 譬如 user 和 permission 两张表. 我在 UserDao 中是否可以处理 Permission 这张表呢? 譬如删除 User 同时删除 Permission 这个动作是在 Service 里调用 PermissionDao 还是在 UserDAO 中直接把 permission 直接删除了? 这个有规范吗? 补充, 我是楼主, 感谢大佬的原始回复. 期待您新的回复. |