Spring访问数据库异常的处理方法(转)
原文链接: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访问数据库异常的处理方法(转)相关推荐
- matlab如何连接数据库,matlab访问数据库的几种方法
matlab访问数据库的几种方法 一.通过MATLAB 提供的数据库引擎, 以下是MATLAB ,DATABASE TOOLBOX中的例子, 通过ODBC/JDBC 接口访问具体的数据库 functi ...
- Spring 访问数据库
数据库基本上是现代应用程序的标准存储,绝大多数程序都把自己的业务数据存储在关系数据库中,可见,访问数据库几乎是所有应用程序必备能力. 我们在前面已经介绍了Java程序访问数据库的标准接口JDBC,它的 ...
- 第一步:Spring访问数据库(jdbcTemplate)
2019独角兽企业重金招聘Python工程师标准>>> 首先当然是访问数据库,以前学习php的时候,就是从留言板.登录等功能开始学习的,之所以这样学习无非就是因为从前台到后台,该有的 ...
- SpringBoot实战(四)之使用JDBC和Spring访问数据库
这里演示的是h2databse示例,所以简单的介绍普及下h2database相关知识 H2数据库是一个开源的关系型数据库. H2是一个嵌入式数据库引擎,采用java语言编写,不受平台的限制,同时H2提 ...
- idea关于连接mysql数据库异常解决的方法
?useUnicode=true&characterEncoding=UTF-8&useJDBCCompliantTimezoneShift=true&useLegacyDat ...
- linux c++编写访问mysql程序,访问数据库出错,解决方法
错误提示:Can't connect to local MySQL server through socket '/var/run/mysqld/mysqld.sock' (2) 摘要:解决不能通过m ...
- 事务传播机制/数据库异常解析——2016-8-13分享总结
一. 事务的传播机制/required 跟 required new 的使用与区别 基础回顾 1.1 事务的隔离级别: ISOLATION_READ_UNCOMMITTED(读未提交) ISOLATI ...
- Java程序员从笨鸟到菜鸟之(七十八)细谈Spring(七)spring之JDBC访问数据库及配置详解
利用spring访问数据库是我们ssh程序中必不可少的步骤,在没有hibernate之前,我们一般都用jdbc访问数据库,所以用jdbc访问数据库必不可少的要进行一些配置,spring中为我们提供了访 ...
- Spring实战6-利用Spring和JDBC访问数据库
主要内容 定义Spring的数据访问支持 配置数据库资源 使用Spring提供的JDBC模板 写在前面:经过上一篇文章的学习,我们掌握了如何写web应用的控制器层,不过由于只定义了SpitterRep ...
最新文章
- Ansible中文手册
- virtio后端驱动详解
- js list删除指定元素_删除js数组中的指定元素,有这两步就够了
- Linux各个目录的作用及内容
- 多用途app软件业务介绍官网模板
- 漫步线性代数二十七——矩阵对角化
- 1月4日编程基础hash
- 35 岁财务自由的小马哥,我想跟他学学!
- 【转载】Eclipse快捷键 10个最有用的快捷键
- multisim扩大工作区_利用Multisim 10仿真软件对共射投放大电路进行了计算机辅助设计和仿真...
- matlab鲍威尔算法,鲍威尔法matlab程序
- 数据管理系统 php,dms: 数据管理系统;采用mvc模型,存php原生操作无模板引擎;响应式前端框架huiadmin套用,扁平化风格,兼容移动端;...
- 智慧交通信号控制系统梗概
- 代码分析工具 - SonarQube
- 【蓝桥杯】-- 竞赛规则及说明(Python程序设计)
- python如何更改背景颜色_python背景颜色,python改背景色
- spring中的aop的xml配置方式简单实例
- 漏洞平台之pikachu详细图文搭建教程
- git服务器更换IP地址后本地仓库设置
- matplotlib官方中文手册pdf下载