1
Leviathann 2021-07-31 09:37:50 +08:00
太多了
jooq jdbi querydsl kotlin 可以使用所有 java 生态然后还有官方的 exposed |
2
sagaxu 2021-07-31 09:37:57 +08:00 via Android
试试 jooq
|
3
br00k 2021-07-31 09:40:33 +08:00
我挺喜欢 querydsl,SQL 、MongoDB 都可以支持。
|
4
Cbdy 2021-07-31 09:45:34 +08:00 via Android
|
5
Cbdy 2021-07-31 09:48:38 +08:00 via Android
当然是 JDBCTemplate 啦,再精妙的 ORM,都不如直接写 SQL 清晰利落
|
6
Leviathann 2021-07-31 09:51:43 +08:00 via iPhone
@Cbdy 根据查询条件拼接 sql,要修改重构的话这种纯字符串的方案巨恶心
|
7
jones 2021-07-31 10:02:38 +08:00 2
jdbctemplate, 其他都是浮云, 代码就应该是代码的样子, jpa 会陷入 Annotation 地狱, mybatis 会陷入 XML 地狱
|
8
Cbdy 2021-07-31 10:05:56 +08:00 via Android
@Leviathann 不同的方案有不同的写法、劣势、优势,直接写字符串明了,虽然动态性差,但是在要动态性的场景可以通过多拆几个方法,或者换动态的 SQL Builder 解决
你这是要求一个完美的方法解决所有问题吗?很可惜软件开发没有银弹 |
9
chendy 2021-07-31 10:11:10 +08:00
jdbctemplate 遇到条件不定的 sql 就很头大了
|
10
alamaya 2021-07-31 10:14:47 +08:00 14
居然有吹直接写 sql 的,这是返祖现象吗?
|
11
notejava 2021-07-31 10:14:54 +08:00 1
习惯了使用 mybatis-plus,兼顾了单表操作和手写 sql 。
|
12
limbo0 2021-07-31 10:21:35 +08:00 1
mybatis-plus + 1 尽量不手写 sql, 维护太麻烦
|
13
bitmin 2021-07-31 10:48:01 +08:00 via Android
jdbctemplate 动态 sql 我的解决方案是先写完整 sql,自己写一个工具类检查入参空参数并删除 sql 中相应的语句。
在 idea 中 sql 都有代码提示,也可以格式化显示,代码中用多行字符串展示看起来很清晰。 |
14
abcbuzhiming 2021-07-31 10:48:16 +08:00 51
这本质是两种思想的碰撞,JPA 的思维是 ORM,mybatis 则来自“sqlUtils”(sql 帮助工具)。
在关系数据库群雄争霸的那个时代,SQL 标准没有统一,在编程界的当时有一个迫切的需求:如果我半途要换关系数据库怎么办?不像现在这个 MySQL“称霸世界”(并没有)的时代,当时做到一半换数据库是真的常见的需求。而当时 SQL 作为一种 4GL 语言其实思想并没有广泛的被人接受,当时的业界还是面向对象的天下。于是就有人说:为什么不能用面向对象来映射关系数据库的表呢?这就是 ORM(Object Relational Mapping,对象关系映射)最初的思想来源。也是最主要的两个 ORM 库,Hibernate 和.Net Entity Framework 的指导思想。 时间飞速前进,新世纪后发生了两个非常主要的变化: 第 1 个变化是,关系数据库面对海量的互联网数据开始变的力不从心,为了解决海量数据的问题(当时大数据还没有像现在这么发达),不得不妥协,把单库拆分成多库,这么一拆之后,关系数据库之前以强约束,关联关系计算为卖点的特性,不再是优势(拆分之后的库无法使用这些特性,只能搞什么最终一致,Base 理论之类的聊以自慰),这也是为啥 MySQL 这种在经典关系数据库理论看上去简直就是个残废的关系数据库大行其道的原因。同时,因为经典关系数据库的特性不再重要,关系数据库开始沦为数据仓库,选哪家的数据库就变的不再重要了,更换数据库变成了伪需求,不再存在,ORM 理论的重要来源:屏蔽各个关系数据库之间的不同点,以让用户更换数据库无忧,这一最初的重要需求,不再存在。 第 2 个变化是,进入新世纪后,SQL 作为一个 4GL 语言的价值终于被发现,大家纷纷表示这种“do not tell me how to do,tell me what you want(不要告诉我怎么干,告诉我你要什么)”的模式真是太香了;而且一众 NoSQL 的鼓吹者们高举大旗准备驱逐关系数据库,结果闹了很久后发现自己拿 SQL 居然毫无办法,只能捏着鼻子,纷纷又开始在自己的查询器上加上了 SQL 支持。传统关系数据库是没落了,但是 SQL 以及背后承载的关系运算的思维,在新时代反而是大行其道。复杂查询直接上 SQL 那感觉是真香,连新普的大数据从业者都自嘲自己说:后端是 CRUD Boy,我们就是 SQL Boy 。 总之,新世纪的竞争里,目前看是 SQL 赢了,ORM 的思维只比较适合无连表的 CRUD,对单表或多个单表执行 OLTP 业务,此时的 ORM 是比你写多个 insert,select 啥的方便的,但是一旦涉及到复杂的联表,group,having 查询,大家否纷纷直接上 SQL 更方便。 另外从业界的进化你也可以看得出来,纯正的 ORM,在 Hibernate 和.Net Entity Framework 之后几乎就没有再看到出名的了,JPA 则是从 Hibernate 发展来的,可以看做延续和强化,但本质不会变。但是各种"SQL 工具类"型的查询库,还在层出不穷的出,而且这些工具并非墨守成规,Ruby on Rails 开历史先河,吸收 ORM 对单表查询很友好这个优势,发展出了 Active Record 这种即可以从单表结构直接映射出对象,并可以在查询的时候以链式调用的方式注入查询条件;同时,都保留了能够方便自定义 SQL 的能力。其它 Sql 工具一看纷纷跟进,包括现在 Mybatis 的几个强化工具都是这个思路。 所以我觉得接下来一段比较长的时间,除非出现新的变革,占优势的应该还是各种更亲和 Sql,但是同时具备表映射对象能力的各种 SQL 帮助工具。 |
15
echo1937 2021-07-31 10:48:33 +08:00
Spring Data 是 Spring 提供的一个操作数据的框架,旨在统一和简化对各类型持久化存储,
而 Spring Data JPA 只是 Spring Data 框架下的一个基于 JPA 标准操作数据的模块。 它的优势是 RDBMS 、Redis 、MongoDB 、ES 、Cassandra 、Solr 、GemFire 等等都可以用同一套的 API 去访问,这点是 mybatis-plus 做不到的。 缺点是国内用的少(国外 99%都是这个),有一定学习门槛,注解比较多,没有 JDK text block 的话,写原生查询 SQL 看着不美观。 如果你业务离不开 mybaits,mybatis-plus 确实非常好用。 |
16
yema50 2021-07-31 10:54:29 +08:00
@limbo0 最近也在尝试用 mybatis-plus, 请问一般查数据的时候,假如有一两个条件参数, 你们一般是在 Mapper 里定义好方法然后 service 里直接调用, 还是直接在 service 里构造 QueryWrapper 查询呢
|
17
abcbuzhiming 2021-07-31 10:58:13 +08:00
@yema50 单表查询请一律不要自己定义 mapper 和 service,直接用表反向映射生成实体,mapper,service,然后你构建 QueryWrapper 注入查询条件,用 mapper 还是用 service 就随你了。
这类工具的设计目的就是为了解决纯 SQL 工具在单表查询时不如 ORM 方便的。如果你单表查询还要去自己定义 mapper 和 service,那等于这个工具没有起作用 |
18
yema50 2021-07-31 11:23:15 +08:00
@abcbuzhiming 感谢回复,可能我没有表述清楚, 我举个例子。现在有个 User 实体,对应的 UserMapper, UserService,现在有个需求要根据 username 查询,我想到的实现方式有 1. UserMapper 里定义一个方法 findUserByName(@Param("name") String name), 然后上面加上对应的注解和 SQL,再在 userService 里直接调用; 2. 在 userService 里需要查询的地方构造 QueryWrapper<User> query....., query.eq("name", "name"), 然后再查询。
我的困惑是:1. 如果使用第二种方式,可能会有多处需要用到类似查询的地方, 那就是代码里会有多处构造相同 QueryWrapper 的代码; 2.如果使用第一种方式, 可能有时查询条件会增减,比如某处需要再加上 age 作为条件,这样又感觉不够动态 请大家指教 |
20
Kipp 2021-07-31 11:30:49 +08:00
@yema50 #18 之前也思考过这个问题,觉得还是放在 mapper 里比较好,不然 QueryWrapper 到处飞,之前的 QueryWrapper 也没法复用
|
22
Rwing 2021-07-31 12:16:01 +08:00
欢迎各位大佬来 C# 体验一下 entity framework,看看什么是真正的 ORM
|
23
abcbuzhiming 2021-07-31 12:16:07 +08:00 3
@yema50
方式 1 就是传统的 mybatis 方法,你要用方式 1,没必要用 mybatis-plus 方式 2 本身就是脱胎于 ActiveRecord 的链式调用,这个方式最初的来源就是我上面说的 Ruby on Rails,它提供了高度的灵活性,代价的就是代码看上去像事务脚本,但是我认为这个在开发效率,这是值得的。 最后,后端的项目,在经历过几轮微服务拆分后,业务是高度内聚的,你几乎很难遇到多处复用你这个查询代码的情况,我认为初期就考虑复用,这个想法是有问题的 |
24
Cbdy 2021-07-31 12:17:36 +08:00
|
25
abcbuzhiming 2021-07-31 12:19:20 +08:00 3
|
26
pigbug OP @abcbuzhiming #25 非常赞同
|
27
ikas 2021-07-31 12:39:29 +08:00 1
1.ORM 到底是什么程度..根据业务.喜好选择,根本不是什么需要争论的问题
2.如何更好的拼接 SQL[条件]才是最大的问题,不管你用 jpa,spring jdbc,jdbc,mybatis,dsl 3.xml 只是 mybatis 的一种动态 sql 方式.他本身也支持代码,也支持你自己开发其他动态方式,也支持 sqlbuilder 目前我自用的.... @Select(""" <script> select count(*) from pet <where> <if test='name != null' > and name like #{name}</if> </where> </script> """ ) List<Long> querySomeCount(@Param("name") String name); |
28
ColinZeb 2021-07-31 12:47:22 +08:00
@abcbuzhiming 不考虑一下 EF Core 的 Linq
|
31
abcbuzhiming 2021-07-31 13:16:00 +08:00 1
|
32
potatowish 2021-07-31 13:18:33 +08:00 via iPhone
jdbctemplate 就算了吧,最好的方案就是单表操作用 mbp 、tk,多表操作就在 mybatis xml 中写原生的 sql,无脑吹这个那个的都是老顽固
|
34
wanguorui123 2021-07-31 14:13:18 +08:00 via iPhone
C#的 EntityFramework 、FreeSql,才是真正的 OOP
|
37
hutoer 2021-07-31 14:26:04 +08:00
@abcbuzhiming Controller 层加业务?不考虑业务代码复用?
|
39
ColinLi 2021-07-31 15:38:46 +08:00
简单查询用 jpa,复杂查询用 jdbctemplate+sqlbuilder
|
40
ebony0319 2021-07-31 16:02:38 +08:00
ORM 的方向是对的,但是 jpa 在稍微复杂一点的场景,关联表的时候还是得写原生 sql,革命尚未成功,仍需努力.
|
41
abcbuzhiming 2021-07-31 16:05:30 +08:00 1
@hutoer 为什么要在初期就考虑代码复用?为啥不能遇到能复用的时候,再去把代码抽成 service ?为啥一定在初期搞这种过度设计?
|
42
abcbuzhiming 2021-07-31 16:06:48 +08:00 1
@ebony0319 ORM 的方向如果是对的,它就不会遇到复杂场景必须回到 SQL 这种尴尬的问题。本质是对象模型并不能如当初的人们估算的那样取代关系模型,只要关系模型自身不倒,ORM 就始终处于尴尬的位置
|
43
alamaya 2021-07-31 16:12:43 +08:00
@abcbuzhiming 可怕,连考虑代码复用都成了过度设计,好同情接手你的屎山代码的同事
|
44
abcbuzhiming 2021-07-31 16:29:39 +08:00 3
@alamaya
问题是你到底是怎么考虑代码复用的? 哦,看到一段操作数据库的代码,就不能放在 Controller 里?就得写个 service 装起来,搞不好这个 service 还得先是一个接口,然后做出一个 Impl 实现类来?是这个意思吗? 考虑复用难道不是先考虑一下有没有复用的可能性吗?当根本就没有复用的可能性时,就像我前面说的,业务代码几轮拆分后都是高内聚的,哪有让你复用的机会?也要“复用”吗? 如果你一开始就已经想到了这段代码在业务上就是需要复用的,甚至这个需求就在眼前,那我万分支持你把立刻把这段代码抽出来变成一个 service,给人复用。如果你一开始根本想不出来要在哪里复用,那为什么要复用?这不是过度设计又是什么呢?就像很多项目写一堆直到项目死掉都不会改成实现的接口,美其名曰 [规范] 。。。 退一万步讲,你到了遇到有需要复用的那一天,再把 Controller 里的代码抽出来变成一个复用的 service,这很费事吗? 我见了太多的人,都是嘴上空谈说 [复用] ,我直接问他们关于眼前项目,你觉得这个位置的代码在哪里可能会复用?鲜有答上来的,他们大部分也估不到项目在发展中会遇到什么。只不过是看别人是这么干的,或者说按所谓的规范应该这么干的。。。 除非你已经想到需要的地方,那么再动手,不要过早动手,优先完成业务。这是我的法则。就目前的实践经验看,和我配合的人都挺喜欢的,没觉得我的代码就是屎山。当然有人不认同我能理解,毕竟张口闭口设计规范的人非常之多,谢欢在项目里写一堆到死也不会发生变化的接口的人更不少 |
46
Kamiyu0087 2021-07-31 17:10:51 +08:00
进来想说 Exposed
仔细一想 Exposed 是 Kotlin 的 |
47
testFor 2021-07-31 17:52:05 +08:00
有个疑问,jpa 这种的 orm,不是对于领域设计会更加友好么,不是更能解决复杂业务么
|
48
fpure 2021-07-31 17:58:10 +08:00
上个项目用 JPA,想撞墙,因为 JPA 匮乏的表达能力做了很多骚操作,现在代码也已经腐烂的不成样子了
|
49
SawyerGuo 2021-07-31 17:59:38 +08:00
哎,我也听说 mybatis-plus 好用,但就是懒得学。
|
50
fpure 2021-07-31 18:03:15 +08:00
@abcbuzhiming 很多人就是这样,过度设计,滥用 DRY 原则和开闭原则
|
51
witcherhope 2021-07-31 18:10:28 +08:00 via iPhone
@testFor 领域驱动设计跟 ORM 没有任何必然联系,统一语言做的就是屏蔽技术细节,抽象业务本身。
|
52
potatowish 2021-07-31 18:44:09 +08:00 via iPhone
@SawyerGuo 没有学习成本,照着文档撸就好了
|
53
Lemeng 2021-07-31 19:09:57 +08:00
哎,感觉自己人变懒了
|
54
KevinBlandy 2021-07-31 20:52:54 +08:00
spring-data-jpa + querydsl 永远滴神。
|
55
shakoon 2021-07-31 21:56:32 +08:00 via Android
脱离业务场景谈技术都是空谈。——一个写了十几年存储过程的程序员
|
56
crclz 2021-07-31 23:11:23 +08:00 4
JPA for write/transaction
SQL for query ================= “来自”微软官方的答案。 ——引号是因为微软在.net 世界给出了一个类似的解决方案。 https://docs.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/cqrs-microservice-reads 查询( read )用的是 micro orm Dapper,命令( write )用的是宇宙最强 orm Entity Framework 。 虽然 ef 的表达能力几乎覆盖 sql,但是微软却告诉你:没必要全程用 ef 哦! 关键词:cqrs |
57
fkdog 2021-08-01 00:00:00 +08:00
我觉得 mybatis-PLUS 的 api 设计的一言难尽。一种查询方法愣是被弄出 N 个 api 。。
其实大部分人对 orm 框架的需求很简单,支持泛型 crud 模板方法,支持 orm 就足以,一个简单的 DBUtils 工具类就能实现。 现在国内的互联网项目都普遍喜欢在代码层面 join 而不是交给数据库。类似管理后台这种经常需要复杂条件组合查询和多表 join 的,一般都丢交给 es 或者数仓了。 |
58
yizmaoaa 2021-08-01 00:06:17 +08:00
Ebean
- -哎,主要还是多行字符串,不然谁用 Mybatis |
59
ameccc 2021-08-01 00:27:51 +08:00
SQLDelight 能算是生产级别的吗?自己写玩具用这个写的很开心。
|
60
GiantHard 2021-08-01 10:34:55 +08:00
我最近在从 mybatis-plus 切换到 MyBatis Dynamic SQL,好处如下:
* 类型安全,通过官方提供的代码生成器,保证数据模型与数据库模型一致,避免字段写漏、类型写错 * 表达力强,Dynamic 提供的 DSL 语法与 SQL 相比差异不大,完全可以复用自己写 SQL 的经验 * 足够灵活,不管是简简单单的 INSERT 还是像一篇小作文一样的 WHERE,Dynamic 提供的 DSL 都可以 hold 住 * 拓展性强,Dynamic SQL 并没有跟 MyBatis 绑定死,默认还支持 JDBCTemplate 跟 JDBC,除此之外,还可以自定义类型安全的数据库函数跟操作符 最开始我很喜欢 EF Core 这样“正宗”的 ORM,但是现在用过这种类型安全且表达力强的 SQL DSL 之后,我的初心动摇了 |
61
ikas 2021-08-01 13:40:01 +08:00
话说没人用过 doma 么...支持模板与 dsl
val list = entityql .from(e) .innerJoin(d) { eq(e.departmentId, d.departmentId) } .where { eq(d.departmentName, "SALES") } .associate(e, d) { employee, department -> employee.department = department department.employeeList += employee } .fetch() @Dao public interface EmployeeDao { @Sql( """ select * from EMPLOYEE where /*%if salary != null*/ SALARY >= /*salary*/9999 /*%end*/ """) @Select List<Employee> selectBySalary(BigDecimal salary); } |
62
xuanbg 2021-08-01 13:57:44 +08:00
用 mybatis,但绝不用 plus 。简单的 sql 数据库管理工具都能自动生成,复制出来就行。复杂的 sql 除了手写没别的办法。。。
|
63
charlie21 2021-08-01 15:48:24 +08:00 via iPhone
靠写面条代码样子的烂代码并入库( merge into main branch in the repo ),
堆屎山堆得谁也看不懂了 不好接手, 让自己的不可替代性变得越来越强, 说的是谁呢 @abcbuzhiming ? 你所在的公司当然是对你的依赖性愈发变强的 这没问题 你的价值是被认可的, 但在我司 如果谁敢在 controller 里作数据库操作,那么第二天他就会被从主程队伍里过滤掉,发配 “边疆” 去写一些边边角角的代码;如果狡辩则直接开除 so 恭喜你没在我司 |
64
james122333 2021-08-01 17:41:15 +08:00 via Android
个人还是爱 php pdo 那种方式 好写 如果案子大了再封装也方便 兼顾灵活与直觉 参数判断写 xml 判断就神经了 也不可能全代码化 debug 又方便 step 调适很容易找到问题点 至于 service 还是会分的 因为 http 特性 但也就两层而已 剩下都是辅助工具让代码容易维护 orm 特烦没错
|
65
tctc4869 2021-08-02 08:52:01 +08:00
jfinal 的 ar+enjoy
|
66
chocotan 2021-08-02 10:27:57 +08:00
公司项目用 mybatis,自己项目用 spring data jpa 和 querydsl
|
67
ccppgo 2021-08-02 14:49:18 +08:00
@james122333 这种就是 jdbcTemplate 吧
|
68
abcbuzhiming 2021-08-03 10:00:43 +08:00 1
@charlie21 我已经非常明确的描述了我的观点,我并不抵触严谨代码结构。我只是强调应该根据不同的的情况选择不同的方式,我非常开心能够不用和你这种永远停留在自己的舒适区的人一起共事,之前也遇到过这样,号称“不按他的规范来就开除”,然后我就看着他有一天就撞到了他的规范无法处理,然后必须妥协的时候,最后此人的选择就是一走了之。。。
在 Controller 里写数据库处理逻辑非常常见,很早就有技术文章描述过这种“事务脚本编程”方式的优劣,如果你看过别的语言的 mvc 框架,也能看到这样的实现,只是你自己不可接受而已,随便你怎么想,我来这里不是和人吵架的,而是和人交流,我不排斥任何处理方式,只要他能更好的解决问题就行。 |
69
unbright 2021-08-04 10:57:52 +08:00
jpa 配合 ddd 强无敌
|
70
CyberShadiao 2021-08-05 11:35:04 +08:00
@Leviathann 我现在就是你说的这种情况,前端传 sql 条件部分的语句 后端再拼接。代码里面到处都是 sql
|