其实,我更喜欢写 SQL

4 天前
 Joker123456789

此文章充满了个人的主观色彩,如果引起了大家的不适,那我也没办法。

其实,我更喜欢写 SQL ,如果在此基础上再稍微方便一些就更好了,所以,我理想中的持久层应该是这样的。

对于单表的增删改查

由于它不需要各种 join ,所以我们关心的只不过是字段,参数和条件而已,所以必须要有一种方式让我们只需要关注这三点,不需要去写那些固定模式的 SQL ,比如这样。

ParamPO paramPO = new ParamPO();
paramPO.setUserName("a");
paramPO.setUserEmail("test@qq.com");

int result = MagicDBUtils.get(jdbcTemplate).insert("表名", paramPO);

又或者这样

/ 构建查询条件
ConditionBuilder conditionBuilder = ConditionBuilder.createCondition()
            .add("id > ?", 10)
            .add("and (name = ? or age > ?)", "bee", 10)
            .add("order by create_time", Condition.NOT_WHERE);

// 执行查询
List<ParamPO> result = MagicDBUtils.get(jdbcTemplate).select("表名", conditionBuilder, ParamPO.class);

注意看上面的代码示例,他跟现有的框架有什么区别?答案就在这行

.add("and (name = ? or age > ?)", "bee", 10)

现有的框架如果要实现这样的条件是一件很头疼的事,而我们可以直接把查询条件写出来,不需要去 set 一堆对象。

其他框架只能很方便的实现这种(也许是我孤陋寡闻,如果说错了欢迎大家来拍砖)

.add("id > ?", 10)

这就是其他框架的写法,不仅没有我们灵活,而且还不够直观,需要能一眼看懂方法名是什么意思。大家可以把这段代码跟上面的那段比一比,哪段更直观简直不言而喻。

ImsCardGoodsExample.Criteria criteria = cardGoodsExample.createCriteria()
                .andIccidEqualTo(iccid) // 需要看懂英文 equal
                .andEndTimeLessThanOrEqualTo(new Date()); // 至于这句是什么意思?到底是>=还是<=,别装了,英文很好的程序员占比真不大

对于其他操作

由于需要各种统计,函数,join ,这个时候无论代码设计的多么出色都不可能有 SQL 灵活好用,而且我们几乎都会在 navicat 等各种客户端里写一遍 SQL ,验证成功了才会把他应用到程序里去。所以在这个场景下我个人认为没有什么方式比把 SQL 直接拷贝到程序里更方便的方式了,所以他必须能很友好的支持原生 SQL 。

比如查询

ParamPO paramPO = new ParamPO();
paramPO.setId(5);
paramPO.setUserName("a");

// 采用{}占位符的写法
List<ParamPO> result = MagicDBUtils.get(jdbcTemplate).selectList("select * from xt_message_board where id > {id} and user_name != {user_name}", paramPO, ParamPO.class);

// 采用 ? 占位符的写法
List<ParamPO> result = MagicDBUtils.get(jdbcTemplate).selectList("select * from xt_message_board where id > ? and user_name != ?", new Object[]{5, "a"}, ParamPO.class);

又或者增删改

ParamPO paramPO = new ParamPO();
paramPO.setUserName("testTx222");
paramPO.setUserEmail("testTx222@qq.com");
paramPO.setId(4);

// 采用{}占位符的写法
int result = MagicDBUtils.get(jdbcTemplate).exec("update xt_message_board set user_name = {user_name} , user_email = {user_email} where id = {id}", paramPO);

// 采用 ? 占位符的写法
int result = MagicDBUtils.get(jdbcTemplate).exec("update xt_message_board set user_name = ? , user_email = ? where id = ?", new Object[]{"testTx222","testTx222@qq.com", 4});

分个页而已,有没有必要引入三方插件啊?

简简单单一句话搞定,当然了,只支持 mysql 哈,为什么不支持别的?因为我懒(其实是大部分公司都不舍得买 oracle ,db2 等数据库,所以我觉得这个懒可以偷)

// 查询条件
ParamPO paramPO = new ParamPO();
paramPO.setId(5);
paramPO.setUserName("a");

// 查询参数
PageParamModel pageParamModel = new PageParamModel();
pageParamModel.setCurrentPage(1);
pageParamModel.setPageSize(10);
pageParamModel.setParam(paramPO);// 把查询条件 set 进去

// 使用默认 countSql 查询
PageModel<ParamPO> pageModel =  MagicDBUtils.get(jdbcTemplate).selectPage("select * from xt_message_board where id > {id} and user_name != {user_name}", pageParamModel, ParamPO.class);

// 使用自定义 countSql 查询
String countSql = "自己定义 countSql";

PageModel<ParamPO> pageModel =  MagicDBUtils.get(jdbcTemplate).selectPageCustomCountSql("select * from xt_message_board where id > {id} and user_name != {user_name}", countSql, pageParamModel, ParamPO.class);

SQL 写在代码里很难看?

现在已经 2024 年的年底了,90 年出生的程序员都已经达到 35 岁退休的年龄了,所以不要再守着 JDK8 过日子了,试一试 JDK17

String sql = """
             select 
                 id,name,age,create_time
             from 
                 user_info
             where 
                 name = {name} and age > {age}
            """;

最重要的是

它只不过是对 Spring 的 JdbcTemplate 做了一个小小的扩展,也就是这玩意儿

@Resource
private JdbcTemplate jdbcTemplate;

所以稳定性,各方面都不用担心,而且使用起来超级方便,也就是说你只需要在 https://start.springboot.io 网站建立一个 springboot 项目,然后再添加一个依赖就好了,不需要去查阅 mybaits 怎么整合,分页插件怎么整合等一堆事。

所以你们打算尝试一下吗?

项目官网:https://magician-io.com

6739 次点击
所在节点    Java
67 条回复
spritecn
3 天前
写在 xml 里是真的很难看,xml 的判断逻辑还有坑
Cbdy
3 天前
写 SQL 确实不错
marcong95
3 天前
andIccidEqualTo andEndTimeLessThanOrEqualTo 这两个方法的槽点竟然在 equal/less/greater 上??
Akitora
3 天前
这就是我喜欢 kt 的 ORM 的地方,比如 ktorm ,非常直观

https://www.ktorm.org/images/ktorm-example.png
AlexHsu
3 天前
orm 确实蠢逼 出问题了 debug 先到控制台找 sql 然后解决 sql 的问题 在回到 orm 里面反推代码怎么改
然而他们号称解决的代码复用 数据库不相关的好处 实际上又能提现多少呢 一个项目天天来回引用 orm 层?还是天天换数据库玩。。
wanguorui123
3 天前
终极 ORM 还是 C#的 EntityFramework 配合 LINQ+DataSet 方便快捷
a194259440
3 天前
当 JAVA 还在为这些烦恼的时候,dotnet 的 Linq 已经普及多年了
zoyao
3 天前
但是直接 sql 会存在不同数据库的兼容问题
dododada
3 天前
很多年前,师兄去给移动解决一个联合查询问题,咨询了 oracle 的工程师之后,搞了一个 3000 多行的 sql 出来,伙伴们只觉得震撼,后来工作了才知道这东西有多麻烦;
oracle 的咨询电话太贵了,当年一小时 1800 ,现在不知道还有哪些行业在用
cheng6563
3 天前
我也喜欢写楼主这种简单需求
zysuper
3 天前
现在是都是 cursor 帮我写全栈代码,我只是个测试和提问者。
WDATM33
3 天前
@zoyao 简单 多写几个不同数据库的实现类 根据读取配置文件动态加载对应的实现类注入就行
fantasy0v0
3 天前
我也喜欢直接写 sql ,于是我也搞了个类似的,https://github.com/fantasy0v0/swift
平时工作就是 jooq + swift-jdbc ,配合使用。
kangkkk
3 天前
我也喜欢直接写 sql ,简洁高效。
lyxxxh2
3 天前
我相反,orm 重度患者。
altwei
3 天前
无论写什么,只要写的规范就行。特别是复杂语句,适当的格式化,而不是一把梭
bingo084
3 天前
@Belmode #2 可以了解一下 Jimmer ,这个是我认为目前的极限 https://babyfish-ct.github.io/jimmer-doc/zh/
qq135449773
3 天前
ConditionBuilder.createCondition() 这个 API 我觉得封装的太丑了。

可以考虑把算子封装到 Java 操作上(比如 `.le(field, value)` 、 `.gt(field, value)` 这种形式)

单说这个 ConditionBuilder 我觉得这种混写 SQL 和 Java 代码无论是美观易用性还是后期维护的成本都稍微有点大了。
june4
3 天前
我自己的 node 后端的 orm 也是自己写的,主打一个简洁直白。
主要设计就是一个模型类系统(定义类/字段/索引,并可自动生成表创建 sql,我可不想手动同步创建表 sql 和代码模型类), 一套查询系统,查询出来的数据 row 直接是对应的模型类的实例。
不搞复杂的自动多表关联系统,因为用处很少还复杂,真有需要时手动处理就行了。
查询系统有覆盖 95%需要的简单的对象方式查询,有需要再直接提供 sql ,毕竟 sql 缺点是没有类型约束这。
整个系统除了直接提供 sql 部分其它都有类型约束,orm 整个只需要 1000 行。
用了很多年,简直太舒服了,以前用那些复杂的 orm 时老是要查 api ,有时还要打印 sql 出来看看到底干了什么,现在因为 orm 太简单到写代码完全不会有任何疑问的地方。
gejun123456
3 天前
@YUyu101 java 可以试试 idea+mybatis+MybatisCodeHelperPro 插件,在写条件 sql 的时候也有代码提示 https://brucege.com/doc/#/typeSafe

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

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

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

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

© 2021 V2EX