Java程序员在写SQL程序时候常犯的10个错误

时间:2019-05-12 21:09:44下载本文作者:会员上传
简介:写写帮文库小编为你整理了多篇相关的《Java程序员在写SQL程序时候常犯的10个错误》,但愿对你工作学习有帮助,当然你在写写帮文库还可以找到更多《Java程序员在写SQL程序时候常犯的10个错误》。

第一篇:Java程序员在写SQL程序时候常犯的10个错误

Java程序员编程时需要混合面向对象思维和一般命令式编程的方法,能否完美的将两者结合起来完全得依靠编程人员的水准: 技能(任何人都能容易学会命令式编程)模式(有些人用“模式-模式”,举个例子,模式可以应用到任何地方,而且都可以归为某一类模式)心境(首先,要写个好的面向对象程序是比命令式程序难的多,你得花费一些功夫)但当Java程序员写SQL语句时,一切都不一样了。SQL是说明性语言而非面向对象或是命令式编程语言。在SQL中要写个查询语句是很简单的。但在Java里类似的语句却不容易,因为程序员不仅要反复考虑编程范式,而且也要考虑算法的问题。

下面是Java程序员在写SQL时常犯的错误(没有特定的顺序): 1.忘掉NULL

Java程序员写SQL时对NULL的误解可能是最大的错误。也许是因为(并非唯一理由)NULL也称作UNKNOWN。如果被称作UNKNOWN,这还好理解些。另一个原因是,当你从数据库拿东西或是绑定变量时,JDBC将SQL NULL 和Java中的null对应了起来。这样导致了NULL = NULL(SQL)和null=null(Java)的误解。

对于NULL最大的误解是当NULL被用作行值表达式完整性约束条件时。

另一个误解出现在对于NULL 在 NOT IN anti-joins的应用中。解决方法: 好好的训练你自己。当你写SQL时要不停得想到NULL的用法: 这个NULL完整性约束条件是正确的? NULL是否影响到结果? 2.在Java内存中处理数据

很少有Java开发者能将SQL理解的很好.偶尔使用的JOIN,还有古怪的UNION,好吧.但是对于窗口函数呢?还有对集合进行分组呢?许多的Java开发者将SQL数据加载到内存中,将这些数据转换成某些相近的集合类型,然后再那些集合上面使用边界循环控制结构(至少在Java8的集合升级以前)执行令人生厌的数学运算.但是一些SQL数据库支持先进的(而且是SQL 标准支持的!)OLAP特性,这一特性表现更好而且写起来也更加方便.一个(并不怎么标准的)例子就是Oracle超棒的MODEL分句.只让数据库来做处理然后只把结果带到Java内存中吧.因为毕竟所有非常聪明的家伙已经对这些昂贵的产品进行了优化.因此实际上,通过将OLAP移到数据库,你将获得一下两项好处: 便利性.这比在Java中编写正确的SQL可能更加的容易.性能表现.数据库应该比你的算法处理起来更加快.而且更加重要的是,你不必再去传递数百万条记录了.完善的方法: 每次你使用Java实现一个以数据为中心的算法时,问问自己:有没有一种方法可以让数据库代替为我做这种麻烦事.3.使用UNION代替UNION ALL 太可耻了,和UNION相比UNION ALL还需要额外的关键字。如果SQL标准已经规定了支持,那么可能会更好点。UNION(允许重复)UNION DISTINCT(去除了重复)移除重复行不仅很少需要(有时甚至是错的),而且对于带很多行的大数据集合会相当慢,因为两个子select需要排序,而且每个元组也需要和它的子序列元组比较。

注意即使SQL标准规定了INTERSECT ALL和EXCEPT ALL,很少数据库会实现这些没用的集合操作符。处理方法:

每次你写UNION语句时,考虑实际上是否需要UNION ALL语句。4.通过JDBC分页技术给大量的结果进行分页操作

大部分的数据库都会支持一些分页命令实现分页效果,譬如LIMIT..OFFSET,TOP..START AT,OFFSET..FETCH语句等。即使没有支持这些语句的数据库,仍有可能对ROWNUM(甲骨文)或者是ROW NUMBER()OVER()过滤(DB2,SQL Server2008等),这些比在内存中实现分页更快速。在处理大量数据中,效果尤其明显。纠正:

仅仅使用这些语句,那么一个工具(例如JOOQ)就可以模拟这些语句的操作。

5.在java内存中加入数据 从SQL的初期开始,当在SQL中使用JOIN语句时,一些开发者仍旧有不安的感觉。这是源自对加入JOIN后会变慢的固有恐惧。假如基于成本的优化选择去实现嵌套循环,在创建一张连接表源前,可能加载所有的表在数据库内存中,这可能是真的。但是这事发生的概率太低了。通过合适的预测,约束和索引,合并连接和哈希连接的操作都是相当的快。这完全是是关于正确元数据(在这里我不能够引用Tom Kyte的太多)。而且,可能仍然有不少的Java开发人员加载两张表通过分开查询到一个映射中,并且在某种程度上把他们加到了内存当中。纠正:

假如你在各个步骤中有从各种表的查询操作,好好想想是否可以表达你的查询操作在单条语句中。

6.在一个临时的笛卡尔积集合中使用 DISTINCT 或 UNION 消除重复项

通过复杂的连接,人们可能会对SQL语句中扮演关键角色的所有关系失去概念。特别的,如果这涉及到多列外键关系的话,很有可能会忘记在JOIN..ON子句中增加相关的判断。这会导致重复的记录,但或许只是在特殊的情况下。有些开发者因此可能选择DISTINCT来消除这些重复记录。从三个方面来说这是错误的:

它(也许)解决了表面症状但并没有解决问题。它也有可能无法解决极端情况下的症状。

对具有很多列的庞大的结果集合来说它很慢。DISTINCT要执行ORDER BY操作来消除重复。对庞大的笛卡尔积集合来说它很慢,还是需要加载很多的数据到内存中。解决方法: 根据经验,如果你获得了不需要的重复记录,还是检查你的JOIN判断吧。可能在某个地方有一个很难觉察的笛卡尔积集合。7.不使用MERGE语句

这并不是一个过失,但是可能是缺少知识或者对于强悍的MERGE语句信心不足。一些数据库理解其它形式的更新插入(UPSERT)语句,如 MYSQL的重复主键更新语句,但是MERGE在数据库中确是很强大,很重要,以至于大肆扩展SQL标准,例如SQL SERVER。解决之道: 如果你使用像联合INSERT和UPDATE或者联合SELECT..FOR UPDATE然后在INSERT或UPDATE等更新插入时,请三思。你完全可以使用一个更简单的MERGE语句来远离冒险竞争条件。8.使用聚合函数代替窗口函数(window functions)

在介绍窗口函数之前,在SQL中聚合数据意味着使用GROUP BY语句与聚合函数相映射。在很多情形下都工作得很好,如聚合数据需要浓缩常规数据,那么就在join子查询中使用group查询。

但是在SQL:2003中定义了窗口函数,这个在很多主流数据库都实现了它。窗口函数能够在结果集上聚合数据,但是却没有分组。事实上,每个窗口函数都有自己的、独立的PARTITION BY语句,这个工具对于显示报告太TM好了。使用窗口函数: 使SQL更易读(但在子查询中没有GROUP BY语句专业)提升性能,像关系数据库管理系统能够更容易优化窗口函数 解决方法:

当你在子查询中使用GROUP BY语句时,请再三考虑是否可以使用窗口函数完成。9.使用内存间接排序

SQL的ORDER BY语句支持很多类型的表达式,包括CASE语句,对于间接排序十分有用。你可能重来不会在Java内存中排序数据,因为你会想: SQL排序很慢 SQL排序办不到 处理方法: 如果你在内存中排序任何SQL数据,请再三考虑,是否不能在数据库中排序。这对于数据库分页数据十分有用。10.一条一条的插入大量纪录

JDBC ”懂“批处理(batch),你应该不会忘了它。不要使用INSERT语句来一条一条的出入成千上万的记录,(因为)每次都会创建一个新的PreparedStatement对象。如果你的所有记录都插入到同一个表时,那么就创建一个带有一条SQL语句以及附带很多值集合的插入批处理语句。你可能需要在达到一定量的插入记录后才提交来保证UNDO日志瘦小,这依赖于你的数据库和数据库设置。处理方法: 总是使用批处理插入大量数据。

第二篇:Java程序员常犯的错误

Java程序员常犯的十大错误

无论你是一名熟练的java程序员,熟悉java的程度就像熟悉自己的手背一样;或者你是一名java新手,你都会犯错误。这是很自然的,更是人之常情。你所想象不到的确实,你犯的错误很可能是其他人也在犯的错误,这些错误犯了一次又一次。在这里我给出来了经常犯的十大错误列表,通过它我们可以发现它们并解决它们。

10.在静态方法中访问非静态的成员变量(例如在main方法中)。

许多程序员,特别是那些刚刚接触JAVA的,都有一个问题,就是在main方法中访问成员变量。Main方法一般都被标示为“静态的”,意思就是我们不需要实例化这个类来调用main方法。例如,java虚拟机能够以这样的形式来调用MyApplication类:

MyApplication.main(命令行参数);

这里并没有实例化MyApplication类,或者这里没有访问任何的成员变量。例如下面的程序就会产生一个编译器的错误。

public class StaticDemo {

public String my_member_variable = “somedata”;public static void main(String args[]){

// Access a non-static member from static method

System.out.println(“This generates a compiler error” + my_member_variable);} }

如果你要访问一个静态方法中的成员变量(比如main方法),你就需要实例化一个对象。下面这段代码示例了如何正确的访问一个非静态的成员变量,其方法就是首先实例化一个对象。

public class NonStaticDemo {

public String my_member_variable = “somedata”;

public static void main(String args[]){

NonStaticDemo demo = new NonStaticDemo();

// Access member variable of demo

System.out.println(“This WON'T generate an error” + demo.my_member_variable);} }

9.在重载的时候错误的键入方法名

重载允许程序员用新的代码去覆盖方法的实现。重载是一个便利的特性,很多面对对象的程序员都在大量的使用它。如果你使用AWT1.1的事件处理模型,你通常会覆盖listener方法去实现定制的功能。一个在重载方法的时候很容易犯的错误就是错误的键入要重载的方法名。如果你错误的输入了方法名,你就不是在重载这个方法了。相反的,你是在重新定义一个方法,只不过这个方法的参数和返回类型和你要重载的方法相同罢了。

public class MyWindowListener extends WindowAdapter { // This should be WindowClosed

public void WindowClose(WindowEvent e){ // Exit when user closes window System.exit(0);} };

这 个方法不会通过编译,很容易就能捕捉找它。在过去我曾经注意过一个方法,并且相信它是被调用的,花了很多时间找这个错误。这个错误的表现就是你的方法不会 被调用,你会以为你的方法已经被跳过了。一种可行的解决方法就是增加一条打印输出语句。在日志文件中记录下信息。或者是使用跟踪调试程序(例如VJ++或者是Borland JBuilder)来一行一行的调试。如果你的方法还不能被调用,那很可能就是你的方法名键入错误了。

8.比较和分配(“=”强于“==”)

这是一个很容易犯的错误。如果你以前使用过别的语言,比如Pascal,你就会知道计算机语言的设计们选择这样的方式是何等的乏味。举个例子,在Pascal中,我们使用:=运算符来表示分配,而使用=来表示比较。这样好像是退回了C/C++,也就是java的起源。

幸运的是,即使你没有发现在屏幕上发现这个错误,你的编译器会帮助你发现它。通常情况下,编译器会报出这样一个错误信息:“不能转换xxx到布尔类型”,这里的XXX是你用来代替比较的java类型。

7.比较两个对象(用==来代替instead of)当我们使用==运算符的时候,我们实际上是在比较两个对象的引用,来看看他们是不是指向的同一个对象。举个例子,我们不能使用==运算符来比较两个字符串是否相等。我们应该使用.equals方法来比较两个对象,这个方法是所有类共有的,它继承自java.lang.Object。

下面是比较两个字符串相等的正确的方法。

// Bad way

if((abc + def)== “abcdef”){

......}

// Good way

if((abc + def).equals(“abcdef”)){

.....}

6.混淆值传递和引用传递。

这是一个不太容易发现的错误。因为,当你看代码的时候,你会十分确定这是一个引用传递,而它实际上却是一个值传递。Java这两者都会使用,所以你要理解你什么时候需要值传递,什么时候需要引用传递。当你要传递一个简单的数据类型到一个函数中,比如,char、int、float或者double,你是在传递一个值。这个意味着这种数据类型的被复制了一个拷贝,是这个拷贝被传递到了函数中。如果这个函数去修改这个值,仅仅是这个值的拷贝被修改了。这个函数结束以后,将会返回到控制调用函数去,这时候那个“真正的”值没有受到影响,没有任何改变被存储。

如果你想修改一个简单的数据类型,可以将这个数据类型定位一个返回值或者将它封装到一个对象中。

当你要传递一个java对 象到一个函数中,比如,数组、向量或者是一个字符串,此时你传递的就是一个对象的引用。这里的字符串也是一个对象,而不是一个简单数据类型。这就意味这你 要传递一个对象到一个函数,你就要传递这个对象的引用,而不能去复制它。任何对这个对象的成员变量的改变都会持久化,这种改变的好坏要取决于你是否是刻意 而为之。

有一点要注意,如果字符串没有包含任何方法改变它的值的时候,你最好将它作为值来传递。

5.写一个空的异常处理。

我知道一个空的异常处理就像忽略错误一样很诱人。但是如果真的发生了错误,你不会得到一个错误信息的输出,它使得不太可能发现错误的原因。甚至是最简单的异常处理都是很有用处的。举个例子,在你的代码加上try{}catch{},去试着捕捉任何的异常抛出,并打印出错误信息。你不用为每个异常都写出定制的处理(虽然这是一个很好的编程习惯)。但是不要将这个异常处理空着,否则你就不会知道有什么错误发生了。

举例:

public static void main(String args[]){

try {

// Your code goes here..}

catch(Exception e){

System.out.println(“Err-” + e);} }

4.忘记java中索引是从0开始的。

如果你有C/C++的编程背景的话,你在使用其他编程语言的时候就不会发现同样的问题了。

在java中数组的索引是从0开始的,这就是说第一个元素的索引必须是0.困惑了?让我们看看例子吧。

// Create an array of three strings String[] strArray = new String[3];

// First element's index is actually 0 strArray[0] = “First string”;

// Second element's index is actually 1 strArray[1] = “Second string”;

// Final element's index is actually 2 strArray[2] = “Third and final string”;

在这个例子中,我们定义了一个有着三个字符串的数组,当我们访问它的元素时候减去了一个。现在,当我们试着去访问strArray[3],也就是第四个元素的时候,就会有一个ArrayOutOfBoundsException异常被抛出。这个就是最明显的例子-忘记了0索引规则。

在其他地方0索引规则也能使你陷入麻烦。例如字符串中。假设你要从一个字符串确定的偏移位置处得到一个字符,使用String.charAt(int)函数,你就能看到这个信息。但是在java中,字符串类的索引也是从0开始的,这就是说第一个字符的偏移位置为0,第二个为1.你可能会陷入一些麻烦,如果你不注意这个问题的话,特别是你的应用程序中使用了大量的字符串处理程序,那样的话你就很可能使用错误的字符,同时在运行是抛出一个StringIndexOutOfBoundsException异常,就像ArrayOutOfBoundsException异常一样。下面的例子证明了这些:

public class StrDemo {

public static void main(String args[]){

String abc = “abc”;

System.out.println(“Char at offset 0 : ” + abc.charAt(0));System.out.println(“Char at offset 1 : ” + abc.charAt(1));System.out.println(“Char at offset 2 : ” + abc.charAt(2));

// This line should throw a StringIndexOutOfBoundsException System.out.println(“Char at offset 3 : ” + abc.charAt(3));} }

同时应该注意的是,0索引规则不应该只应用在数组或是字符串中,java的其他部分也会用到。但是并不是全部都会用到。Java.util.Date和java.util.Calendar,这两个类的月份都是从0开始的,但是日期却通常是从1开始的,下面的程序证明了这一点。

import java.util.Date;import java.util.Calendar;

public class ZeroIndexedDate {

public static void main(String args[]){

// Get today's date Date today = new Date();

// Print return value of getMonth

System.out.println(“Date.getMonth()returns : ” + today.getMonth());

// Get today's date using a Calendar

Calendar rightNow = Calendar.getInstance();

// Print return value of get(Calendar.MONTH)

System.out.println(“Calendar.get(month)returns : ” + rightNow.get(Calendar.MONTH));} }

0索引规则在你不注意它的时候就会发生,如果你不想在运行时遇到这个错误的话,请注意查阅你的API文档。

3.防止线程在共享变量中并行存取。

在写一个多线程的应用程序的时候,许多程序员都喜欢抄近路。而这样会是他们的应用程序或者是小应用程序发生线程冲突。当两个或者两个以上的线程访问同一个数据的时候,就存在一定的概率(概率大小取决与墨菲法则)使得两个线程同时的访问或者修改同一个数据。不要愚蠢的认为这样的情况不会发生在单线程的应用程序中。当访问同一个数据的时候,你的线程就很可能被挂起,而第二个线程进入是就会覆盖第一个线程修改的地方。

这样的问题不是仅仅出现在多线程应用程序或者是小应用程序中的。如果你写了java api或者是java bean,你的代码就很可能不是线程安全的。即使你从来没有写过一个使用线程的单独的应用程序,人们也有可能使用你的程序。为了其他人,不仅仅是你,你就应该采取措施防止线程在共享变量中并行存取。

怎样来解决这个问题呢,最简单的就是让你的变量私有化。同时使用同步存取方法。存取方法允许访问似有的成员变量,但是仅仅是在一种控制方式中。下面的存取方法就能够以安全的方式修改计数器的值。

public class MyCounter {

private int count = 0;// count starts at zero

public synchronized void setCount(int amount){

count = amount;}

public synchronized int getCount(){

return count;} } 2.大写错误。

这是一个我们最经常犯的错误。它是很简单的,但是有时我们看着一个没有大写的变量或者方法却并不能发现这个错误。我自己也常常感到困惑,因为我认为这些方法和变量都是存在的,但是却发现不了他们没有大写。

这里你不能用银子弹来检查它,你只能自己训练着来减少这种错误。这里有一个窍门:

Java api中所用的方法和变量名都应该以小写字母来开头。所有的变量名和方法名的新词的开头都要用大写字母。如果你以这样的形式来定义你的变量名和类名,你就是在有意识的使它们走向正确,你就能逐渐的减少这样错误的数量。这可能需要一段时间,但是在以后有可能会避免更为严重的错误。

下来就是java程序员最常犯的错误了!!1.空指针!

空指针是java程序员最经常犯的错误了。编译器不会为你检查出这个错误它仅仅在运行时在表现出来,如果你发现不了它,你的用户将很可能发现它。

当试着访问一个对象的时候,这个对象的引用就是空的,一个NullPointerException异常就会被抛出。空指针错误的原因是多种多样的,但是一般情况下发生这种错误意味着你没有对一个对象初始化,或者是你没有检查一个函数的返回值。

许多函数返回一个空是用来指示一个错误的条件被执行。如果你不检查返回值的话,你由于不可能知道发生了什么。既然原因是一个错误的条件,一般的测试就不会发现它,这就意味着你的用户可能在最后的时候替你发现它。如果API函数指明一个空的对象很可能被返回,那在使用对象的引用之前一定要进行检查。

另外的原因可能是你在初始化对象的时候不规范,或者是它的初始化是有条件的。举例,检查下面的代码,看看你是否能发现这个错误。

public static void main(String args[]){

// Accept up to 3 parameters String[] list = new String[3];

int index = 0;

while((index < args.length)&&(index < 3)){

list[index++] = args[index];}

// Check all the parameters

for(int i = 0;i < list.length;i++){

if(list[i].equals “-help”){ //.........} else

if(list[i].equals “-cp”){

//.........}

// else.....} }

上面的代码(作为人为的例子),显示了通常的错误。在某些情况下,用户输入了三个或者更多的参数,上述代码将会正常运行。但是如果没有参数被输入,那么在运行的时候就会得到一个空指针异 常。某些时候你的变量将会被初始化,但是其他时候它们却不会。一个简单的解决办法就是在你访问数组元素的时候先检查它十分为空。

总结:

这些错误是我们常犯的错误的一些代表。虽然在编码的时候不可能完全的避免错误,但是你应该去避免犯一些重复的错误。很明显的是,所有的java程序员都会犯这样的错误。唯一能让人感到安慰的就是,当你在夜深人静的时候去跟踪一个错误,在某时某地某个人也在犯着同样的错误。

下载Java程序员在写SQL程序时候常犯的10个错误word格式文档
下载Java程序员在写SQL程序时候常犯的10个错误.doc
将本文档下载到自己电脑,方便修改和收藏,请勿使用迅雷等下载。
点此处下载文档

文档为doc格式


声明:本文内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:645879355@qq.com 进行举报,并提供相关证据,工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。

相关范文推荐