发现问题
最近公司想把原Oracle数据库都迁移到Mysql,这个切换需要一段时间过渡,所以存在Oracle、Mysql在项目中同时使用的情况。这样就需要使用多数据源的技术。多数据源配置本身比较简单,但有一个场景出现了一点小意外。考虑如下代码:
// 自己通过try-catch实现insertOrUpdate语义
Data data = new Data();
try{
dataMapper.insert(data);
} catch (DuplicateKeyException e) {
dataMapper.update(data);
}
可是意外发生了,这里DuplicateKeyException异常并没有被捕获,或者说这里抛出的异常并不是我们想要捕获的,而是一个名叫DataAccessResourceFailureException的异常,异常栈信息片段如下。
org.springframework.dao.DataAccessResourceFailureException:
### Error updating database. Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (...) violated
### The error may involve DataMapper.insert-Inline
### The error occurred while setting parameters
### SQL: INSERT INTO ... VALUES (?, ?, ?, ?, ?)
### Cause: java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (PBOC.PK_PB_NDES_DATA_RELATION) violated
; SQL []; ORA-00001: unique constraint (...) violated
; nested exception is java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (...) violated
at org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator.doTranslate(SQLErrorCodeSQLExceptionTranslator.java:251) ~[spring-jdbc-4.2.0.RELEASE.jar:4.2.0.RELEASE]
at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:73) ~[spring-jdbc-4.2.0.RELEASE.jar:4.2.0.RELEASE]
at org.mybatis.spring.MyBatisExceptionTranslator.translateExceptionIfPossible(MyBatisExceptionTranslator.java:73) ~[mybatis-spring-1.2.2.jar:1.2.2]
at org.mybatis.spring.SqlSessionTemplate$SqlSessionInterceptor.invoke(SqlSessionTemplate.java:371) ~[mybatis-spring-1.2.2.jar:1.2.2]
at com.sun.proxy.$Proxy29.insert(Unknown Source) ~[na:na]
at org.mybatis.spring.SqlSessionTemplate.insert(SqlSessionTemplate.java:240) ~[mybatis-spring-1.2.2.jar:1.2.2]
开始排查
先打开DataAccessResourceFailureException这个类,看了一眼注释,发现跟预期完全不对路啊。上面的异常栈已经说了,driver层给出的异常 java.sql.SQLIntegrityConstraintViolationException: ORA-00001: unique constraint (…) violated 说明这个异常确实是唯一键冲突,但到spring这里异常类型出问题了。
/**
* Data access exception thrown when a resource fails completely:
* for example, if we can't connect to a database using JDBC.
*
* @author Rod Johnson
* @author Thomas Risberg
*/
@SuppressWarnings("serial")
<