jdbc 4 :Better SQLExceptions in Java 6
2007-06-10 23:13
405 查看
Abstract:
Java 6支持最新的JDBC 4.0规范,在这些新的特性中关于数据库异常的改进将会让你更加得心应手,下面我们通过代码来演示如何使用。
Welcome to the 138th edition of The Java(tm) Specialists' Newsletter, where we will look at new features of JDBC 4 that will help you to understand what went wrong with your database queries. I remember cornering Mark Hapner in 1999 when he visited Cape Town and presenting this problem to him. Mark Hapner was the architect for the first JDBC version and went on to architect J2EE and EJB. At the time, there was no easy solution to this problem.
Previously, these faults could be determined by looking at the SQLState contained in the exception. However, I thought that the JDBC driver should do this analysis and give me more specific information about what went wrong.
In JDBC 4.0, which ships as part of JDK 6, we now have a solution that will make it easier to write robust code for communicating with the database.
Instead of just having a single SQLException telling us that there is "a problem", we have three new subclasses, namely SQLNonTransientException, SQLTransientException and SQLRecoverableException. These sub-exceptions are called "categorised exceptions". It can now be possible, if the driver supports JDBC 4, to decide whether we should retry immediately, retry later or give up altogether.
下面是JDBC 4.0规范中关于SQL异常的类结构:
The non-transient exceptions represent permanent failures that are the result of some condition that must be corrected before retrying. Simply retrying the query would almost certainly cause it to fail again. Examples are problems with the data, constraint violations (such as with foreign keys) and syntax errors in the actual SQL query.
The transient exceptions are thrown when an error condition might go away within a short time, without changing any application logic. A typical exception here is the transient SQL connection. However, I have found in my example that I had to start a new connection if we got this exception. With a transient exception, this should typically not be necessary. A good example of a transient exception is when a deadlock occurs in the database, which will cause a SQLTransactionRollbackException.
The recoverable exception means that it might succeed if the application does some recovery steps and then retries the transaction. This will require to at least close the connection and to open a new one.
However, before I show you the test code, there was another annoying problem with database connections in the past. You did not know whether they were still active, unless you sent down a "known good query". This could be something as simple as "SELECT 1". However, if you added a caching JDBC driver, it could happen that the answer would come back immediately for something as simple as that.
Since Java 6, we now have a standard mechanism for checking connectivity to the database. We can call the
To run the DbTest below, all you need to do is make sure that the derby.jar file is in your classpath. This file is now in your JDK6/db/lib directory. Note that you do not need to do Class.forName() to load the driver - another feature of JDBC 4. How that works, is left as an exercise to the reader :-)
You should be able to run the program quite easily, like this:
This is all very nice, but something like this should have been available in Java 1.0. To now go back and fix all the legacy code is just not practical. New code is usually done with the Java Persistence API, not direct JDBC calls. Still, I am pleased to see this finally being added to JDBC.
Java 6支持最新的JDBC 4.0规范,在这些新的特性中关于数据库异常的改进将会让你更加得心应手,下面我们通过代码来演示如何使用。
Welcome to the 138th edition of The Java(tm) Specialists' Newsletter, where we will look at new features of JDBC 4 that will help you to understand what went wrong with your database queries. I remember cornering Mark Hapner in 1999 when he visited Cape Town and presenting this problem to him. Mark Hapner was the architect for the first JDBC version and went on to architect J2EE and EJB. At the time, there was no easy solution to this problem.
Better SQLExceptions in Java 6
Many years ago, I mentioned in a newsletter that when a SQLException occurs, we do not necessarily know what went wrong. It could be a temporary failure or a permanent fault. The SQL could contain a syntax error (permanent fault) or the database could be rebooting (temporary fault). I promised to write up a newsletter on how to solve this, but never got round to it.Previously, these faults could be determined by looking at the SQLState contained in the exception. However, I thought that the JDBC driver should do this analysis and give me more specific information about what went wrong.
In JDBC 4.0, which ships as part of JDK 6, we now have a solution that will make it easier to write robust code for communicating with the database.
Instead of just having a single SQLException telling us that there is "a problem", we have three new subclasses, namely SQLNonTransientException, SQLTransientException and SQLRecoverableException. These sub-exceptions are called "categorised exceptions". It can now be possible, if the driver supports JDBC 4, to decide whether we should retry immediately, retry later or give up altogether.
下面是JDBC 4.0规范中关于SQL异常的类结构:
SQLException +---> SQLNonTransientException | +---> SQLDataException | +---> SQLFeatureNotSupportedException | +---> SQLIntegrityConstraintViolationException | +---> SQLInvalidAuthorizationException | +---> SQLNonTransientConnectionException | +---> SQLSyntaxErrorException +---> SQLTransientException | +---> SQLTimeoutException | +---> SQLTransactionRollbackException | +---> SQLTransientConnectionException +---> SQLRecoverableException
The non-transient exceptions represent permanent failures that are the result of some condition that must be corrected before retrying. Simply retrying the query would almost certainly cause it to fail again. Examples are problems with the data, constraint violations (such as with foreign keys) and syntax errors in the actual SQL query.
The transient exceptions are thrown when an error condition might go away within a short time, without changing any application logic. A typical exception here is the transient SQL connection. However, I have found in my example that I had to start a new connection if we got this exception. With a transient exception, this should typically not be necessary. A good example of a transient exception is when a deadlock occurs in the database, which will cause a SQLTransactionRollbackException.
The recoverable exception means that it might succeed if the application does some recovery steps and then retries the transaction. This will require to at least close the connection and to open a new one.
Apache Derby
Another "feature" with the JDK 6 (not JRE 6) is that it ships standard with the Derby embedded database. I have still not met anyone who thinks this is a good idea. However, it is nice to be able to immediately start testing these new exceptions without having to find the correct drivers for your database.However, before I show you the test code, there was another annoying problem with database connections in the past. You did not know whether they were still active, unless you sent down a "known good query". This could be something as simple as "SELECT 1". However, if you added a caching JDBC driver, it could happen that the answer would come back immediately for something as simple as that.
Since Java 6, we now have a standard mechanism for checking connectivity to the database. We can call the
isValid(int timeout)method on a connection. This sends through a known good query and if it does not get a response within the given timeout (in seconds), then we know that the database connection is not valid anymore.
To run the DbTest below, all you need to do is make sure that the derby.jar file is in your classpath. This file is now in your JDK6/db/lib directory. Note that you do not need to do Class.forName() to load the driver - another feature of JDBC 4. How that works, is left as an exercise to the reader :-)
import java.sql.*; public class DbTest { private final static String dburl = "jdbc:derby:tjsnTest"; public static void main(String[] args) throws SQLException { Connection con = getNewConnection(); Statement s = con.createStatement(); try { s.execute("hello world - this should not work"); } catch (SQLSyntaxErrorException ex) { System.out.println("Permanent problem with syntax"); } s.execute("create table testTable(id int, name varchar(10))"); try { s.execute("insert into testTable values (1, 'Heinz Kabutz')"); } catch (SQLDataException ex) { System.out.println("Permanent problem with the data input"); } System.out.println("Is connection valid? " + con.isValid(10)); shutdownDB(); System.out.println("Is connection valid? " + con.isValid(10)); try { s.execute("drop table testTable"); } catch (SQLTransientConnectionException ex) { System.out.println("Temporary problem connecting to db"); } // restarting the database con = getNewConnection(); s = con.createStatement(); try { s.execute("drop table testTable"); } catch (SQLTransientConnectionException ex) { System.out.println("Temporary problem connecting to db"); } try { s.executeQuery("SELECT id, name FROM testTable"); } catch (SQLSyntaxErrorException ex) { System.out.println("Permanent syntax problem with query"); } } // shutting down the database private static void shutdownDB() throws SQLException { try { DriverManager.getConnection(dburl + ";shutdown=true"); } catch (SQLTransientConnectionException ex) { // this should not happen - but it does ... System.out.println("Temporary problem connecting to db"); } } private static Connection getNewConnection() throws SQLException { return DriverManager.getConnection(dburl + ";create=true"); } }
You should be able to run the program quite easily, like this:
java -cp %JDK_HOME%/db/lib/derby.jar;. DbTest Permanent problem with the data input Is connection valid? true Temporary problem connecting to db Is connection valid? false Temporary problem connecting to db Permanent syntax problem with query
This is all very nice, but something like this should have been available in Java 1.0. To now go back and fix all the legacy code is just not practical. New code is usually done with the Java Persistence API, not direct JDBC calls. Still, I am pleased to see this finally being added to JDBC.
相关文章推荐
- SpringMVC:com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your SQL syntax;
- Failed to load the sqljdbc_auth.dll cause :- no sqljdbc_auth in java.library.path
- 警告:failed to load the sqljdbc_auth.dll cause no sqljdbc_auth in java.library.path
- com.mysql.jdbc.exceptions.MySQLSyntaxErrorException: You have an error in your SQL syntax;
- Hibernate插件出现错误 java.sql.SQLException: No suitable driver found for jdbc:microsoft:sqlserver
- om.microsoft.sqlserver.jdbc.SQLServerException: 到主机 的 TCP/IP 连接失败。 java.net.ConnectException: Connection refused: connect
- Java JDBC下执行SQL的不同方式executeQuery/executeUpdate/execute
- java jdbc for sql 2000 and mysql
- Exception in thread "main" java.sql.SQLException: ORA-00923: FROM keyword not found where expected
- Hive 笔记异常(java.sql.SQLException: Unable to open a test connection to the given database. JDBC url =)
- java.lang.ClassNotFoundException: com.microsoft.sqlserver.jdbc.SQLServerDriver
- Jdbc-Type mismatch: cannot convert from java.sql.ResultSet to com.mysql.jdbc.ResultSet
- jdbc连接sql server 出现 java.sql.SQLException: Network error IOException: Connection refused:
- Exception in thread "main" java.util.ConcurrentModificationExceptions
- 在spring 的jdbc sql中使用in 语句
- java.sql.SQLException: Unknown type '246 in column 0 of 1 in binary-encoded result set的解决办法
- JDBC Java SQL Server 连接
- java.sql.SQLException: [Microsoft][SQLServer 2000 Driver for JDBC][SQLServer]用户 'sa' 登录失败
- eclipse 连接 sqlserver2005错误信息:"java.lang.ClassNotFoundException: com.microsoft.jdbc.sqlserver.SQLServerDriver"
- 158.Oracle数据库SQL开发之 JAVA——JDBC扩展