其实,我更喜欢写 SQL

42 天前
 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

7840 次点击
所在节点    Java
67 条回复
mumbler
42 天前
@kongkongye #17 cursor
mayerer
42 天前
首先就要夸赞一下 OP 帖子的排版 很优秀
dogfeet
42 天前
个人不太喜欢裸 sql 的方式,因为喜欢改字段名,再就是参数类型 时间字符串数值要不停的记住。裸 sql 对测试代码的覆盖率的要求更高。
majula
42 天前
虽然我也不喜欢用 ORM ,但是举的例子有点牵强

真的有程序员看不懂 LessThanOrEqualTo 么,小学英语都可以重修了
EastLord
42 天前
哥们,我看过你好几次了 推广你的项目
codingmiao
42 天前
简单的 crud 丢给 orm 框架很省事,复杂一点的查询本来就要和负责数据的同事去沟通、验证、调整,得到一个符合业务要求的 sql ,这时候再把 sql 翻译回 orm 框架的代码属实没必要
RedBeanIce
42 天前
我非常喜欢楼主的这种写法。。

如果可以下面这样子,就更好了(很抱歉,可能是一种无聊的想法)

```
ConditionBuilder conditionBuilder = ConditionBuilder.createCondition()
.add(ParamPO::id).then(">").(10);
``
wu00
42 天前
重度 ORM 患者
非必要不连表
复杂报表抽数据
adoal
42 天前
把功能齐全的关系数据库仅仅当一堆表用,做单表 crud ,或者少量几个表之间做一层直接匹配的关联查询,其实用 ORM 和直接写 SQL 也没啥区别。用 MySQL 这种残疾货跟用 Oracle 也没啥区别。

ORM 搞不定的是那种,很多老式的业务系统,业务逻辑有很大一部分写在 SQL 里,子查询、窗口函数、触发器、存储过程、CTE 甚至递归 CTE……老式系统里,可能没有 B/S 结构,是 C/S 的,本机运行的 exe 客户端直连数据库,主要是起 UI 的作用……当然,也可以 B/S 方式用 WebUI ,但跟现在互联网流派的架构还是有很大区别的。虽然从互联网生态出来的架构师鄙视和抵制这种架构,但……其实没有绝对的谁先进谁落后,根本上还是有锤皆钉吧。
bthulu
42 天前
为什么不用 Linq 或者 efcore?完美满足 sql 党和非 sql 党的需求
YUyu101
42 天前
@gejun123456 你的这个插件确实是我体验过最好的 mybatis 插件。
ala2008
42 天前
原生 sql 的写法,在旧的项目很难维护,而且还有 sql 注入风险
james122333
42 天前
@ala2008

哪有什么注入... 如果 connector 实现正常不会有问题
corcre
42 天前
@bthulu 还记得当年在老项目查 bug 的时候第一次见到 linq, 让我这个没学过 linq 的新手看着几百行代码四层嵌套的语句找一个小问题, 当时我真的想还不如让我看 SQL🐶🐶🐶(当然, 到现在还是不咋会 linq
james122333
42 天前
@ala2008

Prepare statement 也都是 sql 内建功能
就算没有该功能还是有方法一劳永逸
真有问题是通杀
leonhao
42 天前
我更喜欢写存储过程
ftsland
42 天前
@bthulu 因为 java 没有
bthulu
42 天前
@ftsland 那就换掉啊, 别在一种语言上吊死, 写复杂业务用 java 哪有 C#来的方便
spritecn
42 天前
@ftsland groovy 有..但 java8 后 groovy 存在的意义就不怎么大了
Rehtt
42 天前
golang 的 gorm 也可以这样 db.Table("A").Where("name = ? AND age > ?",name,age).Find()

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

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

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

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

© 2021 V2EX