我一直都是一个 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
liprais 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 应该也能实现出来的。
|