你好@jdbi团队 :)
在 JDBI v2 中,我们使用这样的结构:
@SqlQuery("SELECT COUNT(*) FROM account a WHERE <where>")
int count(@Define("where") String where, <strong i="8">@BindMap</strong> Map<String, Object> params);
where
正在运行时构建。 在某些情况下它是空的(只是1 = 1
),在某些情况下它包含用户在 GUI 过滤器上提供的一些值。 例如:
SELECT COUNT(*) FROM account a WHERE 1 = 1;
和:
where = '1 = 1'
params = { }
或者:
SELECT COUNT(*) FROM account a WHERE 1 = 1 AND a.status = :status;
当用户在 GUI 过滤器中提供状态时:
where = '1 = 1 AND a.status = :status'
params = { status = 2 }
现在,当提供空的params
参数时,这会引发异常。 例如:
com.vividgames.swim.akka.exception.MessageProcessingException: org.jdbi.v3.core.statement.UnableToCreateStatementException: Superfluous named parameters provided while the query declares none: '{positional:{}, named:{}, finder:[{}]}'. [statement:"SELECT count(*) FROM test t WHERE <where>", rewritten:"/* templated */ SELECT count(*) FROM test t WHERE value > 0", parsed:"ParsedSql{sql='/* CountDao.count */ SELECT count(*) FROM `dev-abc.1`.test t WHERE value > 0', parameters=ParsedParameters{positional=false, parameterNames=[]}}", arguments:{positional:{}, named:{}, finder:[{}]}]
at org.jdbi.v3.core.statement.ArgumentBinder.bindNamed(ArgumentBinder.java:58)
at org.jdbi.v3.core.statement.ArgumentBinder.bind(ArgumentBinder.java:29)
at org.jdbi.v3.core.statement.SqlStatement.internalExecute(SqlStatement.java:1429)
at org.jdbi.v3.core.result.ResultProducers.lambda$getResultSet$2(ResultProducers.java:68)
at org.jdbi.v3.core.result.ResultIterable.lambda$of$0(ResultIterable.java:53)
at org.jdbi.v3.core.result.ResultIterable.findFirst(ResultIterable.java:116)
at org.jdbi.v3.sqlobject.statement.internal.ResultReturner$CollectedResultReturner.mappedResult(ResultReturner.java:266)
at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.lambda$configureReturner$0(SqlQueryHandler.java:54)
at org.jdbi.v3.sqlobject.statement.internal.CustomizingStatementHandler.invoke(CustomizingStatementHandler.java:155)
at org.jdbi.v3.sqlobject.statement.internal.SqlQueryHandler.invoke(SqlQueryHandler.java:26)
at org.jdbi.v3.sqlobject.SqlObjectFactory.lambda$null$13(SqlObjectFactory.java:163)
at org.jdbi.v3.core.ConstantHandleSupplier.invokeInContext(ConstantHandleSupplier.java:52)
at org.jdbi.v3.sqlobject.SqlObjectFactory.lambda$createInvocationHandler$14(SqlObjectFactory.java:162)
我在SqlStatements
找到了一个标志,可用于允许未使用的绑定:
/**
* Sets whether or not an exception should be thrown when any arguments are given to a query but not actually used in it. Unused bindings tend to be bugs or oversights, but can also just be convenient. Defaults to false: unused bindings are not allowed.
*
* <strong i="32">@see</strong> org.jdbi.v3.core.argument.Argument
*/
public SqlStatements setUnusedBindingAllowed(boolean allowUnusedBindings) {
this.allowUnusedBindings = allowUnusedBindings;
return this;
}
但是我找不到任何使用此方法的方法:( 在 JDBI 源代码中,我只找到了用法,但没有找到设置它的地方。
我可以重写我们的 DAO 并引入不需要params
新方法,例如:
@SqlQuery("SELECT COUNT(*) FROM account a")
int countAll();
@SqlQuery("SELECT COUNT(*) FROM account a WHERE <where>")
int countFiltered(@Define("where") String where, <strong i="38">@BindMap</strong> Map<String, Object> params);
但这必须在许多现有的 DAO 中完成,老实说,我宁愿更改一行并神奇地使其再次工作。
您必须在创建 SqlObject 的 Jdbi/Handle 上设置标志。
jdbi.useHandle(h -> {
Dao dao = h.configure(SqlStatements.class, stmts -> stmts.setUnusedBindingAllowed(true))
.attach(Dao.class);
});
据我所知,没有像@AllowUnusedBindings
这样的自定义注释的语句来做到这一点。 如果你真的想要,可以很容易地做出贡献。
嗨@TheRealMarnes ,
您的代码完美运行 :) 谢谢!
我认为这可以在 www 或setUnusedBindingAllowed
javadoc 中的 JDBI 文档中进行描述(因为这些是我开始研究如何使用它的第一个地方)。
我不知道如何编辑文档,但如果您愿意,我可以更新 javadoc。
你是对的,手册没有提到它。 也许例外也应该提到它。
我不知道你为什么把 javadoc 说成是缺乏的; 你真的粘贴了javadoc,所以它存在。
如果你想开始一个关于它的手册部分,手册文件是index.adoc
。 它是用 asciidoc 写的,当你阅读它时,它真的解释了它自己,它有点像降价。 我从来没有真正学过它,但我一直在写手动部分很好:) 任何 IDE 还应该为您提供实时预览。
@TheRealMarnes ,
谢谢你。 会看看指数。
关于:
我不知道你为什么把 javadoc 说成是缺乏的; 你真的粘贴了javadoc,所以它存在。
是的,它就在那里,但它只描述了可以直接从代码中读取的内容。 特别是它没有描述如何配置它,这是这个问题的核心点。 我在代码中找到了该方法,我阅读了 javadoc,但这就是全部,并且在代码中挣扎了一段时间,寻找用法等之后,我不得不向你们寻求帮助。 如果在此 javadoc 中引用/提及handle.configure
方法(最好有示例),它将大大增加其在理解如何启用此特定功能方面的价值。
我认为你错过了更大的图景。 handle.configure
是Configurable
对象(如 Jdbi 和 Handle(以及getConfig
)上的所有配置的标准配置),这并不是特别的东西。 allowUnusedBindings
需要一个布尔值,只有它应该很明显。 调用方法及其传播方式遵循我们的标准配置范例。
嗯,确实,我似乎错过了它,但其他用户可能也错过了它。 在我看来,对于核心开发人员来说,它是一种非常先进的 _tribal_ 知识,但对于我们这里的野外人员来说并不那么明显。 在你将它描述为一个_标准配置范式_之后,我去做了 JDBI 文档,在阅读了关于配置的内容之后,我仍然对它的工作原理有一个简单的了解。 configure
方法仅用于设置 Vavr 的TupleMappers
。
这是一个更大问题的一部分,文档中并未详细描述所有功能,但我们,JDBI 用户,在这里帮助指出缺失的内容并帮助填补空白。
因此,我建议更改 javadoc 以包含更多详细信息,例如:
/**
* Sets whether or not an exception should be thrown when any arguments are
* given to a query but not actually used in it. Unused bindings tend to be bugs or
* oversights, but can also just be convenient. Defaults to false: unused bindings
* are not allowed.<br>
* <br>
* It can be changed by configuring {<strong i="10">@link</strong> Configurable} object (e.g. {<strong i="11">@link</strong> Jdbi}
* or {<strong i="12">@link</strong> Handle}), for example:
* <pre>
* handle.configure(SqlStatements.class, s -> s.setUnusedBindingAllowed(true))
* </pre>
*
* <strong i="13">@see</strong> org.jdbi.v3.core.argument.Argument
* <strong i="14">@see</strong> Handle.configure
* <strong i="15">@see</strong> Jdbi.configure
*/
我很乐意添加它,但如果我写的没问题,请告诉我。
今天早上我自己也遇到了同样的缺陷。 我将准备一个 PR,在 sqlobject 上添加@AllowUnusedBindings
。
部落知识对核心开发人员来说显而易见,但对我们来说在野外并不那么明显
我只想指出,我是核心成员,因为只有 2 个月左右,而在那之前我只是像你一样的普通用户一年多,所以我并不精通神秘的知识。 😛 我知道我所知道的关于 jdbi 的大部分事情,因为我处于相同的情况,只是探索和点击 API 和接口,让 Intellij 向我提示方法等等。
但是是的,它应该被清楚地记录下来,因为我们不能指望每个人都检查 jdbi 的内部来找出基本用法。 :)
我认为我们不会按照您建议的方式添加 javadoc。 配置咒语应该单独说明,而不是在每一个配置设置中重复或包含在任何一个特别选择的配置设置中。 每个配置设置应该只解释它自己的效果。
我们有一个关于JdbiConfig
: http :
我正在阅读JdbiConfig
并且我也有同样的印象。 在@TheRealMarnes给我一个他在评论中提供的例子之后,事情就
谢谢你的@AllowUnusedBindings
:)
伙计们,我知道这是反对将配置范式记录在一个地方,但请考虑在异常消息中添加信息,就像在这里完成的一样:
这将节省一个被此异常击中的人大量挖掘代码:)
我非常同意,例外本身应该暗示它。
@TheRealMarnes提示添加到https://github.com/jdbi/jdbi/pull/1428
我们已经向错误消息添加了提示,以及以此作为特定示例的一般配置文档。 希望这是一个足够的修复; 感谢使用 jdbi :)
谢谢史蒂文! 小心 :)
最有用的评论
我正在阅读
JdbiConfig
并且我也有同样的印象。 在@TheRealMarnes给我一个他在评论中提供的例子之后,事情就谢谢你的
@AllowUnusedBindings
:)