当前位置:   article > 正文

【spring boot】JdbcTemplate druid ClobProxyImpl cannot be cast to oracle.sql.CLOB

【spring boot】JdbcTemplate druid ClobProxyImpl cannot be cast to oracle.sql.CLOB

一·异常信息:

  1. ===2018-01-24 10:36:10.256 ERROR org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler Line:37 - Unexpected error occurred invoking async method 'public void com..service.SmsCallBackListenner.callback(com..pojo.SendInterfaceListEvent)'.
  2. org.springframework.jdbc.UncategorizedSQLException: PreparedStatementCallback; uncategorized SQLException for SQL [INSERT INTO SEND (..) VALUES(?,?,?,?,?,?,?,?,?,?,?);]; SQL state [null]; error code [0]; Error; nested exception is java.sql.SQLException: Error
  3. at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:90)
  4. at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
  5. at org.springframework.jdbc.support.AbstractFallbackSQLExceptionTranslator.translate(AbstractFallbackSQLExceptionTranslator.java:82)
  6. at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:655)
  7. at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:668)
  8. at org.springframework.jdbc.core.JdbcTemplate.batchUpdate(JdbcTemplate.java:956)
  9. at com..service.SmsCallBackListenner.insertSms(SmsCallBackListenner.java:44)
  10. at com..service.SmsCallBackListenner.callback(SmsCallBackListenner.java:40)
  11. at com..service.SmsCallBackListenner$$FastClassBySpringCGLIB$$7d92c1dc.invoke(<generated>)
  12. at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
  13. at org.springframework.aop.framework.CglibAopProxy$CglibMethodInvocation.invokeJoinpoint(CglibAopProxy.java:738)
  14. at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
  15. at org.springframework.aop.interceptor.AsyncExecutionInterceptor$1.call(AsyncExecutionInterceptor.java:115)
  16. at java.util.concurrent.FutureTask.run(FutureTask.java:266)
  17. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
  18. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
  19. at java.lang.Thread.run(Thread.java:745)
  20. Caused by: java.sql.SQLException: Error
  21. at com.alibaba.druid.pool.DruidDataSource.handleConnectionException(DruidDataSource.java:1392)
  22. at com.alibaba.druid.pool.DruidPooledConnection.handleException(DruidPooledConnection.java:136)
  23. at com.alibaba.druid.pool.DruidPooledStatement.checkException(DruidPooledStatement.java:71)
  24. at com.alibaba.druid.pool.DruidPooledPreparedStatement.setClob(DruidPooledPreparedStatement.java:607)
  25. at com..dao.InsertSmsSendBatchPreparedStatementSetter.setValues(InsertSmsSendBatchPreparedStatementSetter.java:29)
  26. at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:966)
  27. at org.springframework.jdbc.core.JdbcTemplate$4.doInPreparedStatement(JdbcTemplate.java:956)
  28. at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:639)
  29. ... 13 common frames omitted
  30. Caused by: java.lang.ClassCastException: com.alibaba.druid.proxy.jdbc.ClobProxyImpl cannot be cast to oracle.sql.CLOB
  31. at oracle.jdbc.driver.OraclePreparedStatement.setClob(OraclePreparedStatement.java:6805)
  32. at oracle.jdbc.driver.OraclePreparedStatementWrapper.setClob(OraclePreparedStatementWrapper.java:162)
  33. at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setClob(FilterChainImpl.java:3054)
  34. at com.alibaba.druid.filter.FilterAdapter.preparedStatement_setClob(FilterAdapter.java:1195)
  35. at com.alibaba.druid.filter.FilterChainImpl.preparedStatement_setClob(FilterChainImpl.java:3051)
  36. at com.alibaba.druid.proxy.jdbc.PreparedStatementProxyImpl.setClob(PreparedStatementProxyImpl.java:297)
  37. at com.alibaba.druid.pool.DruidPooledPreparedStatement.setClob(DruidPooledPreparedStatement.java:605)
  38. ... 17 common frames omitted

二·背景描述

oracle 数据库,查询带有clob类型字段的A表,并存储到 实体类,实体类对应的字段 类型也为 oracle.sql.CLOB。
经过业务处理后 把该字段的值插入到 到 B表 的也为clob类型字段时  报出 如上异常。
<dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>druid-spring-boot-starter</artifactId>
   <version>1.1.1</version>
</dependency>
<dependency>
   <groupId>com.oracle</groupId>
   <artifactId>ojdbc6g</artifactId>
   <version>11.2.0.4.0</version>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>

三·异常分析

主要是 使用的druid 连接池导致的,JdbcTemplate本身没有直接关系。
我们看到错误日志 ,有一个类型转换异常。
Caused by: java.lang.ClassCastException: com.alibaba.druid.proxy.jdbc.ClobProxyImpl cannot be cast to oracle.sql.CLOB
oracle 数据库驱动 clob 使用的是oracle.sql.CLOB 而
 Druid 我们 从  ClobProxyImpl  和 DruidPooledPreparedStatement 可以看到  使用的是 java.sql.Clob
而 这并没有关系 ,会在 驱动包里的 OraclePreparedStatement 里把clob 强转成 CLOB

继续看源码 :在FilterChainImpl 里的connection_createClob 方法:

  1. @Override
  2. public Clob connection_createClob(ConnectionProxy connection) throws SQLException {
  3. if (this.pos < filterSize) {
  4. return nextFilter().connection_createClob(this, connection);
  5. }
  6. Clob clob = connection.getRawObject().createClob();
  7. return wrap(connection, clob);
  8. }
最后 return的 是 FilterChainImpl 下的 wrap:

  1. public ClobProxy wrap(ConnectionProxy conn, Clob clob) {
  2. if (clob == null) {
  3. return null;
  4. }
  5. if (clob instanceof NClob) {
  6. return wrap(conn, (NClob) clob);
  7. }
  8. return new ClobProxyImpl(dataSource, conn, clob);
  9. }

导致 类型转换异常的原因就是这样。 至于为什么这么做,并不清楚,可能我们使用的姿势并不对,druid 可能并不允许我们这么做。

四·解决方案

从数据库读取的clob字段的时候 ,实体类 相应字段 使用String 类型存储,读取的时候 也 通过getSting 去 获取clob的值:
  1. @Override
  2. public Object mapRow(ResultSet resultSet, int i) throws SQLException {
  3. SendInterface sendInterface = new SendInterface();
  4. sendInterface.setSendId(resultSet.getString("SEND_ID"));
  5. sendInterface.setMobileTo(resultSet.getString("MOBILE_TO"));
  6. sendInterface.setSendMsg(resultSet.getString("SEND_MSG"));
  7. sendInterface.setExtendNumber(resultSet.getString("EXTEND_NUMBER"));
  8. sendInterface.setSysTime(resultSet.getDate("SYS_TIME"));
  9. sendInterface.setPreSendTime(resultSet.getDate("PRE_SEND_TIME"));
  10. return sendInterface;
  11. }
存储 字符串 在 表 clob字段的时候 也不需要你把 String 转为 clob 再存 ,因为Druid 都 替你做了,



DruidLobCreator:

  1. @Override
  2. public void setClobAsAsciiStream(PreparedStatement ps, int paramIndex, InputStream asciiStream, int contentLength)
  3. throws SQLException {
  4. if (asciiStream != null) {
  5. Clob clob = ps.getConnection().createClob();
  6. OutputStream out = clob.setAsciiStream(1);
  7. final int BUFFER_SIZE = 4096;
  8. try {
  9. byte[] buffer = new byte[BUFFER_SIZE];
  10. int bytesRead = -1;
  11. while ((bytesRead = asciiStream.read(buffer)) != -1) {
  12. out.write(buffer, 0, bytesRead);
  13. }
  14. out.flush();
  15. } catch (Exception e) {
  16. throw new SQLException("setClob error", e);
  17. } finally {
  18. JdbcUtils.close(asciiStream);
  19. JdbcUtils.close(out);
  20. }
  21. ps.setClob(paramIndex, clob);
  22. } else {
  23. ps.setClob(paramIndex, (Clob) null);
  24. }
  25. }
  1. @Override
  2. public void setClobAsString(PreparedStatement ps, int paramIndex, String content) throws SQLException {
  3. Clob clob = ps.getConnection().createClob();
  4. clob.setString(1, content);
  5. ps.setClob(paramIndex, clob);
  6. }



声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/141589
推荐阅读
相关标签
  

闽ICP备14008679号