您好,登錄后才能下訂單哦!
Spring訪問數據庫異常的處理方法是什么,針對這個問題,這篇文章詳細介紹了相對應的分析和解答,希望可以幫助更多想解決這個問題的小伙伴找到更簡單易行的方法。
使用JDBC API時,很多操作都要聲明拋出java.sql.SQLException異常,通常情況下是要制定異常處理策略。而Spring的JDBC模塊為我們提供了一套異常處理機制,這套異常系統的基類是DataAccessException,它是RuntimeException的一種類型,那么就不用強制去捕捉異常了,Spring的異常體系如下:
目前為止我們還沒有明確地處理Spring中JDBC模塊的異常。要理解它的異常處理機制,我們來做幾個測試。看下面的測試代碼:
public void insert(final Vehicle vehicle) {
String sql = "insert into vehicle
(ID,PLATE,CHASSIS,COLOR,WHEEL,SEAT) values
(:id,:plate,:chassis,:color,:wheel,:seat)";
SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(
vehicle);
getSimpleJdbcTemplate().update(sql, parameterSource);
}
public void insert(final Vehicle vehicle) {
String sql = "insert into vehicle(ID,PLATE,CHASSIS,COLOR,WHEEL,SEAT)
values(:id,:plate,:chassis,:color,:wheel,:seat)";
SqlParameterSource parameterSource = new BeanPropertySqlParameterSource(
vehicle);
getSimpleJdbcTemplate().update(sql, parameterSource);
}
public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:org/ourpioneer/vehicle/spring/applicationContext.xml"); VehicleDAO vehicleDAO = (VehicleDAO) ctx.getBean("vehicleDAO"); Vehicle vehicle = new Vehicle("遼B-000000", "1A00000001", "RED", 4, 4); vehicle.setId(1); vehicleDAO.insert(vehicle); } public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:org/ourpioneer/vehicle/spring/applicationContext.xml"); VehicleDAO vehicleDAO = (VehicleDAO) ctx.getBean("vehicleDAO"); Vehicle vehicle = new Vehicle("遼B-000000", "1A00000001", "RED", 4, 4); vehicle.setId(1); vehicleDAO.insert(vehicle); }
修改SQL語句,不使用自增主鍵的特性,并在這里設置重復的主鍵,那么運行程序,就會報出字段重復的異常。下面來捕捉這個異常:
try { vehicleDAO.insert(vehicle); } catch (DataAccessException e) { SQLException sqle = (SQLException) e.getCause(); System.out.println("Error code: " + sqle.getErrorCode()); System.out.println("SQL state: " + sqle.getSQLState()); } try { vehicleDAO.insert(vehicle); } catch (DataAccessException e) { SQLException sqle = (SQLException) e.getCause(); System.out.println("Error code: " + sqle.getErrorCode()); System.out.println("SQL state: " + sqle.getSQLState()); }
此時,我們就可以獲得錯誤碼和SQL狀態(不同的數據庫系統會有不同):
關于HSQL數據庫的錯誤碼可以到org.hsqldb.Trace類中查看,只要注意運行結果會有一個負號,而類中定義的是沒有負號的。這樣就知道了這個錯誤的具體含義,比如104:***約束驗證失敗。這就是我們故意設置的重復主鍵問題。
Spring的JDBC模塊為我們預定義了一些錯誤代碼,它存儲在org.springframework.jdbc.support包下的sql-error-codes.xml文件中,其中描述HSQL的內容為:
<bean id="HSQL" class="org.springframework.jdbc.support.SQLErrorCodes"> <property name="databaseProductName"> <value>HSQL Database Engine</value> </property> <property name="badSqlGrammarCodes"> <value>-22,-28</value> </property> <property name="duplicateKeyCodes"> <value>-104</value> </property> <property name="dataIntegrityViolationCodes"> <value>-9</value> </property> <property name="dataAccessResourceFailureCodes"> <value>-80</value> </property> </bean> <bean id="HSQL" class="org.springframework.jdbc.support.SQLErrorCodes"> <property name="databaseProductName"> <value>HSQL Database Engine</value> </property> <property name="badSqlGrammarCodes"> <value>-22,-28</value> </property> <property name="duplicateKeyCodes"> <value>-104</value> </property> <property name="dataIntegrityViolationCodes"> <value>-9</value> </property> <property name="dataAccessResourceFailureCodes"> <value>-80</value> </property> </bean>
其余數據庫的錯誤碼內容也可以從這個文件之中獲得。下面我們來看看如何自定義異常處理。上面我們已經知道在org.springframework.jdbc.support包下有sql-error-codes.xml文件,在Spring啟動時會自動讀取這個文件中的錯誤碼,它為我們預分類了一些錯誤碼,而我們可以加強它,來使用我們自定義的異常。首先,定義一個異常類,我們就來自定義一下前面的-104錯誤,就是HSQL的重復鍵的問題:
package org.ourpioneer.vehicle.exception; import org.springframework.dao.DataIntegrityViolationException; public class VehicleDuplicateKeyException extends DataIntegrityViolationException { public VehicleDuplicateKeyException(String msg) { super(msg); } public VehicleDuplicateKeyException(String msg, Throwable cause) { super(msg, cause); } } package org.ourpioneer.vehicle.exception; import org.springframework.dao.DataIntegrityViolationException; public class VehicleDuplicateKeyException extends DataIntegrityViolationException { public VehicleDuplicateKeyException(String msg) { super(msg); } public VehicleDuplicateKeyException(String msg, Throwable cause) { super(msg, cause); } }
之后我們重新新建一個sql-error-codes.xml代碼,并將它放到類路徑的根目錄下,這樣Spring會發現它并使用我們自定義的文件,在配置中定義如下:
<bean id="HSQL" class="org.springframework.jdbc.support.SQLErrorCodes"> <property name="databaseProductName" value="HSQL Database Engine" /> <property name="useSqlStateForTranslation" value="false" /> <property name="customTranslations"> <list> <ref local="vehicleDuplicateKeyTranslation" /> </list> </property> </bean> <bean id="vehicleDuplicateKeyTranslation" class="org.springframework.jdbc.support.CustomSQLErrorCodesTranslation"> <property name="errorCodes" value="-104" /> <property name="exceptionClass" value="org.ourpioneer.vehicle.exception.VehicleDuplicateKeyException" /> </bean> <bean id="HSQL" class="org.springframework.jdbc.support.SQLErrorCodes"> <property name="databaseProductName" value="HSQL Database Engine" /> <property name="useSqlStateForTranslation" value="false" /> <property name="customTranslations"> <list> <ref local="vehicleDuplicateKeyTranslation" /> </list> </property> </bean> <bean id="vehicleDuplicateKeyTranslation" class="org.springframework.jdbc.support.CustomSQLErrorCodesTranslation"> <property name="errorCodes" value="-104" /> <property name="exceptionClass" value="org.ourpioneer.vehicle.exception.VehicleDuplicateKeyException" /> </bean>
HSQL的bean的名稱不要改,并將useSqlStateForTranslation置為false,就可以使用我們自己定義的異常類了。在主函數中移除try/catch塊,啟動程序,我們就可以看到如下內容:
從啟動信息中可以發現Spring發現了我們自定義的sql-error-codes.xml,并替換其中的HSQL數據庫處理部分,使用了我們定義的異常,模擬出主鍵重復的異常后,VehicleDuplicateKeyException就拋出了。除此之外,還可以實現SQLExceptionTranslator接口,并在JDBC模板中注入其實例來實現異常控制,我們來看一下,首先創建一個Translator類:
package org.ourpioneer.vehicle.exception; import java.sql.SQLException; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.UncategorizedSQLException; import org.springframework.jdbc.support.SQLExceptionTranslator; public class VehicleDuplicateKeyTranslator implements SQLExceptionTranslator { public DataAccessException translate(String task, String sql, SQLException ex) { if (task == null) { task = ""; } if (sql == null) { } if (ex.getErrorCode() == -104) { return new VehicleDuplicateKeyException(buildMessage(task, sql, ex)); } else { return new UncategorizedSQLException(task, sql, ex); } } private String buildMessage(String task, String sql, SQLException ex) { return "數據庫操作異常:" + task + "; SQL [" + sql + "]; " + ex.getMessage(); } } package org.ourpioneer.vehicle.exception; import java.sql.SQLException; import org.springframework.dao.DataAccessException; import org.springframework.jdbc.UncategorizedSQLException; import org.springframework.jdbc.support.SQLExceptionTranslator; public class VehicleDuplicateKeyTranslator implements SQLExceptionTranslator { public DataAccessException translate(String task, String sql, SQLException ex) { if (task == null) { task = ""; } if (sql == null) { } if (ex.getErrorCode() == -104) { return new VehicleDuplicateKeyException(buildMessage(task, sql, ex)); } else { return new UncategorizedSQLException(task, sql, ex); } } private String buildMessage(String task, String sql, SQLException ex) { return "數據庫操作異常:" + task + "; SQL [" + sql + "]; " + ex.getMessage(); } }
其中,要覆蓋translate方法,方法有三個參數,task表示當前操作要進行的任務是什么,sql就是執行的sql語句,ex表示SQLException,我們可以從中獲取異常信息,其處理代碼僅僅捕捉了錯誤碼為-104(HSQL數據庫)的錯誤,其余的配置信息可以根據需要來自行添加。之后要在Spring中重新配置它們:
<bean id="vehicleDuplicateKeyTranslator" class="org.ourpioneer.vehicle.exception.VehicleDuplicateKeyTranslator"></bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="exceptionTranslator" ref="vehicleDuplicateKeyTranslator" /> <property name="dataSource" ref="dataSource" /> </bean> <bean id="vehicleDAO" class="org.ourpioneer.vehicle.dao.VehicleDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean> <bean id="vehicleDuplicateKeyTranslator" class="org.ourpioneer.vehicle.exception.VehicleDuplicateKeyTranslator"></bean> <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"> <property name="exceptionTranslator" ref="vehicleDuplicateKeyTranslator" /> <property name="dataSource" ref="dataSource" /> </bean> <bean id="vehicleDAO" class="org.ourpioneer.vehicle.dao.VehicleDAOImpl"> <property name="jdbcTemplate" ref="jdbcTemplate" /> </bean>
調整DAO實現類的代碼:
public class VehicleDAOImpl extends SimpleJdbcDaoSupport implements VehicleDAO { … … public void insert(final Vehicle vehicle) { String sql = "insert into vehicle(ID,PLATE,CHASSIS,COLOR,WHEEL,SEAT) values(?,?,?,?,?,?)"; getJdbcTemplate().update(sql, vehicle.getId(),vehicle.getPlate(),vehicle.getChassis(),vehicle.getColor(),vehicle.getWheel(),vehicle.getSeat()); } … … } public class VehicleDAOImpl extends SimpleJdbcDaoSupport implements VehicleDAO { … … public void insert(final Vehicle vehicle) { String sql = "insert into vehicle(ID,PLATE,CHASSIS,COLOR,WHEEL,SEAT) values(?,?,?,?,?,?)"; getJdbcTemplate().update(sql, vehicle.getId(),vehicle.getPlate(),vehicle.getChassis(),vehicle.getColor(),vehicle.getWheel(),vehicle.getSeat()); } … … }
為了進行測試,其它代碼可不用修改,這樣繼續運行測試程序,同時將sql-error-codes.xml文件從類路徑的根路徑下去除,就可以得到如下結果:
Spring的JDBC模塊在自定義異常處理上也非常靈活,可以選擇自己喜歡的方式來實現。
關于Spring訪問數據庫異常的處理方法是什么問題的解答就分享到這里了,希望以上內容可以對大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關注億速云行業資訊頻道了解更多相關知識。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。