写了 15 年的程序,人到中年总有很多话要说,千言万语尽在项目里,里面有我想说的一切。
项目地址: https://github.com/braisdom/ObjectiveSql
ObjectiveSQL 是我构想了很长时间,到底是让 Java 像 SQL 一样编程,还是让 SQL 让 Java 一样编程,纠结了很久,还是让 Java 更像 SQL,Java 的语法表现力不够,只能扩展 Javac,实现了算法运算,比较运算,逻辑运算符重载,并封装了常用数据的的函数,抽象了 Expression,使的 Java 非常接的 SQL,同时也实现了简单 SQL 编程的代码生成,基本不需要写代码,也不需要配置就能实现简单 SQL 的编程,话不多说,先看示例,有兴趣可以到 github 上看。
Order.Table orderTable = Order.asTable();
Select select = new Select();
select.project(sum(orderTable.amount) / sum(orderTable.quantity) * 100)
.from(orderTable)
.groupBy(orderTable.productId);
Member.Table member = Member.asTable();
Order.Table order = Order.asTable();
Select select = new Select();
select.from(order, member)
.where(order.memberId.eq(member.id));
select.project(member.no,
member.name,
member.mobile,
countDistinct(order.no).as("order_count"),
sum(order.quantity).as("total_quantity"),
sum(order.amount).as("total_amount"),
min(order.salesAt).as("first_shopping"),
max(order.salesAt).as("last_shopping"));
select.groupBy(member.no, member.name, member.mobile);
ObjectiveSQL is an ORM framework in Java base on ActiveRecord pattern, which encourages rapid development and clean, codes with the least, and convention over configuration.
Features
102
pythonee 2020-11-22 21:51:56 +08:00 1
点赞
有对比过 linq 吗 |
103
bugmakerxs 2020-11-22 22:01:00 +08:00 1
其实解决 orm 还有另一个思路是避免复杂 sql,比如微服务;如果一定要复杂 sql 才能解决的问题,我们一般都交给大数据团队做离线计算了。个人认为复杂 sql 不管怎么表达,,都挺难维护的。。
|
104
Braisdom OP @bugmakerxs 离线计算需要一定的前提,离线计算只是输出中间结果,前台的计算复杂度依然存在。
|
105
Braisdom OP @pythonee 你有兴趣可以看一下贴子前面的讨论,Linq 分为两种,1 )内存计算,2 ).NET Entity Framework 实现,很优秀,值得借鉴
|
106
liuhan907 2020-11-22 22:44:04 +08:00 via Android
@Braisdom 其实 ef core 最优秀,或者说最能节省精力的地方在于自动追踪查询出来的结构的数据变化并生成 update 语句。所有的操作都是强类型。不过性能上就弱一些。再次看了你的项目的 repo,你这个我觉得更加类似 dapper 。
|
107
beginor 2020-11-22 22:53:00 +08:00 via Android
不知楼主有没有兴趣了解一下这个 https://github.com/re-motion/Relinq, .Net 上的不管是 EF 还是 NHibernate, 都是用了这个来进行 linq 表达式树的转换
|
108
beginor 2020-11-22 22:54:34 +08:00 via Android
@beginor 手滑了, 正确的地址是 https://github.com/re-motion/Relinq
|
109
momocraft 2020-11-23 01:23:55 +08:00
有点像 slick
|
110
momocraft 2020-11-23 01:24:26 +08:00
纯用 java 做这个真的有毅力..
|
111
miaoever 2020-11-23 02:57:38 +08:00
我司 (也算大厂了吧) 做过类似的事情, 主要针对的场景是 OLAP 的 SQL. 我们的做法是提供两套 API ,一套是 SQL 本身,另一套是类似于楼主的这种链式调用 API (不过我们是 Python), 同时我们两套 API 可以混用 .
我们做这个工作一个重要的出发点能够对 SQL 进行静态的类型检查 (以及其他的一些语义检查). 做法上和楼主不一样的是, 我们不基于宿主语言 (Java or Python) 的类型系统,而是将 SQL 或者 链式 API 的程序统一翻译成一个中间表达形式 (IR), 然后再其上做类型检查. 此外, 我们不仅仅是对单个 SQL 做类型检查, 更重要的是对整个 OLAP 链路上所有具有数据血缘的 SQL 会做全局检查, 以保证链路上任何 SQL 的修改都都不会破坏其上游及下游 SQL 的合法性. 当然类型检查只是我们做的一方面, 我们还做了很多其他的更重要的语义检查, 在这儿就先不展开说了. 另一很重要的动机是 SQL 的的提高可组合型以及复用性. 举个简单的例子, 用楼主的给的场景来说, 对于以下的这个计算(当然我们的现实中的场景比这个复杂的多): sum(orderTable.amount) / sum(orderTable.quantity) * 100 我们的系统里, 这个计算可以定义成一个库函数 (def sum(double)->double). 这个函数可以像普通编程语言中的库函数一样在任何一个 SQL 中进行调用: SELECT sum(1.0) FROM table1 // SELECT.PROJECT(sum(1.0))..... 同时, 我们的静态检查工具能够静态的当前调用环境中 SUM 函数时输入类型和返回类型做类型检查. |
112
Mithril 2020-11-23 07:25:31 +08:00
支持,Java 和.NET 都写的表示 Java 真的缺少 Linq 这种东西。
Linq to object 自动在内存中处理所有 IEnumerable,而且支持并行。 Line to SQL 会自动编译成对应的 SQL,而且无法编译的现在并不会自动在内存处理,会直接报错。虽然免不了手写 SQL,但不是整个项目所有地方都需要真正手工优化 SQL 的。 最关键的是两者语法基本一致,写起来非常流畅。 |
113
wanguorui123 2020-11-23 07:49:42 +08:00 via iPhone
有点像 FreeSQL
|
114
lqw3030 2020-11-23 08:22:53 +08:00 via iPhone
不管怎么样先嘲讽,思想就很有问题
|
115
luoyikang52066 2020-11-23 08:46:48 +08:00 via Android
支持
|
116
CallMeADU 2020-11-23 10:00:13 +08:00
出发点不错,技术能力也很强。不过从多数程序员角度肯定是不喜欢用 java 代码去实现 sql 生成的,一不直观,二代码有 sql 写的爽吗?还是喜欢各自领域各司其职
|
117
Braisdom OP @lqw3030 我的想法是很有问题的,充满了对现实的不满,我之前写了四,五年的 Ruby, Python,回到 Java 尽然快 20 年了一直都没什么变化,十分气愤
|
118
Braisdom OP @miaoever 通过函数实现算术表达现在比较流行,但表达式过于复杂,函数也力不从心的。
例如: IF((COUNT(DISTINCT IF((dateDiff('second', t1.finish_time, t2.sales_at) AS t) < 14*24*60*60 AND t > 0, t2.member_no, NULL)) AS p6) IS NULL, 0, p6) AS sales_member_count 这样的表达式,如果全部是函数封装,根本没人看得懂 |
119
wysnylc 2020-11-23 10:33:13 +08:00
支持聚合函数的 JPA,但是分页子查询排序这些问题不可能维护的完的
|
120
Braisdom OP @wysnylc 复杂性是无法避免的问题,也是客观的事实,ObjectiveSQL 的目的是让复杂性变得更清晰,更可读,而不能完全降低复杂性。
|
121
ZiLong 2020-11-23 10:39:14 +08:00 2
点赞,支持,这是有人不断提出挑战,落实行动,才会有不断的进步
|
122
zclHIT 2020-11-23 10:54:43 +08:00 1
赞
|
123
aiden4 2020-11-23 11:21:16 +08:00
rails 就是这样子写 sql 的,用起来还是很舒服的。java 确实缺少这样的东西
|
124
mazhimazh 2020-11-23 11:33:48 +08:00
支持,哈哈,你历时 3 年写软件,我历时 3 年是研究 JVM 源代码,并且写 3 本书,明年 8 月就 3 年,也快完成了
|
125
GM 2020-11-23 12:07:41 +08:00
已经很不错了,点个赞。
其实我一直在找类似 ActiveRecord 的 Java 实现,一直没找到感觉好用的,ActiveJDBC 、ActiveJpa 都不够好用。 你这参考 lombok 的思路倒是个方法,可以用来实现一套 ActiveRecord for Java 。 |
127
zoharSoul 2020-11-23 14:00:06 +08:00
感觉用 kotlin 实现好一些.
天然支持中缀表达式和运算符重载. 熟悉起来会更像 sql |
128
cmdOptionKana 2020-11-23 14:05:05 +08:00
@zoharSoul 对哦,这个改成 kotlin 看起来会很酷,甚至可能比 Linq 更酷!
|
129
Braisdom OP @zoharSoul 非常认可你的想法,这也是 Java 语言糟糕的地方,不够灵活
但话说回来,Kotlin 语言想成为主流,过程还是很漫长的,Android 后续也会向 Flutter 倾斜,Kotlin 后面的发展比较难呀。 很多好东西不一定会流行,但历史会记住它的 |
130
Braisdom OP 如果 ObjectiveSQL 后续的发展能够起来,我准备在 Python 端探索方向,Python 的受众群体也是比较大的。
|
131
122006 2020-11-23 14:13:22 +08:00
用类似于 lombok 实现运算符重载,太强了。
安卓不知道能不能支持,理论上 lombok 也可以说明应该只是兼容的问题,在安卓中直接写 sql 比较少的,如果可以证明稳定性的话推广起来比 springboot 上容易太多 |
132
vitoliu 2020-11-23 14:14:07 +08:00 1
支持,感受产品->创造产品->激发新产品
|
133
zoharSoul 2020-11-23 14:15:48 +08:00
|
134
cmdOptionKana 2020-11-23 14:17:47 +08:00
@Braisdom 楼主,请看一下 kotlin 的这个特性,就花你 2 分钟时间 https://medium.com/makingtuenti/infix-functions-in-kotlin-2db3d3142dd2
用上这个,可以让你这个项目看起来很 geek, 很酷! |
135
zsc8917zsc 2020-11-23 14:22:47 +08:00 1
Java 版的 Linq2SQL,点赞支持,向大佬致敬
|
136
Braisdom OP |
137
brezp 2020-11-23 15:22:27 +08:00
支持, 下次自己的项目拿来试试
|
139
bk201 2020-11-23 16:05:16 +08:00
我是不明白为啥要把可以让 dba 去优化的 sql 写成代码。
|
140
Braisdom OP @bk201 你可以看一下前面我的解释,
DBA 和程序员 需要的是不同的 SQL 编程方式,程序员需要的更多是动态的 SQL 构造过程,传统 SQL 远远做不到。 |
141
CatTom 2020-11-23 17:15:58 +08:00
老哥,我在导入你的 jar 时 maven 一直报错识别不到。。。。。
|
144
bxb100 2020-11-23 17:40:14 +08:00
有性能优化的比较吗
|
148
Gugetech 2020-11-23 17:59:55 +08:00 1
很赞哦,已 star
|
149
Braisdom OP @bxb100 老实说,性能指标还真的不好搞,主要因为 ObjectiveSQL 是一个无状态的框架,本身不存储任何东西,唯一需要验证的是内存泄露,SQL 的构造也都是字符串拼接,本质上不会有性能问题。
|
150
a4854857 2020-11-23 19:31:27 +08:00 1
|
151
henryshen233 2020-11-23 19:48:33 +08:00
@Braisdom 楼主,#114 好像说的是首页有些人说话语气有问题
|
153
tt0411 2020-11-23 21:31:07 +08:00 1
为楼主点个赞.
但从实用角度和个人偏好来说, 能直写 sql 就绝不用各类 dsl/自动 SQL 生成 的框架: 一方面专门学一套新的接口 ROI 不高, 另一方面真的遇到问题是, 看 SQL 改 SQL 也比接口更容易. |
154
Braisdom OP @tt0411 其实我不是很喜欢 DSL 这个概念,按道理说 SQL 是一个 DSL,而 Java 是基于自身的抽象能力与表达能力使得 SQL 更便于逻辑控制。
当然,这是我个人的感觉,每个人有不同的背景,也会有不一样的认知,没有对与错,只是会用不同的方式进行工作而已。 |
156
aguesuka 2020-11-24 12:49:32 +08:00 via Android
楼主了解依赖类型(dependent type)吗。我想过为什么 java 表现不了 sql,这个是答案之一。不过 sql 是基于集合论而非类型论,所以拘束于 sql 语法是实现不了类型安全的
|
157
Braisdom OP @aguesuka 你说的很对,SQL 语言是一种已经被习惯的数据查询和分析语言,最初的设计是直接给人使用的,而不是为程序设计的,逻辑控制、强类型等程序化的概念的使用是需要专业训练的。
我挑战的是 SQL 语言在程序上的表现力,目前只是第一个版本,我的想法还没有充分彰显。 对权威的挑战必定会迎来更多人的挑战,这是正常的,没有对权威的挑战,这个时代也就不会进步了。 |
158
Joker123456789 2020-11-25 14:16:37 +08:00
我也是做开源项目的,也遭遇过不少质疑,从这个角度来看,我真的很想说一些鼓励的话,甚至支持一下。我最近也看到这个项目在 osc 上得奖了。
但是我还是想理性分析一下: 1. 一般来说,我们在开发的时候如果需要操作数据库,会怎么办?我想大多数人都是在 navicat 里写 sql,测好以后,再贴到项目中来, 而用了你这个,只需要直接在项目中写代码即可,省去了粘贴的步骤。 2. 第 1 点看似是提高了效率,但是也引发了另一个问题,如果在 navicat 里写 sql,用工具也可以通过可视化的方式生成 sql,写起来并不慢,而且验证速度非常快,只需要点击一个按钮即可, 而在项目中用你这个写的话,验证就得启单测了,这个速度相差的可不是一点点。 我之前也想过要在我的项目中加入类似的功能,但是考虑到开发效率,就放弃了。毕竟一切的工具都是为了提高干活的效率,或者运行效率,如果没有这个前提的话,所有的花样都只是一种新鲜感。 如果你可以解决这个问题的话,比如开发配套的 idea 插件 或者 其他方法,相信大家会更愿意使用的。 |
159
Braisdom OP @Joker123456789 你的分析很到位,一个工具很难做到面面俱到,不太可能适应所有的场景,有舍才有得。
1 ) ObjectiveSQL 主要解决动态 SQL 的编程,所谓动态:也就是 SQL 结构很难通过字符串接近的形式实现,这种场景下,传统 SQL 想变为程序很困难,将这样的程序直接变成 SQL 也不容易,ObjectiveSQL 会通过单元测试的形式提供完成 SQL 。 2 )其实,程序员到底是看到 SQL 呢,还是还到 Java 一直是矛盾的中点,试想一下,如果没有 SQL 的存在,大家直看 Java 会是什么样的一种状态。 |
161
VincentLau 2021-02-19 14:30:20 +08:00
支持,这个项目很有意义,另外想问一下楼主都 Ktorm 怎么看
|
162
VincentLau 2021-02-19 14:31:45 +08:00
打错字,都 --> 对
|
163
Braisdom OP @VincentLau 兄弟我仔细看过你的项目,Kotlin 语言不是特别熟悉,你的项目和 ObjectiveSql 的思路非常接近,将 SQL 程序化封装(只不过我按 Lombok 的原理,实现了一些更方便的特性),能持续维护很值得敬佩,加油。
@VincentLau 最近我在自己做一个搜索引擎的项目,也是我未来创业的项目,如果有兴趣可以加入。 |