关于java.sql.ResultSetMetaData

   一直在考虑如何查找一行或多行数据,并把这些数据按需求拼成插入或者修改语句。在参考了java.sql.ResultSetMetaData的API后,总算是实现了。  

  再来看下它的典型应用:

 

Java代码   收藏代码
  1. ResultSet rs = stmt.executeQuery("SELECT a, b, c FROM TABLE2");  
  2. ResultSetMetaData rsmd = rs.getMetaData();  
  3. int numberOfColumns = rsmd.getColumnCount();  
  4. boolean b = rsmd.isSearchable(1);  

   

其实个人认为ResultSetMetaData完全可以理解为一个列结果集,其中getColumnCount()方法用于获取这个结果集的列数

 以下为一些常用方法:

 

Java代码   收藏代码
  1. getColumnName  
  2. String getColumnName(int column)  
  3.         throws SQLException获取指定列的名称。   
  4.   
  5. 参数:  
  6. column - 第一列是 1,第二个列是 2,……   
  7. 返回:  
  8. 列名称   
  9. 抛出:   
  10. SQLException - 如果发生数据库访问错误  

 

Java代码   收藏代码
  1. isSearchable  
  2. boolean isSearchable(int column)  
  3.             throws SQLException指示是否可以在 where 子句中使用指定的列。   
  4.   
  5. 参数:  
  6. column - 第一列是 1,第二个列是 2,……   
  7. 返回:  
  8. 如果是这样,则返回 true;否则返回 false   
  9. 抛出:   
  10. SQLException - 如果发生数据库访问错误  

 

所以可以利用这个接口完成类似于JAVA反射机制的动态获取表数据的操作,以下代码仅供参考:

Java代码  
  1. public String getInsertSql(String 列名, String 列值,String 表名) {  
  2.     Connection conn = getConnection();  
  3.    Statement st=null;  
  4.     ResultSet rs=null;  
  5.     ResultSetMetaData metaData = null;  
  6. try{  
  7.      st=conn.createStatement();  
  8.       rs=st.executeQuery("select * from "+tableName+" where "+columnName+" = "+columnValue);  
  9.       metaData=rs.getMetaData();  
Java代码   收藏代码
  1. result.append("(");  
Java代码   收藏代码
  1.      for(int i=1;i<=metaData.getColumnCount();i++){  
  2.      if(i!=metaData.getColumnCount()){  
  3.       result.append(metaData.getColumnName(i).toLowerCase()+",");  
  4.      }else{  
  5.       result.append(metaData.getColumnName(i).toLowerCase());  
  6.      }  
  7.     }  
Java代码   收藏代码
  1. result.append(")");  
Java代码   收藏代码
  1. result.append(" values (");  
Java代码   收藏代码
  1.   for(int i=1;i<=metaData.getColumnCount();i++){  
  2.       //TODO:日期类型怎么处理?  
  3.       try{  
  4.        result.append("'"+nvlToString(rs.getString(i))+"'");  
  5.       }catch(Exception e){  
  6.        java.util.Date date=rs.getDate(i);  
  7.        result.append("'"+format.format(date)+"'");  
  8.       }  
  9.       if(i!=metaData.getColumnCount()) result.append(",");      
  10.      }  
Java代码   收藏代码
  1. result.append(")");  
Java代码   收藏代码
  1. //关闭数据库连接(略过)  
Java代码   收藏代码
  1. }  
<think>好的,我现在要解决用户遇到的java.sql.SQLException异常,具体是“Closed Statement: getMetaData”。首先,我需要理解这个错误的原因。根据用户提供的引用,特别是引用[4],这个问题可能与JDBC驱动版本不兼容有关,比如ojdbc版本和JDK版本不匹配。用户提到将ojdbc11换成ojdbc6后问题解决,而他们的JDK是1.8,这可能是一个关键点。 接下来,我需要考虑其他可能的原因。比如,用户可能在执行完Statement后没有正确关闭资源,导致后续操作尝试访问已关闭的Statement。例如,如果在调用getMetaData()之前Statement已经被关闭,就会触发这个异常。另外,数据库连接池的配置问题也可能导致连接提前关闭,比如连接超时设置过短,或者连接被自动回收。 然后,我需要检查资源管理是否正确。用户可能在使用MyBatis或类似框架时,没有正确管理SqlSession或Connection,导致在获取元数据时连接已经关闭。例如,引用[2]提到sqlSessionTemplate.getConnection()遇到连接关闭的问题,可能涉及框架配置或资源释放的顺序问题。 此外,异常处理不当也可能导致问题。例如,在发生其他异常时,资源被关闭,但后续代码仍尝试使用已关闭的资源。这时候需要确保在finally块中正确关闭资源,避免异常导致资源泄漏或提前关闭。 可能的解决方案包括: 1. 检查并更换合适的JDBC驱动版本,确保与JDK版本兼容。 2. 检查代码中的资源管理,确保Statement和Connection在使用完毕前不被关闭。 3. 使用连接池时,调整配置参数,如超时时间和验证查询。 4. 在框架配置中,如MyBatis,确保SqlSession的生命周期管理正确,避免提前释放连接。 5. 添加日志记录,追踪资源关闭的时机,帮助定位问题源头。 需要验证这些方案的有效性,比如更换驱动版本后是否异常消失,或者调整资源关闭顺序后问题是否解决。同时,用户提到的引用[3]关于流被关闭的错误,可能与结果集处理不当有关,但当前问题更直接相关的是Statement的状态。因此,重点应放在驱动版本、资源管理和连接池配置上。 总结来说,用户需要逐步排查驱动兼容性、资源管理代码、连接池设置,以及框架配置,以解决“Closed Statement: getMetaData”异常。</think>### 解决方案:`java.sql.SQLException: Closed Statement: getMetaData` #### 1. **检查JDBC驱动版本兼容性** - **问题根源**:JDBC驱动版本与JDK版本不兼容可能导致`Statement`对象被意外关闭。例如,JDK 1.8应使用`ojdbc6`或`ojdbc7`,而非`ojdbc11`(适用于JDK 11+)[^4]。 - **操作步骤**: 1. 确认项目使用的JDK版本(如1.8)。 2. 替换驱动为匹配的版本(如`ojdbc6`)。 ```xml <!-- Maven示例 --> <dependency> <groupId>com.oracle.database.jdbc</groupId> <artifactId>ojdbc6</artifactId> <version>11.2.0.4</version> </dependency> ``` #### 2. **确保`Statement`未提前关闭** - **问题根源**:若在调用`getMetaData()`前已关闭`Statement`,会触发此异常。 - **操作步骤**: 1. 检查代码中是否在操作完成后过早调用`statement.close()`。 2. 使用`try-with-resources`确保资源按顺序释放: ```java try (Connection conn = dataSource.getConnection(); Statement stmt = conn.createStatement(); ResultSet rs = stmt.executeQuery("SELECT * FROM table")) { ResultSetMetaData metaData = rs.getMetaData(); // 正确位置 } // 自动关闭资源 ``` #### 3. **验证数据库连接池配置** - **问题根源**:连接池可能因超时或闲置回收导致连接关闭。 - **操作步骤**(以HikariCP为例): ```java HikariConfig config = new HikariConfig(); config.setJdbcUrl("jdbc:oracle:thin:@localhost:1521:ORCL"); config.setUsername("user"); config.setPassword("password"); config.setConnectionTimeout(30000); // 超时时间设为30秒 config.setIdleTimeout(600000); // 闲置超时延长 config.addDataSourceProperty("oracle.jdbc.autoCommitSpecCompliant", "false"); // 解决特定兼容性问题 HikariDataSource ds = new HikariDataSource(config); ``` #### 4. **框架配置优化(如MyBatis)** - **问题根源**:MyBatis可能因`SqlSession`管理不当导致连接关闭[^2]。 - **操作步骤**: 1. 避免手动调用`sqlSession.close()`前获取连接。 2. 通过`SqlSessionTemplate`自动管理生命周期: ```java @Autowired private SqlSessionTemplate sqlSessionTemplate; public void queryData() { try (Connection conn = sqlSessionTemplate.getConnection()) { DatabaseMetaData dbMetaData = conn.getMetaData(); // 在有效作用域内操作 } // 自动释放连接 } ``` #### 5. **添加调试日志** - 在关键节点记录`Statement`状态: ```java System.out.println("Statement is closed? " + stmt.isClosed()); // 输出状态 ResultSetMetaData metaData = rs.getMetaData(); // 触发异常的代码 ``` --- ### 相关问题 1. **如何排查JDBC驱动版本与JDK的兼容性问题?** 2. **MyBatis中如何正确管理数据库连接以避免提前关闭?** 3. **数据库连接池超时配置有哪些最佳实践?** --- 通过以上步骤,可系统解决因驱动版本、资源管理或配置不当导致的`Closed Statement: getMetaData`异常。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值