package jef.database.meta; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.SQLFeatureNotSupportedException; import java.sql.Statement; import java.util.ArrayList; import java.util.List; import jef.common.log.LogUtil; import jef.database.DbUtils; import org.apache.commons.lang.builder.ToStringBuilder; public class MetadataFeature { /** * 存入数据库时变大小写变化,如Oracle始终变大写 */ private Case defaultCase; /** * 大部分数据库都支持用引号来标注数据库对象。主要用途 1、让数据库认识到这是一个对象名而不是数据库关键字 2、保留原先的大小写 * 因此一般来说加了引号以后,数据库对象都变为混合大小写 */ private Case quotedCase; /** * 引号字符串 */ private String quoteChar; /** * 支持的表类型 */ private String[] tableTypes; /** * 数据库是否支持恢复点 */ private boolean supportsSavepoints; /** * JDBC版本 */ private int jdbcVersion; public Case getDefaultCase() { return defaultCase; } public void setDefaultCase(Case defaultCase) { this.defaultCase = defaultCase; } public Case getQuotedCase() { return quotedCase; } public void setQuotedCase(Case quotedCase) { this.quotedCase = quotedCase; } public boolean isSupportsSavepoints() { return supportsSavepoints; } public String getQuoteChar() { return quoteChar; } public void setQuoteChar(String quoteChar) { this.quoteChar = quoteChar; } public boolean supportsSavepoints() { return this.supportsSavepoints; } public MetadataFeature(DatabaseMetaData metadata) throws SQLException { this.quoteChar = metadata.getIdentifierQuoteString(); if (metadata.supportsMixedCaseIdentifiers() || metadata.storesMixedCaseIdentifiers()) { this.defaultCase = Case.MIXED_SENSITIVE; } else if (metadata.storesUpperCaseIdentifiers()) { this.defaultCase = Case.UPPER; } else if (metadata.storesLowerCaseIdentifiers()) { this.defaultCase = Case.LOWER; } else { throw new SQLException("The database driver " + metadata.getClass().getName() + " not support JDBC case feature."); } // 增加引号后。有三种情况 1、变为大小写敏感(大部分数据) 2、不支持引号(SQLITE)3、自动转小写(MYSQL开启对应开关后) if (metadata.supportsMixedCaseQuotedIdentifiers()) {// 大小写敏感 this.quotedCase = Case.MIXED_SENSITIVE; } else { this.quotedCase = this.defaultCase; } supportsSavepoints = metadata.supportsSavepoints(); try { jdbcVersion = caclJdbcVersion(metadata.getConnection()); } catch (SQLException e) { jdbcVersion = -1; } List<String> type = new ArrayList<String>(); ResultSet rs = null; try { rs = metadata.getTableTypes(); while (rs.next()) { type.add(rs.getString(1)); } } finally { DbUtils.close(rs); } this.tableTypes = type.toArray(new String[type.size()]); } private int caclJdbcVersion(Connection conn) throws SQLException { try { if (testJdbc4(conn)) return 4; if (testJdbc3(conn)) return 3; if (testJdbc2(conn)) return 2; return 1; } catch (Exception e) { LogUtil.exception(e); } return -1; } private boolean testJdbc2(Connection conn) { try { Statement st = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_READ_ONLY); DbUtils.close(st); } catch (SQLException e) { LogUtil.exception(e); } catch (AbstractMethodError e) { return false; } return true; } private boolean testJdbc3(Connection conn) { Statement st = null; ResultSet rs = null; try { st = conn.createStatement(); rs = st.getGeneratedKeys(); } catch (SQLFeatureNotSupportedException e) { return false; } catch (AbstractMethodError e) { return false; } catch (SQLException e) { } finally { DbUtils.close(rs); DbUtils.close(st); } return true; } private boolean testJdbc4(Connection conn) { try { conn.isValid(1); return true; } catch (AbstractMethodError e) { return false; } catch (SQLException e) { } try { Statement st = conn.createStatement(); DbUtils.close(st); st.isClosed(); return true; } catch (AbstractMethodError e) { return false; } catch (SQLException e) { } try { conn.createBlob(); return true; } catch (AbstractMethodError e) { return false; } catch (SQLException e) { return false; } } public String[] getTableTypes() { return tableTypes; } public int getJdbcVersion() { return jdbcVersion; } @Override public String toString() { return ToStringBuilder.reflectionToString(this); } }