如何在源代码中处理巨大的SQL字符串

我正在开发一个项目,目前代码中有大约3000行的SQL字符串。

该项目是一个java项目,但这个问题可能适用于任何语言。

无论如何,这是我第一次看到这么糟糕的事情。 代码库是遗留的,所以我们可以突然迁移到Hibernate或类似的东西。

你如何处理这样的非常大的SQL字符串?

我知道它很糟糕,但我不确切地知道建议解决方案的最佳方法是什么。

在我看来,将这些硬编码的值转换为存储过程并从代码中引用sprocs可能是高产量和低工作量。

SQL是否有很多变量的字符串连接?

如果没有,你可以提取它们将它们放在资源文件中。 但是你必须删除换行符中的字符串conatentation。

您使用的存储过程方法非常好,但有时当需要了解SQL正在执行的操作时,您必须从工作区切换到您喜欢的SQL IDE。 那是唯一的坏事。

对于我的建议,它将是这样的:

String query = "select ......."+ 3000 lines. 

 ResourceBundle bundle = ResourceBundle.getBundle("queries"); String query = bundle.getString( "customerQuery" ); 

那就是这个想法。

我想第一个问题是,你应该怎么做呢? 如果它没有被打破,请悄悄地将它关闭并假装你从未见过它。 否则,重构就像疯了一样 – 希望某些退出条件看起来像合同。

到目前为止,我能想出的最好的事情是将查询放入几个存储过程,就像我在Java中处理一个太长的方法一样。

我和你在同一个地方…我的计划是将SQL拉入项目中的separate.sql文件,并创建一个实用工具方法,在我需要查询时读取文件。

 string sql = "select asd,asdf,ads,asdf,asdf," + "from asdfj asfj as fasdkfjl asf" + "..........................." + "where user = @user and ........"; 

查询将被转储到名为usageReportByUser.sql的文件中
而变成这样的东西。

 string sql = util.queries("usageReportByUser"); 

确保以文件不可公开访问的方式完成。

使用框架iBatis

我曾经为此写了一个工具包 ,并在几个项目中使用过它。 它允许您将查询放在大多数文本文件中,并为它们生成绑定和文档。

查看这个示例和一个示例用法 (它几乎只是编译为具有早期绑定/类型安全查询绑定的java类的预准备语句)。

它也会生成一些不错的javadoc,但我目前还没有任何在线版本。

我是第二个iBatis推荐。 至少,您可以从最可能使用StringBuffer的Java代码中取出SQL,并将String concat追加到XML中,这样可以更容易维护。

我为遗留的Web应用程序做了这个,我打开调试并运行DAO的unit testing,并将生成的每个语句的sql复制到iBatis xml中。 工作得相当顺利。

我在PHP中做的是:

 $query = "SELECT * FROM table WHERE "; $query .= "condition < 5 AND "; $query .= "condition2 > 10 AND "; 

然后,一旦你在$query上完成分层:

 mysql_query($query); 

一种简单的方法是将它们分解成某种常量。 这至少会使代码更具可读性。

我将它们存储在文件(或资源)中,然后在应用程序启动时读取并缓存它们(如果它是服务或其他东西,则更改)。

或者,只需将它们放入一个大的旧SqlQueries类中作为consts或readonlys。

我已成功将大型动态查询转换为linq查询。 (1K行+)这适用于在相对较少的表上进行大量动态过滤和动态分组的报告场景。 为这些表创建一个edmx,您可以编写出色的强类型可组合查询。

我发现性能实际上得到了改善,结果sql更加简单。 我相信你会得到与Hibernate类似的里程 – 除了能够使用linq ofcourse。 但一般来说,如果生成的sql需要高度动态,那么它就不是存储过程的良好候选者。 在存储过程中编写动态sql是两个世界中最糟糕的。 sql生成框架将是我首选的方式。 如果你挖掘Hibernate,我认为这将是一个很好的解决方案。

话虽这么说,如果查询只是带参数的简单字符串,那么只需将它们放入存储过程中并完成它。 – 但是你错过了使用对象很好的结果。