我一直都是一个 SQL 派,所以我开发了这个框架, 但我也不是愚昧的排斥无 sql 操作,所以在项目中,单表的操作不需要写 sql ,但是多表 或者 复杂的操作 还是以 sql 为准。
自从 springboot 出来后,war 包就进入历史了,现在流行的方式是 打 jar 包,这就有点意思了,一旦打了 jar 包 就意味着 mybatis 的 xml 文件也会被打进 jar 包,这种情况下 如果要改 sql 就必须去找源码; 就算是 war 包年代,也不可能直接改线上,肯定还是从源码开始修改,经过正规的一套流程后 才能上线。
所以,把 sql 写在文件里的这种形式,我个人认为 意义已经非常弱了,基于这样的考虑,所以我没支持 xml ,而是直接在代码里写 sql 。
这里大家肯会有疑问,那就是如何解决 用 StringBuilder 时,append 太多的情况,其实这个问题 JDK 已经帮解决了,从 JDK14 开始,就支持了这种语法:
String sql = """ 可以把多行的字符串写在这里 可以把多行的字符串写在这里 可以把多行的字符串写在这里 可以把多行的字符串写在这里 """
现在 虽然 jdk8 的钉子户还很多,但是 未来肯定会用上 14 ,甚至是 17,18,19,20 ,只是早晚的问题。
废话不多说,直接上示例
ParamPO paramPO = new ParamPO(); paramPO.setUserName("a"); paramPO.setUserEmail("[email protected]"); int result = JDBCTemplate.get().insert("表名", paramPO);
// 构建修改条件 List<Condition> cOnditionList= ConditionBuilder.createCondition() .add("id = ?", 10) .add("and name = ?", "bee")) .build(); // 构建修改数据 ParamPO paramPO = new ParamPO(); paramPO.setUserName("a"); paramPO.setUserEmail("[email protected]"); // 执行修改 int result = JDBCTemplate.get().update("表名", paramPO, conditionList);
// 构建删除条件 List<Condition> cOnditionList= ConditionBuilder.createCondition() .add("id = ?", 10) .build(); // 执行删除 int result = JDBCTemplate.get().delete("表名", conditionList);
// 构建查询条件 List<Condition> cOnditionList= ConditionBuilder.createCondition() .add("id > ?", 10) .add("and (name = ? or age > ?)", "bee", 10)) .add("order by create_time", Condition.NOT_WHERE)) .build(); // 执行查询 List<ParamPO> result = JDBCTemplate.get().select("表名", conditionList, ParamPO.class);
ParamPO paramPO = new ParamPO(); paramPO.setUserName("testTx222"); paramPO.setUserEmail("[email protected]"); paramPO.setId(4); // 采用{}占位符的写法 int result = JDBCTemplate.get().exec("update xt_message_board set user_name = {user_name} , user_email = {user_email} where id = {id}", paramPO); // 采用 ? 占位符的写法 int result = JDBCTemplate.get().exec("update xt_message_board set user_name = ? , user_email = ? where id = ?", new Object[]{"testTx222","[email protected]", 4});
ParamPO paramPO = new ParamPO(); paramPO.setId(5); paramPO.setUserName("a"); // 采用{}占位符的写法 List<ParamPO> result = JDBCTemplate.get("dataSource").selectList("select * from xt_message_board where id > {id} and user_name != {user_name}", paramPO, ParamPO.class); // 采用 ? 占位符的写法 List<ParamPO> result = JDBCTemplate.get("dataSource").selectList("select * from xt_message_board where id > ? and user_name != ?", new Object[]{5, "a"}, ParamPO.class);
/ 查询条件 ParamPO paramPO = new ParamPO(); paramPO.setId(5); paramPO.setUserName("a"); // 查询参数 PageParamModel pageParamModel = new PageParamModel(); pageParamModel.setCurrentPage(1); pageParamModel.setPageSize(10); pageParamModel.setParam(paramPO); // 使用默认 countSql 查询 PageModel<ParamPO> pageModel = JDBCTemplate.get().selectPage("select * from xt_message_board where id > {id} and user_name != {user_name}", pageParamModel, ParamPO.class); // 使用自定义 countSql 查询 String countSql = "自己定义 countSql"; PageModel<ParamPO> pageModel = JDBCTemplate.get().selectPageCustomCountSql("select * from xt_message_board where id > {id} and user_name != {user_name}", countSql, pageParamModel, ParamPO.class);
// 开启事务 TransactionManager.beginTraction(); try { ParamPO paramPO = new ParamPO(); paramPO.setUserName("testTx222"); paramPO.setUserEmail("[email protected]"); paramPO.setId(4); int result = JDBCTemplate.get().exec("update xt_message_board set user_name = {user_name} , user_email = {user_email} where id = {id}", paramPO); // 提交 TransactionManager.commit(); } catch(Execption e){ // 回滚 TransactionManager.rollback(); }
![]() | 1 brust 2022-03-04 18:01:52 +08:00 就我觉得很奇怪吗 |
![]() | 2 Saurichthys 2022-03-04 18:04:05 +08:00 你这是实现一个类似 mybatis 的 querywrapper 功能,说实话没有什么特别之处啊 |
![]() | 3 F281M6Dh8DXpD1g2 2022-03-04 18:05:58 +08:00 prepared statement 都不用...... |
4 py2ex 2022-03-04 18:09:40 +08:00 8 的钉子户报到 |
5 9c04C5dO01Sw5DNL 2022-03-04 18:21:06 +08:00 “一旦打了 jar 包 就意味着 mybatis 的 xml 文件也会被打进 jar 包” 但凡用 maven assembly 等插件配置一下,都不至于把 xml 也打进 jar 包。 |
![]() | 6 pocketz 2022-03-05 09:51:19 +08:00 是我孤陋寡闻了。。。现在嵌入式 tomcat 用的这么普遍吗 |
![]() | 7 ldyisbest 2022-03-05 11:49:20 +08:00 看着感觉和 mybatis 的 example 差不多 |
![]() | 8 msg7086 2022-03-05 11:53:30 +08:00 唔,恭喜你重新发明了半个 ORM ? |
![]() | 9 msg7086 2022-03-05 12:18:20 +08:00 最理想的做法应该是根据输入数据构建 AST 然后把 AST 变形转换成对应的 SQL 语句,这是一般 ORM 的做法。 你这个只是做了一个 StringBuffer 在那拼字符串。 而且这么核心的组件没有基本的测试覆盖,是不是太草率了一些…… (我十几年前倒是在 PHP4.4 上做过类似的项目,在 ADOdb 上面包一层字符串处理。可这都已经 2022 年了……) |
10 a0210077 2022-03-05 17:58:23 +08:00 “自从 springboot 出来以后,war 包就进入历史了,现在流行的方式是 打 jar 包,这就有点意思了,一旦打了 jar 包 就意味着 mybatis 的 xml 文件也会被打进 jar 包,这种情况下 如果要改 sql 就必须去找源码; 就算是 war 包年代,也不可能直接改线上,肯定还是从源码开始修改,经过正规的一套流程后 才能上线。” |
11 a0210077 2022-03-05 18:03:30 +08:00 这里不用 xml 的理由非常牵强,同意我 @giiiiiithub #5 说的,用 maven ,想怎么打包都可以 |
![]() | 12 Joker123456789 OP @liprais 你确定不是你眼花了? |
![]() | 13 Joker123456789 OP @msg7086 ast 确实高端一点,但是 stringBuffer 也没什么 致命的弱点吧。 |
![]() | 14 Joker123456789 OP @a0210077 确实....... , 但是 我最后还有一句:线上不可能让你直接改的,你还是要回去改源码,然后 经过一套流程 才能上线。 我个人认为,配置文件 是 外包界的产物, 去客户现场 安装 调试等,改起来方便。 对于自研的公司,配置文件存在的意义 只是一个归纳整理。 按照环境拆分,统一配置中心等 都不是非文件不可的。 |
![]() | 15 Joker123456789 OP @pocketz 是的,非常普遍,因为 几乎都在用 springboot 。 然后.... 我用的是嵌入式 netty |
![]() | 16 Joker123456789 OP @Saurichthys 确实是的,用法上没什么特别的。 但是因为我是一个 sql 派,所以 这种写法 // 构建查询条件 List<Condition> cOnditionList= ConditionBuilder.createCondition() .add("id > ?", 10) .add("and (name = ? or age > ?)", "bee", 10)) // 这里是一个条件的组合 .add("order by create_time", Condition.NOT_WHERE)) .build(); 我觉得比这种写法更容易上手 QueryWrapper queryWrapper = new QueryWrapper(); queryWrapper.eq("id", 10); 因为前者是 原生 sql ,学习成本几乎为 0 ,而且 组合条件 也很好写。 而后者 需要熟练的记住 eq, lt, ge 等方法的意思。 而且我这个 jar 包非常小,很小很小, 连源码都没几个类。 |
![]() | 17 msg7086 2022-03-07 15:39:18 +08:00 StringBuffer 意味着你只能以真正 SQL 的方式去写查询。 如果用 AST 或者类似的技术,则不需要遵循 SQL 的顺序,也不需要逼着用户去加生硬的「 and 」。 举个简单的例子: bob = User.where(email: "[email protected]").where(active: true) # => SELECT "users".* FROM "users" WHERE "users"."email" = '[email protected]' AND "users"."active" = 't' details = User.select(:id, :email, :first_name).order(id: :desc) # => SELECT "users"."id", "users"."email", "users"."first_name" FROM "users" ORDER BY "users"."id" DESC bob.merge(details).first # => SELECT "users"."id", "users"."email", "users"."first_name" FROM "users" # WHERE "users"."email" = '[email protected]' AND "users"."active" = 't' # ORDER BY "users"."id" DESC LIMIT 1 这里的这种 bob.merge(details).first 的用法可以让代码变得非常干净且易于维护。 你可以提前列出所有可能的查询条件,然后在最后一步根据输入参数或者具体需求进行拼装。 |
18 coderwl 2022-03-07 18:19:52 +08:00 建议直接使用 jooq |
![]() | 20 msg7086 2022-03-08 13:40:21 +08:00 via Android @lichao 概念是类似的,不是添加字符串而是添加成 ast 然后从 ast 构建语句。我相信就算 Java 应该也能实现出来的。 |