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

Java 如何在源代码中处理巨大的SQL字符串,java,sql,coding-style,Java,Sql,Coding Style,我目前正在从事一个项目,其中代码中有大约3000行的SQL字符串 该项目是一个java项目,但这个问题可能适用于任何语言 无论如何,这是我第一次看到这么糟糕的事情。 代码库是遗留的,所以我们可以突然迁移到Hibernate或类似的地方 如何处理如此大的SQL字符串 我知道这不好,但我不知道到底什么是最好的解决方案建议。到目前为止,我能想到的最好办法是将查询放入几个存储过程中,与我处理Java中太长的方法的方法相同。在我看来,将这些硬编码的值转换为存储过程并从代码中引用存储过程可能是一种高产低耗的

我目前正在从事一个项目,其中代码中有大约3000行的SQL字符串

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

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

如何处理如此大的SQL字符串


我知道这不好,但我不知道到底什么是最好的解决方案建议。

到目前为止,我能想到的最好办法是将查询放入几个存储过程中,与我处理Java中太长的方法的方法相同。

在我看来,将这些硬编码的值转换为存储过程并从代码中引用存储过程可能是一种高产低耗的方法。

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

我在PHP中所做的是:

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

我想第一个问题是,你该怎么处理它?如果它没有坏,静静地把它关起来,假装你从未见过它。否则,就要疯狂地重构——希望在某个地方有一些类似契约的退出条件。

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

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

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

我的建议如下:

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

这就是我的想法。

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


或者,将它们作为const或readonly放入一个大的、旧的SqlQueries类中。

我与您处于同一位置。。。我的计划是将SQL拉入项目中单独的.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");
确保文件不可公开访问。

使用框架

我不久前为此写了一篇文章,并在几个项目中使用过。它允许您将查询主要放在文本文件中,并为它们生成绑定和文档

签出并创建一个(它几乎只是一个准备好的语句,编译成具有早期绑定/类型安全查询绑定的java类)


它也生成了一些很好的Javadoc,但我目前还没有在线文档。

我支持iBatis的建议。至少,您可以从最有可能使用StringBuffer的Java代码中提取SQL,并在XML中添加或添加字符串concat,这样更易于维护


我为一个遗留web应用程序做了这项工作,打开了调试,并为DAO运行了单元测试,只是将为每个语句生成的sql复制到iBatis xml中。工作非常顺利。

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

我发现性能实际上得到了提高,生成的sql简单得多。 我相信你们在Hibernate上也会得到类似的效果——当然除了能够使用linq之外。但是一般来说,如果生成的sql需要高度动态,那么它就不适合存储过程。在存储过程中编写动态sql是两个世界中最糟糕的。sql生成框架将是我首选的方法。如果你喜欢Hibernate,我认为这是一个很好的解决方案


也就是说,如果查询只是带有参数的简单字符串,那么只需将它们扔到存储的进程中,就可以完成查询-但是,您会错过处理对象的好结果。

几个存储过程?这是一个大问题还是这到底是什么?肯定有。最大的问题是它很难理解。大型长sql语句本身并没有什么坏处。如果你把它们分解,并把各部分相加,理解它们就不容易了。这样可能更有效。有没有办法知道它是否被分析/优化了?分解是一个不可转移的概念,从过程性代码(几乎总是赢的)到声明性代码(几乎总是输的)。这就是为什么临时表是SQL反模式。分解在SQL中绝对有效。您可以分解一个具有多个连接的复杂查询,并使用视图或存储过程使其易于理解。我看不出有任何理由不将其作为存储过程。高产低耗是对的!你听上去很肯定没有看到这个问题。:)确切地说,您指的是什么硬编码值?不幸的是,它被破坏了。或者更确切地说,它被更改了,现在不符合代码质量标准。然后将它从java中取出,放到一个SP中。这不是对它进行分解,而是将它从一个不合适的位置移动到一个合适的位置,因为它不会修复损坏的内容,但可能会更改代码标准规则。(在任何情况下都应该移动。)然后如果你想发布它,我会帮助你看看我们是否可以修补它。-1因为这是一个不专业的回答。是的,逃避问题和遗留代码很容易,但在StackOverflow,我希望找到实际的提示和解决方案,而不是像“假装你从未见过它”这样愚蠢的答案。但我欣赏幽默感。真的。你可以用这个面包
string sql = "select asd,asdf,ads,asdf,asdf," 
           + "from asdfj asfj as fasdkfjl asf"
           + "..........................."
           + "where user = @user and ........";
string sql = util.queries("usageReportByUser");