新聞中心
使用JDBC API時,很多操作都要聲明拋出java.sql.SQLException異常,通常情況下是要制定異常處理策略。而Spring的JDBC模塊為我們提供了一套異常處理機制,這套異常系統(tǒng)的基類是DataAccessException,它是RuntimeException的一種類型,那么就不用強制去捕捉異常了,Spring的異常體系如下:

專注于為中小企業(yè)提供成都做網(wǎng)站、網(wǎng)站建設服務,電腦端+手機端+微信端的三站合一,更高效的管理,為中小企業(yè)璧山免費做網(wǎng)站提供優(yōu)質的服務。我們立足成都,凝聚了一批互聯(lián)網(wǎng)行業(yè)人才,有力地推動了成百上千家企業(yè)的穩(wěn)健成長,幫助中小企業(yè)通過網(wǎng)站建設實現(xiàn)規(guī)模擴充和轉變。
目前為止我們還沒有明確地處理Spring中JDBC模塊的異常。要理解它的異常處理機制,我們來做幾個測試??聪旅娴臏y試代碼:
- 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狀態(tài)(不同的數(shù)據(jù)庫系統(tǒng)會有不同):
關于HSQL數(shù)據(jù)庫的錯誤碼可以到org.hsqldb.Trace類中查看,只要注意運行結果會有一個負號,而類中定義的是沒有負號的。這樣就知道了這個錯誤的具體含義,比如104:***約束驗證失敗。這就是我們故意設置的重復主鍵問題。
Spring的JDBC模塊為我們預定義了一些錯誤代碼,它存儲在org.springframework.jdbc.support包下的sql-error-codes.xml文件中,其中描述HSQL的內(nèi)容為:
HSQL Database Engine -22,-28 -104 -9 -80 HSQL Database Engine -22,-28 -104 -9 -80
其余數(shù)據(jù)庫的錯誤碼內(nèi)容也可以從這個文件之中獲得。下面我們來看看如何自定義異常處理。上面我們已經(jīng)知道在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會發(fā)現(xiàn)它并使用我們自定義的文件,在配置中定義如下:
HSQL的bean的名稱不要改,并將useSqlStateForTranslation置為false,就可以使用我們自己定義的異常類了。在主函數(shù)中移除try/catch塊,啟動程序,我們就可以看到如下內(nèi)容:
從啟動信息中可以發(fā)現(xiàn)Spring發(fā)現(xiàn)了我們自定義的sql-error-codes.xml,并替換其中的HSQL數(shù)據(jù)庫處理部分,使用了我們定義的異常,模擬出主鍵重復的異常后,VehicleDuplicateKeyException就拋出了。除此之外,還可以實現(xiàn)SQLExceptionTranslator接口,并在JDBC模板中注入其實例來實現(xiàn)異??刂疲覀儊砜匆幌?,首先創(chuàng)建一個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 "數(shù)據(jù)庫操作異常:" + 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 "數(shù)據(jù)庫操作異常:" + task + "; SQL [" + sql + "]; " + ex.getMessage();
- }
- }
其中,要覆蓋translate方法,方法有三個參數(shù),task表示當前操作要進行的任務是什么,sql就是執(zhí)行的sql語句,ex表示SQLException,我們可以從中獲取異常信息,其處理代碼僅僅捕捉了錯誤碼為-104(HSQL數(shù)據(jù)庫)的錯誤,其余的配置信息可以根據(jù)需要來自行添加。之后要在Spring中重新配置它們:
- class="org.ourpioneer.vehicle.exception.VehicleDuplicateKeyTranslator">
- class="org.ourpioneer.vehicle.exception.VehicleDuplicateKeyTranslator">
調(diào)整DAO實現(xiàn)類的代碼:
- 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());
- }
- … …
- }
為了進行測試,其它代碼可不用修改,這樣繼續(xù)運行測試程序,同時將sql-error-codes.xml文件從類路徑的根路徑下去除,就可以得到如下結果:
Spring的JDBC模塊在自定義異常處理上也非常靈活,可以選擇自己喜歡的方式來實現(xiàn)。希望對使用者有用,歡迎交流,下一部分開始介紹Spring的ORM。
文章題目:Spring訪問數(shù)據(jù)庫異常的處理方法
本文網(wǎng)址:http://www.dlmjj.cn/article/cdooped.html


咨詢
建站咨詢
