异常和 SQLException 的区别
Posted
技术标签:
【中文标题】异常和 SQLException 的区别【英文标题】:Difference between Exception and SQLException 【发布时间】:2014-05-21 14:49:56 【问题描述】:有人可以解释捕获Exception
和捕获SQLException
之间的区别吗?我知道如果您选择打印异常错误,SQLException 会打印出更多信息,但还有什么其他的吗?
try
//code
catch(Exception ex)
//code
和
try
//code
catch(SQLException ex)
//code
在catch块中使用Exception
和SQLException
有什么好处和区别?
【问题讨论】:
Exception 是一种更通用的类型,是 SQLException 的父类。它用于与 SQL 和数据库相关的上下文中,而不是一般上下文中。使用与正在发生的活动相关的异常很重要...这意味着使用好的代码您可能更有可能看到 SQL 类型的 SQL 异常... "我知道如果你选择打印异常错误,SQLException 会打印出更多信息" 不。不管你是在 Exception 类型的变量中捕获它还是在 SQLException 类型的变量中捕获它,它仍然是同一个 SQLException 对象,并且将包含相同的信息。 【参考方案1】:Exception 是一个标准类,每个异常都从该类继承。
SQLException 是一个继承自 Exception 的类,专为数据库 (SQL) 异常而设计。
通过做
try
// Your code here
catch (Exception e)
// Catching here
您正在捕获所有可能的异常类型...但是,您可能无法知道如何对特定异常做出反应。
但是通过做
try
// Your code here
catch (SQLException e)
// Catching here
您知道在处理数据库时发生了异常,它可以帮助您了解如何对异常做出反应。
【讨论】:
【参考方案2】:SQLException
继承自 Exception
,因此 SQLException
将包含比 Exception
更多(和更具体)的信息(旨在普遍适用于所有异常)。
您还可以有多个catch
子句;所以你可以先尝试捕捉SQLException
,但如果不是SQLException
,那么你可以捕捉一般的Exception
。
一般来说,您不应该catch
异常,除非您打算以某种方式处理它们。您可以有一个***异常处理程序来捕获任何冒泡到调用堆栈顶部的异常,这样您的程序就不会因未处理的异常而崩溃。
【讨论】:
【参考方案3】:如您所见,SQLException 扩展异常。所以这是唯一的区别。当您捕获异常时,您将捕获所有异常(这很糟糕)。但是当你捕捉到 SQLException 时,你只会捕捉到那个(这很好,因为那是你正在寻找的)。
【讨论】:
【参考方案4】:这不是唯一的区别。
捕获Exception
是危险的,因为它还捕获所有RuntimeException
s(因此是未经检查的异常),其中包括NullPointerException
等明显的程序员错误。 不要那样做!
另外,Exception
与其他类一样,因此您可以将其子类化并添加您的构造函数/方法。例如,SQLException
有一个 .getErrorCode()
method,而 Exception
没有。如果只捕获Exception
,则无法访问此方法。
一般来说,首先捕获“更精确”的异常是最好的。例如,使用新的(在 Java 7...中)文件 API,您可以轻松区分文件系统级错误和其他 I/O 错误,因为 FileSystemException
扩展了 IOException
:
try
something();
catch (FileSystemException e)
// fs level error
catch (IOException e)
// I/O error
【讨论】:
所以 SQLException 将是一个实例,您正在捕获更具体而不是通用的东西? 是的,完全正确。而且总是最好先捕获更具体的异常!如果你抓住“太低”,你可能会抓住不受欢迎的人。 完全有道理,非常感谢您的帮助! 还要注意,如果你实现/覆盖一个声明为throws A
的方法,你可以选择让你的实现抛出A
或任何子类。【参考方案5】:
如果在 try 和 catch 块之间抛出一个不是 SQL 异常的异常(这些通常仅来自与数据库相关的代码),例如空指针异常,异常捕获将捕获它,但 SQLException不会。
【讨论】:
【参考方案6】:SQLException 是一个异常,所以你只是得到一个更具体的异常。
根据Oracle的javadocs,你得到的具体信息是:
描述错误的字符串。这用作 Java 异常 消息,可通过 getMessage 方法获得。 一个“SQLstate”字符串,它跟在 XOPEN SQLstate 之后 约定或 SQL:2003 约定。 SQLState 的值 字符串在相应的规范中进行了描述。数据库元数据 方法 getSQLStateType 可用于发现驱动程序是否 返回 XOPEN 类型或 SQL:2003 类型。 特定于每个供应商的整数错误代码。通常这个 将是底层数据库返回的实际错误代码。 到下一个异常的链。这可以用来提供额外的 错误信息。 此 SQLException 的因果关系(如果有)。【讨论】:
【参考方案7】:SQLException
是从Exception
派生的特殊异常。
如果你捕捉到Exception
,所有的异常都会被捕捉到。甚至是不受欢迎的例外。
如果你只捕捉到它的特化,SQLException
,只有 SQLException
本身或其派生会被捕捉到。
一个人应该只捕获一个可以处理或希望处理的异常,并让其他人冒泡。
如需进一步参考,请查看以下内容:
-
Exception
SQLException
【讨论】:
【参考方案8】:当您谈论捕获异常时,这都是关于层次结构的。
从技术上讲,Exception - 是捕获每个异常的超类。 如果您在 try 块中编写与 SQL 相关的内容,并且您知道它甚至可能抛出 SQL 异常。 那么你也可以这样声明。
try
catch(SQLException ex)
Do this,when SQL Exception is caught.
catch(Exception ex)
Generic Exception - works for all
【讨论】:
【参考方案9】:SQL 异常是在 Java 数据库连接 (JDBC) 中工作时经常出现的错误。它与使用准备好的语句访问或设置 SQL 查询中的列有关。
SQLException 是从 Exception 派生的,包含更具体的与访问或设置 SQL 查询中的列相关的信息,而异常通常更笼统。
【讨论】:
【参考方案10】:A - 解释
SQLException
是java.lang.Exception
的子类型,它也实现了Iterable<Throwable>
类。程序员更喜欢抛出 Exception
类的不同子类型,因为在更高级别上,他们希望捕获确切的子异常类,以便他们可以确保在某些确切情况下抛出特定的异常。因此,他们可以知道异常的确切来源。
B - 示例
假设您编写了一个引发多个异常的方法。假设您获取一个 json 字符串并对其进行解析,然后将其保存在数据库中。考虑以下方法;
public boolean persistCustomer(String jsonString) throws SQLException, IOException
Connection conn = getConnection();
PreparedStatement preparedStatement = null;
ObjectMapper objectMapper = new ObjectMapper();
try
Customer customer = objectMapper.readValue(jsonString, Customer.class);
preparedStatement = conn.prepareStatement(PERSIST_CUSTOMER);
preparedStatement.setString (1, customer.getName());
preparedStatement.setInt (2, customer.getAge());
preparedStatement.setBoolean (3, customer.getIsRegular());
preparedStatement.executeUpdate();
return true;
catch (IOException e)
throw e;
finally
try
if (preparedStatement != null)
preparedStatement.close();
if (conn != null)
conn.close();
catch (SQLException e)
e.printStackTrace();
在此方法中,我们将 JSON 转换为 Customer 类,并将客户类持久化到数据库中。
以下行抛出SQLException
;
preparedStatement = conn.prepareStatement(PERSIST_CUSTOMER);
preparedStatement.setString (1, customer.getName());
preparedStatement.setInt (2, customer.getAge());
preparedStatement.setBoolean (3, customer.getIsRegular());
preparedStatement.executeUpdate();
prepareStatement()
、setter 和 executeUpdate()
方法,它们都在抛出 SQLException
的。而且,我们将 String 中的 JSON 转换为 Customer 对象的那一行,除了 SQLException 之外,也抛出了几个异常。
Customer customer = objectMapper.readValue(jsonString, Customer.class);
readValue()
方法抛出 JsonParseException
、JsonMappingException
和 IOException
。所有这些都可以使用IOException
捕获,因为与 JSON 相关的异常扩展了IOException
。
我将提供两个不同的示例,以便清楚地理解为什么我们需要不同类型的异常。
C - 坏习惯:使用异常捕获所有异常
public class BadPracticeExample
public static void main(String[] args)
mysqlUtil dbUtil = new MySQLUtil();
String jsonString = "\"name\":\"Levent\",\"age\":31,\"isRegular\":true";
try
dbUtil.persistCustomer(jsonString);
catch (Exception e)
System.out.println("A problem occured");
如您所见,它捕获了异常,但如果我们需要针对两种不同的问题来源进行特殊异常处理,我们该怎么办? persistCustomer 可以抛出 IOException 或 SQLException ,如果我们需要执行不同的任务集来处理这些问题怎么办?我想在发生 SQLException 时向数据库管理员发送电子邮件,并且我想在发生 JSON 解析问题时继续,在捕获 IOException 的情况下?
在这种情况下,您不能这样做。这是上面代码 sn-p 的输出,我们只确定发生了异常,但我们不知道它的来源;
A problem occured
D - 良好实践示例 I:捕获的 SQL 异常
public class GoodPracticeExample
public static void main(String[] args)
MySQLUtil dbUtil = new MySQLUtil();
String jsonString = "\"name\":\"Levent\",\"age\":31,\"isRegular\":true";
try
dbUtil.persistCustomer(jsonString);
catch (SQLException e)
System.out.println("SQL Exception catched, SQL State : " + e.getSQLState());
System.out.println("Error Code : " + e.getErrorCode());
System.out.println("Error Message : " + e.getMessage());
catch (IOException e)
System.out.println("Cannot parse JSON : " + jsonString);
System.out.println("Error Message : " + e.getMessage());
如您所见,我们同时捕获了 JSON 和 SQL 问题,在此示例中,子方法试图在没有表的情况下持久化 DB。输出如下;
SQL Exception catched, SQL State : 42000
Error Code : 1142
Error Message : INSERT command denied to user 'levent'@'example.com' for table 'CUSTOMER'
所以我们已经捕获了 SQL 异常,并且我们拥有发送警报电子邮件所需的所有参数。我们可以在 SQLException catch 块上添加额外的处理程序或实用程序方法。
D - 良好实践示例 II:IOExceptoin 遇到解析错误
public class GoodPracticeExample
public static void main(String[] args)
MySQLUtil dbUtil = new MySQLUtil();
String jsonString = "\"Zname\":\"Levent\",\"age\":31,\"isRegular\":true";
try
dbUtil.persistCustomer(jsonString);
catch (SQLException e)
System.out.println("SQL Exception catched, SQL State : " + e.getSQLState());
System.out.println("Error Code : " + e.getErrorCode());
System.out.println("Error Message : " + e.getMessage());
catch (IOException e)
System.out.println("Cannot parse JSON : " + jsonString);
System.out.println("Error Message : " + e.getMessage());
如果你注意到了,我已经破坏了 JSON 以导致 IOException。现在在 json 字符串中,写入了“Zname”而不是“name”,这将导致 Jackson Parser 失败。让我们检查一下输出这段代码。
Cannot parse JSON : "Zname":"Levent","age":31,"isRegular":true
Error Message : Unrecognized field "Zname" (class com.divilioglu.db.utils$Customer), not marked as ignorable (3 known properties: "isRegular", "name", "age"])
at [Source: (String)""Zname":"Levent","age":31,"isRegular":true"; line: 1, column: 11] (through reference chain: com.divilioglu.db.utils.MySQLUtil$Customer["Zname"])
如您所见,我们捕捉到了具体场景,我们确信,这来自 dbUtil.persistCustomer() 方法中的行,如下所示;
Customer customer = objectMapper.readValue(jsonString, Customer.class);
E - 结论
因此,通过扩展现有的异常类来创建新的异常是一种最佳实践。在开始编写代码时,您可能会认为这是一种矫枉过正,您不需要额外的异常类,但是当您需要区分问题的根源并独立处理它们时,您将需要它们。
在上面演示的这个示例中,我可以独立捕获IOException
和SQLException
,并且两个异常的来源都来自同一个方法。我想区分两者,以便我可以独立处理它们。如果你只是用基类 Exception 类包装所有的 Exceptions,你就无法拥有这种灵活性。
【讨论】:
以上是关于异常和 SQLException 的区别的主要内容,如果未能解决你的问题,请参考以下文章
ResultSet 关闭后不允许出现 ResultSet、空指针异常和 SQLException 操作
System.Data.Entity.Core.EntityCommandExecutionException 和内部异常 SqlException:无效的列名“xxxx”
java.sql.SQLException:Io 异常:指定了未知主机
Android Studio 未报告异常 SQLException & ClassNotFoundException