原文链接:http://sarin.javaeye.com/blog/888458

今天我们将谈谈Spring访问数据库异常的处理方法,使用JDBC
API时,很多操作都要声明抛出java.sql.SQLException异常,通常情况下是要制定异常处理策略。

使用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的ORM。

转载于:https://www.cnblogs.com/cczhoufeng/archive/2013/02/20/2918584.html

Spring访问数据库异常的处理方法(转)相关推荐

  1. matlab如何连接数据库,matlab访问数据库的几种方法

    matlab访问数据库的几种方法 一.通过MATLAB 提供的数据库引擎, 以下是MATLAB ,DATABASE TOOLBOX中的例子, 通过ODBC/JDBC 接口访问具体的数据库 functi ...

  2. Spring 访问数据库

    数据库基本上是现代应用程序的标准存储,绝大多数程序都把自己的业务数据存储在关系数据库中,可见,访问数据库几乎是所有应用程序必备能力. 我们在前面已经介绍了Java程序访问数据库的标准接口JDBC,它的 ...

  3. 第一步:Spring访问数据库(jdbcTemplate)

    2019独角兽企业重金招聘Python工程师标准>>> 首先当然是访问数据库,以前学习php的时候,就是从留言板.登录等功能开始学习的,之所以这样学习无非就是因为从前台到后台,该有的 ...

  4. SpringBoot实战(四)之使用JDBC和Spring访问数据库

    这里演示的是h2databse示例,所以简单的介绍普及下h2database相关知识 H2数据库是一个开源的关系型数据库. H2是一个嵌入式数据库引擎,采用java语言编写,不受平台的限制,同时H2提 ...

  5. idea关于连接mysql数据库异常解决的方法

    ?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDat ...

  6. linux c++编写访问mysql程序,访问数据库出错,解决方法

    错误提示:Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) 摘要:解决不能通过m ...

  7. 事务传播机制/数据库异常解析——2016-8-13分享总结

    一. 事务的传播机制/required 跟 required new 的使用与区别 基础回顾 1.1 事务的隔离级别: ISOLATION_READ_UNCOMMITTED(读未提交) ISOLATI ...

  8. Java程序员从笨鸟到菜鸟之(七十八)细谈Spring(七)spring之JDBC访问数据库及配置详解

    利用spring访问数据库是我们ssh程序中必不可少的步骤,在没有hibernate之前,我们一般都用jdbc访问数据库,所以用jdbc访问数据库必不可少的要进行一些配置,spring中为我们提供了访 ...

  9. Spring实战6-利用Spring和JDBC访问数据库

    主要内容 定义Spring的数据访问支持 配置数据库资源 使用Spring提供的JDBC模板 写在前面:经过上一篇文章的学习,我们掌握了如何写web应用的控制器层,不过由于只定义了SpitterRep ...

最新文章

  1. Ansible中文手册
  2. virtio后端驱动详解
  3. js list删除指定元素_删除js数组中的指定元素,有这两步就够了
  4. Linux各个目录的作用及内容
  5. 多用途app软件业务介绍官网模板
  6. 漫步线性代数二十七——矩阵对角化
  7. 1月4日编程基础hash
  8. 35 岁财务自由的小马哥,我想跟他学学!
  9. 【转载】Eclipse快捷键 10个最有用的快捷键
  10. multisim扩大工作区_利用Multisim 10仿真软件对共射投放大电路进行了计算机辅助设计和仿真...
  11. matlab鲍威尔算法,鲍威尔法matlab程序
  12. 数据管理系统 php,dms: 数据管理系统;采用mvc模型,存php原生操作无模板引擎;响应式前端框架huiadmin套用,扁平化风格,兼容移动端;...
  13. 智慧交通信号控制系统梗概
  14. 代码分析工具 - SonarQube
  15. 【蓝桥杯】-- 竞赛规则及说明(Python程序设计)
  16. python如何更改背景颜色_python背景颜色,python改背景色
  17. spring中的aop的xml配置方式简单实例
  18. 漏洞平台之pikachu详细图文搭建教程
  19. git服务器更换IP地址后本地仓库设置
  20. matplotlib官方中文手册pdf下载

热门文章

  1. linux动态链接库---一篇讲尽
  2. 《Shell脚本学习指南》第一章 背景知识
  3. 【onethink1.0】HTML模板获取前台和后台当前登录用户名
  4. Reverse String
  5. linux nexus bulid
  6. 浅玩JavaScript的数据类型判断
  7. 流程控制 - PHP手册笔记
  8. 如何访问“我的网站”
  9. php 百度收录api_php使用百度翻译api示例分享
  10. LA3266田忌赛马