Spring SQLErrorCodeSQLExceptionTranslator在Mysql/Oracle并存多数据源下的一个BUG

发现问题

最近公司想把原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")
<
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
可以通过在Nacos配置中心上配置两个不同的配置文件,分别对应MySQLOracle数据源的配置。在Spring Cloud应用中,通过使用Spring Cloud Config客户端,将这些配置文件下载到本地,并在应用程序中进行解析和使用。 以下是一个简单的示例,假设我们有两个数据源:MySQLOracle。我们可以在Nacos配置中心上创建两个不同的配置文件:mysql.properties和oracle.properties。示例配置如下: mysql.properties: ``` jdbc.url=jdbc:mysql://localhost:3306/mysql_db jdbc.username=mysql_user jdbc.password=mysql_password ``` oracle.properties: ``` jdbc.url=jdbc:oracle:thin:@localhost:1521:orcl jdbc.username=oracle_user jdbc.password=oracle_password ``` 然后,在Spring Cloud应用程序中,我们可以使用以下代码来加载这些配置文件,并在应用程序中使用它们: ```java @Configuration @RefreshScope public class DataSourceConfig { @Value("${jdbc.url}") private String url; @Value("${jdbc.username}") private String username; @Value("${jdbc.password}") private String password; @Bean(name = "mysqlDataSource") @Primary public DataSource mysqlDataSource() { return DataSourceBuilder.create() .url(url) .username(username) .password(password) .driverClassName("com.mysql.jdbc.Driver") .build(); } @Bean(name = "oracleDataSource") public DataSource oracleDataSource() { return DataSourceBuilder.create() .url(url) .username(username) .password(password) .driverClassName("oracle.jdbc.driver.OracleDriver") .build(); } } ``` 在这个例子中,我们使用@Value注释来注入配置文件中的属性。然后,我们可以使用DataSourceBuilder来构建数据源对象,并将其声明为Spring Bean。通过在@Bean注释中设置名称,我们可以在应用程序中引用这些数据源对象。 需要注意的是,使用Spring Cloud Config客户端从Nacos配置中心下载配置文件的具体细节可能会有所不同,具体取决于您的应用程序和环境。但是,上述示例应该可以帮助您了解如何在Spring Cloud应用程序中使用多个数据源配置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值