项目地址: https://github.com/braisdom/ObjectiveSql
@DomainModel
public class Blog {
private Long id;
private String title;
private Integer state;
@Relation(relationType = RelationType.BELONGS_TO)
private Author author;
}
MyBatis | ObjectiveSQL |
public interface BlogMapper { @Select("SELECT * FROM blog WHERE id = #{id}") Blog selectBlog(int id); } ... BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.selectBlog(i); |
Blog blog = Blog.queryByPrimaryKey(1); |
MyBatis | ObjectiveSQL |
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="org.mybatis.example.BlogMapper"> <select id="findByTitle" resultType="Blog"> select * from Blog where title like '%#{title}%' </select> </mapper> ... BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.findByTitle("标题"); |
public static Blog queryByTitle(String title) { Query<Blog> query = createQuery(); query.where("title like ?", "%" + title + "%"); return query.queryFirst(); } ... Blog blog = Blog.queryByTitle(1); |
MyBatis | ObjectiveSQL |
<select id="findActiveBlogLike" resultType="Blog"> SELECT * FROM BLOG WHERE <if test="state != null"> state > #{state} </if> <if test="title != null"> AND title like #{title} </if> <if test="author != null and author.name != null"> AND author_name like #{author.name} </if> </select> ... BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper.findActiveBlogLike(...); |
Blog.Table blog = Blog.asTable(); Select select = new Select(); LogicalExpression eternalExpression = new EternalExpression(); if(state != null) eternalExpression = eternalExpression.and(blog.state > state); if(title != null) eternalExpression = eternalExpression.and(blog.title.like(title)); if(author != null && author.name != null) eternalExpression = eternalExpression.and(blog.author.like(author.name)); return select.from(blog).where(eternalExpression).execute(); |
MyBatis | ObjectiveSQL |
<mapper> <resultMap type="Blog" id="blog"> <id column="id" property="id" /> ... <association property="author" javaType="Author"> ... </association> </resultMap> <select id="findBlog" parameterType="int" resultMap="blog"> ... </select> </mapper> ... BlogMapper mapper = session.getMapper(BlogMapper.class); Blog blog = mapper. findBlog(...); |
Blog blog = Blog.queryByPrimaryKey(1, Blog.BELONGS_TO_AUTHOR) |
1
cmlanche 2020-12-11 16:54:05 +08:00
不错
|
2
putaozhenhaochi 2020-12-11 16:54:40 +08:00
为啥不用 JPA?
|
3
Braisdom OP @putaozhenhaochi JPA 和 MyBatis 差别不大,
|
5
qmzhixu 2020-12-11 16:57:18 +08:00 1
简单查询用 MyBatisPlus 可以解决
|
6
wr516516 2020-12-11 16:57:59 +08:00
看上去和 MyBatisPlus 差不多?
|
7
brucewuio 2020-12-11 17:03:28 +08:00
自己写,这种声明式的确是很爽,但是如果是公司,人员经常流动,mybatis 这种 xml 可能阅读性高一点。
|
9
Braisdom OP @wr516516 MyBatisPlus 依然无法摆脱 xml,可以进去详细了解一下: https://github.com/braisdom/ObjectiveSql
|
10
w292614191 2020-12-11 17:12:05 +08:00
现在大部分语句都是生成了。
复杂的要手写,你这个也要手写。 |
11
Kirsk 2020-12-11 17:18:11 +08:00 via Android
这不就是 active record 模式么 没必要自己实现 直接在 orm 上自定义就好了 要不在 jpa 上封装一套 unit of work activeRecord 各种模式可选 狗头
|
12
Jeb 2020-12-11 17:19:54 +08:00
if 后面没有大括号看着有点不习惯了
|
13
sheeta 2020-12-11 17:20:25 +08:00
laravel orm 才是真的爽
|
14
cheng6563 2020-12-11 17:20:30 +08:00
eternalExpression.and(blog.state > state);
这个大于判断怎么做到的? |
17
fengpan567 2020-12-11 17:29:10 +08:00
我现在都是首选 mybatis-plus 了,右边的感觉很像 JPA,但是复杂 sql 还是写到 xml 比较好
|
18
okayan 2020-12-11 17:30:47 +08:00
还是感觉 MyBatis 的 XML 更易读
|
19
easylee 2020-12-11 17:33:15 +08:00 1
只要是不用 xml,看起来就很舒服。
|
20
Braisdom OP |
22
taogen 2020-12-11 17:44:21 +08:00
试着对比一下这个 sql 呢?下面是 mybatis 写法
SELECT name, value FROM ( SELECT b.site AS name, COUNT(*) AS value FROM task AS a left join task_for_development AS b ON b.task_id=a.id WHERE a.delete_flag=FALSE AND a.category="development" AND b.site IS NOT NULL AND b.site != '' <trim prefix="and" suffixOverrides="and"> <if test="beginTime != null"> DATE(a.create_time) <![CDATA[ >= ]]> #{beginTime,jdbcType=TIMESTAMP} and </if> <if test="endTime != null"> DATE(a.create_time) <![CDATA[ <= ]]> #{endTime,jdbcType=TIMESTAMP} and </if> </trim> GROUP BY b.site ) AS temp2 ORDER BY value desc limit 10 |
23
ychost 2020-12-11 17:51:07 +08:00
看着和 tk.mybatis 一样呢,另外 JPA 的 SpecificationExecutor 和 Example 用起来也很简单,不过还是喜欢 .NET 的 LINQ 感觉这才是最好用的
|
24
Ayanokouji 2020-12-11 17:53:23 +08:00
和 ebean jooq 比有啥优势( jooq 非开源的收费)
|
25
qwerthhusn 2020-12-11 17:57:09 +08:00
'%#{title}%' 这样如果没校验,分分钟 SQL 注入
|
26
lishen226 2020-12-11 18:33:54 +08:00
sql 可读性更强些
|
27
Kirsk 2020-12-11 19:12:45 +08:00 via Android 1
@Braisdom 设计的挺好的 不过条件查询上是怎样个用法 看起来有点接近 sql 拼接了 应该可以用下 example spec 的思路 example 没实现条件表达
|
28
miao1007 2020-12-11 20:40:18 +08:00
这个人员流动大时,控制不住质量
|
29
VeryZero 2020-12-11 21:00:57 +08:00
支持一下,不过看着跟 JPA 类似啊,有什么这个能做,JPA 不能做的特性吗?
|
30
Braisdom OP @cheng6563 看我的代码,我实现了运算符重载
@taogen 你想要的通过这种方式很容易实现 Member.Table member = Member.asTable(); Order.Table order = Order.asTable(); Select select = new Select(); select.project(member.no, member.name, count().as("order_count")) .from(member) .leftOuterJoin(order, order.memberId.eq(member.id)) .groupBy(member.no, member.name); List<Member> members = select.execute(Member.class); |
31
Braisdom OP @VeryZero 下面的复杂表达式计算,现有的所有 ORM 框架都做不到,但却很实用。
``` Order.Table orderTable = Order.asTable(); Select select = new Select(); select.project((sum(orderTable.amount) / sum(orderTable.quantity) * 100).as("unit_amount")) .from(orderTable) .where(orderTable.quantity > 30 && orderTable.salesAt.between("2020-05-01 00:00:00", "2020-05-02 23:59:59")) .groupBy(orderTable.memberId); List<Order> orders = select.execute(Order.class); ``` |
32
adguy 2020-12-11 21:51:03 +08:00 2
手写 sql 是对我这个 crud 仔最后的尊重
|
34
kylix 2020-12-11 22:44:38 +08:00 via iPhone
恕我眼拙,没看出来
|
35
sprite82 2020-12-11 22:47:52 +08:00
很好,可我还是选择 mybatis plus
|
36
Jrue0011 2020-12-11 22:48:47 +08:00 1
那如果需要使用一些函数比如 Oracle 的 partition by 呢,毕竟框架如果没提供,要么就直接写 SQL,要么就只能通过框架的扩展能力自己实现,这样想想还是写 SQL 好维护一些。
|
37
rockyou12 2020-12-11 23:26:46 +08:00
你这实现的……我用 jpa+querydsl 都完全能做啊,优势在哪……
|
38
casillasyi 2020-12-11 23:38:39 +08:00
mybatis 和 jpa 的优势在于,开发者知道自己最终的 sql 是什么
|
39
zmxnv123 2020-12-11 23:38:42 +08:00
可惜我用 SqlAlchemy
|
40
nc4697 2020-12-11 23:46:50 +08:00
看起来 MyBatisPlus 更易用。但是也说明楼主的项目潜力还是很大,加油
|
41
murmur 2020-12-11 23:53:04 +08:00
mybatis 的特点就是可以完全控制 sql,尤其是做复杂报表特别好使
|
42
zsl199512101234 2020-12-12 00:10:42 +08:00
https://mybatis.org/mybatis-dynamic-sql/docs/quickStart.html
感觉官方的这个更香,打算新项目试一试这个框架 |
43
sagaxu 2020-12-12 00:14:06 +08:00 via Android
拿 dsl 拼 sql ?我还不如手写 sql,代码量差不多,是个后端就能秒上手,不用学。
|
44
micean 2020-12-12 05:54:06 +08:00 via Android 1
楼主最近推广很密集哇
其实现在 idea 做的已经很好了,连上数据库就能用脚本生成一切,写 sql 用 language inject 就可以用上自动完成字段了,还带校验的 重载操作符确实是亮点,但是对于 dsl 写 sql 来说还不够 |
45
Braisdom OP 一个时代的发展前期,总是充满质疑,很正常,等真相大白的一天,各位可以反思一下今天的质疑。
我对比过现有的所有 ORM 框架,才决定做 ObjectiveSQL,以我 15 年编程的经验对比了各种优缺点。 我是做零售系统的大数据分析的,零售业也是最早将数据应用到生产过程中的行业之一,其中的 SQL 与 Java 之间磨合了很多年。我也在其中痛苦了很年。感谢各位支持,你们的质疑也是对我分析优缺点的补充。 @micean @sagaxu @zsl199512101234 @nc4697 @casillasyi @rockyou12 @sprite82 @kylix |
47
Braisdom OP @micean 推广的积极,也就说明项目的成熟度在提升,需要兄弟们支持,需要各位通过实际的行动进行投票。就像优秀的企业是靠客户的钞票投票,而不同情,一味的寻求国产支持,一直靠扶的项目或公司走不远。
|
48
justin2018 2020-12-12 10:06:04 +08:00
|
49
Braisdom OP @justin2018 感觉是的,但我的用法不太对呀。应该通过滚动条的。哈哈
|
50
xiangyuecn 2020-12-12 10:29:35 +08:00 1
@qwerthhusn #25 用了这种框架的基本上不存在 sql 注入的问题,#格式是参数化查询( like 字符串虽然也是个表达式,但只是模式而已),除非不明白机制的前提下手贱用$
jdbc 手写参数化查询太麻烦,因此直接拼接 sql 字符串多简单😂 要是易用大部分项目也就没这些要写 xml 的框架什么鸟事了(没错就是那些连接池都用不上的项目) |
51
zsl199512101234 2020-12-12 12:06:31 +08:00 1
@Braisdom 有你这样的心态和实力,肯定会成功,我会持续关注的
|
52
wg20080215 2020-12-12 12:49:05 +08:00
看起来很优秀,可能业务没那么复杂需要 DSL 和 SQL 嵌套着来,我还是继续用 JPA 。
|
53
Braisdom OP @wg20080215 ObjectiveSQL 有长的长处,也有其短处,不可能覆盖所有场景的使用
JPA 代表的是一种编程模式,以动态代理的编程,ObjectiveSQL 则是以另一种静态生成代码的形式,属于另一个流派,有人喜欢,有人讨厌,这是个人偏好问题。用心做好自己的事,不断进步。 |
54
WhereverYouGo 2020-12-12 13:33:52 +08:00
@qmzhixu #5 +1
|
55
tydl 2020-12-12 13:36:52 +08:00 via Android
比起 php 落后 写这么多代码
|
57
Braisdom OP @sweetsorrow211 @qmzhixu 有兴趣,可以深入聊一下两者,MyBatis MyBatis-Plus 我用了好多年的,正是因为它们有太做做的不好的地方,我才开始 ObjectiveSQL 项目的。
|
58
hantsy 2020-12-12 13:49:31 +08:00
10 多年没接触 Batis,实在没法比较,自进入 Apache 就没用过了,后来又被 Apache 踢出去了。
>下面的复杂表达式计算,现有的所有 ORM 框架都做不到,但却很实用。 这个吹得有点过了。 如果与 JPA 比较,从 Type Safe 角度考虑, 我首选用 JPA Criteria API ( Criteria 操作可似代替复杂的 JPQL ),不用 Spring Data 的话,自己写个通用接口,https://github.com/hantsy/helidon-sample/blob/master/mp-jpa/src/main/java/com/example/Repository.java 复杂的自己定义一下 Criteria Predicate 。 从软件设计的角度,Domain 为中心已经不再关心 Table 了,SQL 还是 NoSQL 。 |
59
Braisdom OP @hantsy 现有的框架当然支持复杂表达式了,只不过支持的方式不同而已,
以同环比的投影表达式为例: SQL:(sum(t1.current) - sum(t1.last)) / sum(t1.last) * 100 ObjectiveSQL: (sum(sales.current) - sum(sales.last)) / sum(sales.last) * 100 // sales 为 Order.asTable() 方法生成,该方法包括内部的所有字段均为怎么生成 我的项目几乎和 SQL 一模一样,你猜其它项目会怎么做呢?字符?还是 lambda |
60
Braisdom OP @hantsy 除了这些比较简单的表达式,下面的表达式呢?
过滤:where (t1.amount > 1000 and t1.product_code = '0001') and (t1.state = 1 or t1.state = null) ObjectiveSQL: order.where((order.amount > 1000 && order.product_code.eq('0001')) && order.state.eq(1) || order.state.isNull() ) 您是大佬,能看出我的 API 设计吗?为什么要做这件事,其它的 ORM 框架对于上述表达式什么怎么做? |
61
lower 2020-12-12 14:15:57 +08:00
那个说的操作符重载 是怎么弄的?看了代码没太看懂
类似这样:eternalExpression = eternalExpression.and(blog.state > state); |
62
C603H6r18Q1mSP9N 2020-12-12 14:18:50 +08:00
php 既视感,支持下,感觉 php 更简单点,请继续努力:
$blog = db('blog')->find(1); $res = db('blog')->whereLike('title', $title)->select(); if ($state) $where['state'] = ['>', $state]; if ($title) $where['title'] = ['like', $title]; $res = db('blog')->where($where)->select(); $blog = db('blog')->with('author')->find(1); |
63
Braisdom OP @shanghai1998 简单的表达式,每个框架和语言差别不大,一个项目中存在大量复杂表达式,那些都是关键,php 的复杂表达式写起来估计那没这么美观。
你写的这些每个语言,或者 ORM 框架都差不了太多,最多的就是对符号的偏好不同罢了。 @lower 那块比较复杂,不是简单能说清楚的。有兴趣加我微信:braisdom |
64
hantsy 2020-12-12 14:31:27 +08:00
@Braisdom 为了 SQL 看起来更清楚,不必要的条件就直接过滤掉,不喜欢用 Or 把所有条件考虑都加进去。
https://github.com/hantsy/helidon-sample/blob/master/mp-jpa/src/main/java/com/example/PostRepository.java#L38 |
65
Braisdom OP @hantsy 只是一个示例,算术表达式,比较表达式,逻辑表达式、函数调用 这几种在 SQL 中是最为常用的,也是每个语言都有的,但不同语言的表现形式是不一样的。
我只是使的 Java 中的上述表达式 能够直接转换,保持统一的编码样式,而不是通过其它形式的封装,大部分 ORM 框架,包括 Spark SQL, Flink SQL 等 SQL 编程都是通过函数来实现,例如:plus(a, b), minus(a, b) 等,这种形式会使得代码可读性极差。 |
66
lispczz 2020-12-12 14:49:36 +08:00
这个项目我挺喜欢。但是我想说,我已经在 V2EX 首页看到至少三次这个项目了,感受都快有点像知乎看到 圆胖肿 或者 微博看到 阚清子 了。
|
67
sagaxu 2020-12-12 14:54:52 +08:00 via Android
mybatis 不是 orm,只是个裸 query builder,选用它的人,大概率是嫌弃 orm 的,可能不需要一个更好的 orm 。
任何 dsl 都有学习成本,在 dsl 和 sql 之间来回翻译,需要对 dsl 内部非常熟悉,否则稍微复杂一点点的逻辑就会卡住不知道怎么下手。还有一些时候要用到 db 特有的功能,没有比裸写 sql 更简单的办法了。 |
68
Braisdom OP @lispczz 哈哈,现在才刚刚开始,项目已经初步的稳定,但未来的路还很长,需要更多的人认可,并能参与进来。
v2ex 是个很好的平台,是我在推广过程中,回复和评论最多的一个平台,与大家在一起讨论,收获颇多,感谢各位的支持,希望得到更多批评与挑战。 |
69
young1lin 2020-12-12 14:58:51 +08:00
主要是 MyBatis 是个会写 SQL 的人都能上手,JPA 和 Hibernate 比较难一点点,还有历史遗留问题。
|
70
felixin 2020-12-12 15:11:15 +08:00 via Android
怎么用函数呢?比如 postgres 里面的 json 操作函数,能给个例子看看吗
|
71
beidounanxizi 2020-12-12 15:12:42 +08:00
写过 Go 原生 和 gorm 以及 mybatis 最舒服 最 instinct 的还是原生的
不想用 orm 的原因是因为 写数据库的查询 用原生 sql 优化也方便 |
72
Braisdom OP @young1lin 这要去研究一下 SQL 和 ORM 的发展史了,你就能明白为什么会有 ORM 这种形式的框架,为什么数据库不像 TCP/IP,HTTP,SMTP 等交换协议一样,泛泛的讨论框架的区别没有太大意义,每个框架的出现代表一个时代的认知水平,人的认知随时间一直在变的。ObjectiveSQL 的出现也是基于前人的认知升级而已。
|
73
quan01994 2020-12-12 17:40:31 +08:00
下面的复杂表达式计算,现有的所有 ORM 框架都做不到。。
你是指 java 的 orm 吗。 C# 还是有很多能做到的。 |
74
kran 2020-12-12 17:53:01 +08:00 via Android
很喜欢这个项目。也很佩服楼主的技术和沟通能力。
就是没看懂那个运算符重载。。。 |
75
NeinChn 2020-12-12 18:10:47 +08:00
这不就是简单场景没必要,复杂场景学习成本高么
举个例子,我们线上数据库都是同一套,因此要做线上隔离全靠表名区别 以 members 为例,staging 环境的表名是 members_staging 你这个文档写的真的不清不楚,根本没办法通过文档决定怎么开发 简单看了下代码,DomainModel 的 tableName 或者 class 的 getSimpleName 。 那我一个 domain 用在多个表上还要搞 2 个类么? 真的有时间,建议完善下文档,至少做到 MyBatis 的文档水平,再做宣传。 想让别人做什么事情都看源代码解决是不现实的事情,有的是太菜看不懂源代码,有的是太忙没有时间花在读这种代码上。 |
76
Braisdom OP @quan01994 .net 的 entity framework 我参考了很多,表达式这块它可以做的,但有很多做了。
|
77
Braisdom OP @NeinChn 兄弟,不同部署环境应该通过数据库区分,例如:开发环境 development, 测试环境 test,生产环境 production, 我实在不明白,你为什么用表名去区分不同的部署环境,
|
80
Braisdom OP @NeinChn 我理解你的意思了,如果数据是暂时存储,一般通过内存数据库 Redis 类型的,如果是数据库的中间状态可以通过继承的方式存在,数据库中理论上不应该存在一模一样的表结构。
我的理解不一定正确,如果有问题,恳请你明示,感谢支持。 |
81
bbao 2020-12-12 22:48:04 +08:00
楼主的项目,经过线上项目以及压力的考验么?
|
82
Braisdom OP @bbao 我的项目刚上线 2 个月不到,以经有很多兄弟在尝试,应该没有商用项目在用。
你这问题很像一个刚毕业找工作的人被某一个公司问,你有工作经验吗?你应该能体会其中的含义 |
83
bbao 2020-12-13 00:30:50 +08:00
@Braisdom
朋友,你的攻击欲望挺强呀,你这应该不是第一次在 v2 里面推广自己的框架了,之前看到过,不容的别人说一点不好。 首先,推广自己的框架和思想是值得赞同的。 其次,开源框架和基础工具都是经过全方面的压力测试的,是被证实过的。 面试的时候没有工作经验,但是我可以有实习经验,项目经验,学习过程中的成果,拿得出来的结果来证明我「行」; 我的问题也就是想了解,你怎么证明你的框架「行」「能解决各种问题」「性能也能保证」 |
84
xcstream 2020-12-13 05:04:21 +08:00
我觉得拼装 sql 这种工作并不酷
感觉就像看别人都用手搬砖,我有新技巧用脚搬砖一样。 |
85
Braisdom OP @bbao 兄弟误会了,所有的批评和挑战我都乐意接受,所有项目都有开始的时候。
另外证明一个开源框架项目是否可以行,代码就是最好证明,总共加起来也没有多少行,如果我使用一个框架都不能理解代码和基础原理,我肯定不会用,所以证明我行不行,通过代码就可以。 估计兄弟应该没有看过我的项目,里面所各种数据库的 Example,看了 Example 就能证明能不能解决了。 |
86
quan01994 2020-12-13 09:23:13 +08:00
@Braisdom entityframework 还是差点,你可以去参考 linq2db 。这个是一个开源的第三方 orm,支持数据库函数,视图,自定义函数,等等。
|
87
Braisdom OP @quan01994 我看过,ObjectiveSQL 支持数据库函数,自定义函数,后期会支持内存表,视图没有必要支持
|
88
zypy333 2020-12-13 13:58:11 +08:00
现在有用这个工具搭的脚手架吗
|
90
zypy333 2020-12-13 14:23:42 +08:00
感觉很多新手接触 mybatis 都是直接从脚手架开始的,如果有的话可能会更方便推广吧,创意挺好的,希望未来能看到有很多落地的项目
|
91
Braisdom OP @zypy333 建议不错,如果是脚手架,也是 SpringBoot 或其它项目应用程序框架项目的脚手架,可以搞一个,哈哈
|
92
zhuangzhuang1988 2020-12-13 18:22:49 +08:00
还是 C# linq or F# query 好看
|
93
Braisdom OP @zhuangzhuang1988 是的,代码的简洁,美观很重要,而且不能只覆盖简单场景,复杂场景下也能适应。
|
94
mysunshinedreams 2020-12-14 00:47:50 +08:00
之前调研过 JOOQ,感觉 JOOQ 也挺好用,就是建模太重。
|
95
Braisdom OP @mysunshinedreams jooq 的设计想法很有创意,由于 java 的限制,无法发挥到极致
|
96
liuhuan475 2020-12-14 11:10:29 +08:00
想推荐自己的代码,不一定要攻击另一个
|
97
coderwl 2020-12-14 11:11:05 +08:00
这运算符重载的实现,IDE 不会一片飘红吗,如果非要这么灵活的 SQL DSL,用 ruby 的 active record 不香吗
|
99
Braisdom OP @liuhuan475 请看一下我前面的讨论,我只是客观的分析优缺点而已,每个项目能够留下来总有它存在的意义,也代表着一代程序员的认识水平。进步和发展的本身就是要推翻旧的技术,找他们的弱点进行攻击,不攻击,也就不存在进步和发展
|
100
Still4 2020-12-14 11:59:42 +08:00
如果涉及到联表怎么办,我自己搭建的框架里面也有类似的功能,查询条件通用化和规范化,重复逻辑也可以提取出通用方法,对外提供接口的时候也很方便,遵循相同的标准即可
但是联表就很痛苦,我现在没有好的解决办法只能是部分 sql 部分 model,返回数据的使用也比较蛋疼 |