Java开发者编写SQL语句时常见错误分别有哪些

63次阅读
没有评论

共计 3460 个字符,预计需要花费 9 分钟才能阅读完成。

今天就跟大家聊聊有关 Java 开发者编写 SQL 语句时常见错误分别有哪些,可能很多人都不太了解,为了让大家更加了解,丸趣 TV 小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

Java 开发者对于面向对象编程思维与命令行编程思维的协调程度,取决于他们如下几种能力的水平:

技巧 (任何人都可以编写命令行形式的代码) 教条 (有的人使用“模式 – 模式”的方式,即模式无处不在,并以名字作为标识) 情绪状况(在初期,真正面向对象形式的代码比起命令式代码会更加难懂。)

但是,当 Java 开发人员编写 SQL 语句时,一切都变得不同了。SQL 是一种说明式语言,与面向对象思想和命令式思想无关。在 SQL 语言中,查询非常容易表达。但它也不是那么容易以最佳或最正确地方式编写出来。开发人员不仅需要重新思考自己的编程模式,还需要从集合论的角度进行深入思考。

以下是 Java 开发人员使 JDBC 或 jOOQ 编写 SQL 语句时,几种常见的错误:

1. 忘记了 NULL

误解 NULL 的含义可能是 Java 开发人员编写 SQL 最常犯的错误。这有可能是因为 NULL 也被称为 UNKNOWN,但也有其他的原因。当然如果它只被叫做 UNKNOWN,会更容易理解一些。另一个原因是,JDBC 在获取数据,或绑定变量时,SQL 中的 NULL 被映射到 Java 中的 null。这可能会导致人们认为类似 Java 中 null==null 的情况,SQL 中也存在 NULL= NULL。

一个更离奇的误解 NULL 的例子是,当 NULL 谓词用于行值表达式时。

另一个微妙的问题产生与对 NOTIn 反连接中 NULL 含义的误解。

解决办法

不断的训练自己。要时刻明确 NULL 的含义,每次你写 SQL 时,都要考虑:

对于 NULL 来说谓词是否正确?NULL 是否影响该函数的结果?2. 在 Java 内存中处理数据

一些 Java 开发者十分了解 SQL 特性。偶尔 JOIN,零散的 UNION,没什么问题。但如果遇到视窗功能,结果集分组等情况又怎么样呢? 很多 Java 开发人员会把 SQL 数据加载到内存,把数据转换成一些适合的集合类型,以十分冗长的循环结构在集合上执行恼人数学运算(至少在 Java 8 改进容器之前是这样的)。

但一些 SQL 数据库除了支持 SQL 标准外,还支持先进的 OLAP 特性,执行效率更好,且更容易编写。一个非标准的例子就是甲骨文的 MODEL 子句。只是让数据库进行数据处理过程,将最终获取的结果加载到 Java 内存中。因为一些非常聪明的人已经优化了这些昂贵的产品。所以,事实上,通过向 OLAP 数据库上进行迁移,您将得到两个好处:

简洁。它可能使得在 SQL 中编写正确代码会比在 Java 中相对容易性能。该数据库将可能比你的算法要快。更重要的是,你不必再通过网络传输数百万条记录。解决办法

每次你在 Java 中实现以数据为中心的算法时,要试着问问自己:有没有办法让数据库执行这些工作,而只把结果交付给我?

3. 尽量使用 UNION,而不是 UNION ALL

相对于 UNION,UNION ALL 需要额外的关键字显得相形见绌。如果在 SQL 标准已定义如下支持,那将会好很多:

UNION(允许重复)UNION DISTINCT(去掉重复)一般很少需要去除重复(有时去重甚至是错误的),而且对于具有很多列的大结果集,它往往很慢,因为这两个子查询需要排序,每个元组都需要与随后的元组进行比较。

需要注意的是,即使 SQL 标准指定了 INTERSECTALL 和 EXCEPTALL,但几乎没有任何数据库实现这些用处不大的操作。

解决办法

你每次写到 UNION 时,要考虑下你是否实际上想写的是 UNIONALL。

4. 使用 JDBC 分页功能将大量结果分页

大多数数据库都支持通过 LIMIT.. OFFSET,TOP .. START AT、OFFSET.. FETCH 等子句以某种方式对结果进行分页。在没有对这些子句的支持下,但仍然有 ROWNUM(Oracle)或 ROW_NUMBER()OVER()(DB2,SQL Server 2008 和更低版本),这比在内存中分页要快得多。而且这对于大数据集更是明显。

解决办法

只要使用那些子句或工具(如 jOOQ),可以为你模拟上述分页子句。

5. 将 Java 内存中实现连接

从 SQL 的发展的初期,一些开发商在面对 SQL 连接时仍然有一种不安的感觉。一直存在着一种固有的恐惧 —JOIN 速度缓慢。如果基于成本的优化器选择执行嵌套循环,创建一个连接表源之前,加载完整表到数据库内存,那速度确实十分缓慢。但很这少发生。通过适当的谓词,约束和索引,MERGEJOIN 和 HASHJOIN 操作是非常快的。这与正确的元数据相关(我不用再举 Tom Kyte 的例子了)。然而,也有仍然可能有不少 Java 开发人要会从单独的查询中加载两个表到 map 容器中,在 java 内存中以某种方式进行连接操作。

解决办法

如果你从多个步骤的多个表中进行了 SELECT 操作,那要慎重考虑一下是否可以在一条语句中表达你所需要的查询功能。6. 使用 DISTINCT 或 UNION 从一个笛卡尔积中删除重复

冗长连接的存在,会导致 SQL 语句中起作用的关系显得十分松散。具体地,如果涉及到多列外键关系,很有可能忘记在 JOINON 子句上添加谓词。这可能会导致重复的记录,但也许只在特殊情况下。然后一些开发者可能会选择使用 DISTINCT 再次删除这些重复记录。这种错误有三种危害:

可能治标不治本。甚至在某些边缘情况下,标都治不了这在有很多列的大结果集上会十分的缓慢。DISTINCT 会执行 ORDER BY 操作来删除重复。这在大型笛卡尔积中也十分的缓慢,因为这样做仍然会导致在内存中加载大量数据。解决办法

作为一个经验法则,当你得到不想要的重复结果时,应该首先检查你的连接谓词。因为有可能是在某个地方存在着一个不易察觉的笛卡尔积。

7. 不使用 MERGE 语句

严格意义上讲,这不是一个真正的错误,可能只是对于功能强大的 MERGE 语句缺乏足够的认知或存在着某种恐惧而已。有些数据库包括其他形式的 UPSERT 语句,如 MySQL 的 ONDUPLICATE KEY UPDATE 子句。但 MERGE 真的十分强大,最重要的是在数据库中,它在很大程度上扩展了 SQL 标准,如 SQL Server。

解决办法

如果你通过链接 INSERT 和 UPDATE 或链接 SELECT… FOR UPDATE 来实现 UPSERTING,那么你要多想一想。抛开与运行条件的风险,你也许可以使用一个简单的 MERGE 语句来达到目的。

8. 使用了聚合函数,而不是窗体功能

引入窗函数之前,使用 GROUPBY 子句与投影聚合函数是汇总数据的唯一方式。这在大部分情况下都十分有效,如果聚集后的数据需要由常规的数据进行补充,该分组的查询可以置于连接子查询中。

但是,SQL:2003 定义了窗口功能,目前很多主流的数据库厂商也纷纷实现了窗口功能。窗口功能可以聚集结果集中未被分组的数据。事实上,每个窗口的功能支持自身独立的 PARTITIONBY 子句,这对于报表类应用是一个非常有用的工具。

使用窗口功能将:

导致更多的可读性 SQL(减少子查询中非专用 GROUP BY 子句的存在)提高性能,作为一个 RDBMS 很可能更容易优化其窗口功能。解决办法

当你在一个子查询写一个 GROUPBY 子句时,仔细想想这是否能用一个窗口函数来完成。

9. 使用内存排序法进行间接排序

在 SQLORDER BY 子句支持多种类型的表达式,包括 CASE 语句,这对间接排序非常有用。你应该永远可能在 Java 内存中对数据进行排序,因为你认为:

SQL 排序太慢 SQL 排序不能做到这一点解决办法

如果你在内存中对任何 SQL 数据进行排序,请仔细想想,你是否能把排序迁移至数据库中。这和将分页迁移至数据库中的原因一样。

10 一个接一个的插入大量的记录

JDBC 包含了批处理,而且你应该使用它。面对成千上万的记录,切勿为每一条记录都创建一个新的 PreparedStatement 来进行插入操作。如果你要将所有记录都插入到同一个表,使用单一的 SQL 语句和多个绑定值集合建立一个批处理的 INSERT 语句。根据您的数据库和数据库配置,您可能需要在一定数量的插入的记录后进行提交,为了保持 UNDO 日志不过分庞大。

解决办法

始终批量插入大型数据集。

Java 开发者编写 SQL 语句时常见的 10 种错误,大家是不是有了大概了解,希望在编写的过程中一定要特别注意!

看完上述内容,你们对 Java 开发者编写 SQL 语句时常见错误分别有哪些有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注丸趣 TV 行业资讯频道,感谢大家的支持。

正文完
 
丸趣
版权声明:本站原创文章,由 丸趣 2023-07-19发表,共计3460字。
转载说明:除特殊说明外本站除技术相关以外文章皆由网络搜集发布,转载请注明出处。
评论(没有评论)