从实用程序方法返回PreparedStatement是否是良好的实践?

4

我正在处理一个继承而来的庞大的Java代码库,其中许多不同的方法以令人疯狂的方式查询数据库;在我进行调试和标准化一切的过程中,我编写的大部分代码最终看起来都像这样:

log.info("Audit-required logging for query: "+SOME_QUERY);
log.info("Ditto for each argument: "+parameter+" "+otherParameter+ ...);
ps = conn.prepareStatement(SOME_QUERY);
ps.setString(1, aString);
ps.setString(2, anotherString);
// ... 
ps.setString(14, yetAnotherString);
rs = ps.executeQuery();
log.debug("Query executed: "+SOME_QUERY);

我讨厌要三次写下查询和两次参数(还要为每个参数做setString())——这是未来维护时出现错误的食谱。我宁愿将所有内容放在一个(静态的)通用方法中,这样我只需要说一次就可以了(并且可以为代码库未来提供保障,以防需要执行其他操作...比如法律部门需要不同类型的日志记录或者需要新的错误处理方式)。像这样:

public static PreparedStatement fullyPrepare(final Connection conn, final String query, final String... arguments) { ... }

我将使用一句话来调用它(而不是每次使用整个代码块):
ps = fullyPrepare(conn, CONSTANT_FOR_THIS_QUERY, parameter, otherParameter, ...);

然而,基于“这是不好的实践”的想法,我发现有人反对。我一直在尝试阅读相关内容,但我找不到任何关于从准备它的方法返回PreparedStatement是好还是坏的做法的说明(与处理ResultSet对象不同,例如在Is it Ok to Pass ResultSet?线程中)。

为什么我的预期PreparedStatement准备者会是一个不好的想法?


1
你可能想要检查像DbUtilsjdbc-helperjdbi这样的库。它们可以完成你在问题中展示的所有工作,并且在你不需要/不想使用整个ORM系统(如Hibernate、MyBatis、jooq等)时非常好用。(编辑:修复了jdbc-helper链接,改为我想要的那个,而不是Jruby的链接) - Olivier Grégoire
2个回答

3

这样做是个极好的主意。

为什么呢?因为你把PrepareStatement创建集中在一个地方,让你的同事更容易阅读你的代码。如果有 bug,只需要在一个地方修复而不是到处都修。

这个想法是如此优秀,以至于有几个框架甚至专门为此而设计。我在评论中提到了 DbUtilsjdbc-helperjDBI。还有其他的,例如jcabi-jdbc,或者流行的JOOQ。当然,它们并不都是完全活跃的(jdbc-helper 甚至可能已经停止维护了),但它们仍然被用在生产项目中。

你提到的这种情况,也可能取决于你使用的数据库层,因为有些数据库对于输入的空列表或简单的null值可能有不同的期望值(我在看着你,Oracle!)。因此,我强烈建议使用这些库,而不是编写自己的实用方法。jDBI 是我的首选,因为它是目前正在积极开发的。


2

由于PreparedStatement绑定到Connection对象上,因此需要同步才能在多个方法中访问,这将限制您的多用户性能。

有关更多信息,请参见:重用PreparedStatement在方法之间?


2
我认为楼主并不是在谈论重复使用语句。 - Chetan Kinger
是的,但问题是在谈论当您不再拥有PreparedStatement局部于一个方法的情况下。它在一个地方被创建并传递到另一个方法。这就是我的关注点。 - sharath

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接