All Downloads are FREE. Search and download functionalities are using the official Maven repository.

sf.database.dbinfo.DBInfoBuilder Maven / Gradle / Ivy

The newest version!
package sf.database.dbinfo;

import sf.tools.StringUtils;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;

public class DBInfoBuilder {

    protected DataSource dataSource;
    protected Set excludedTables = new TreeSet(String.CASE_INSENSITIVE_ORDER);

    protected Connection conn = null;
    protected DatabaseMetaData dbMeta = null;

    protected String[] removedTableNamePrefixes = null;

    protected String driverName;
    protected String driverVersion;
    protected int driverMajorVersion;

    public DBInfoBuilder(DataSource dataSource) {
        if (dataSource == null) {
            throw new IllegalArgumentException("dataSource can not be null.");
        }
        this.dataSource = dataSource;
    }

    public void addExcludedTable(String... excludedTables) {
        if (excludedTables != null) {
            Collections.addAll(this.excludedTables, excludedTables);
        }
    }

    /**
     * 设置需要被移除的表名前缀,仅用于生成 modelName 与 baseModelName 例如表名 "osc_account",移除前缀
     * "osc_" 后变为 "account"
     */
    public void setRemovedTableNamePrefixes(String... removedTableNamePrefixes) {
        this.removedTableNamePrefixes = removedTableNamePrefixes;
    }

    public List build() {
        System.out.println("Build TableInfo ...");
        try (Connection conn = dataSource.getConnection()) {
            this.conn = conn;
            dbMeta = conn.getMetaData();
            this.driverName = dbMeta.getDriverName();
            this.driverVersion = dbMeta.getDriverVersion();
            this.driverMajorVersion = dbMeta.getDatabaseMajorVersion();

            List ret = new ArrayList();
            buildTableNames(ret);
            for (TableInfo TableInfo : ret) {
                buildPrimaryKey(TableInfo);
                buildColumnMetas(TableInfo);
            }
            return ret;
        } catch (SQLException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 通过继承并覆盖此方法,跳过一些不希望处理的 table,定制更加灵活的 table 过滤规则
     * @return 返回 true 时将跳过当前 tableName 的处理
     */
    protected boolean isSkipTable(String tableName) {
        return false;
    }

    /**
     * 不同数据库 dbMeta.getTables(...) 的 schemaPattern 参数意义不同
* 1:oracle 数据库这个参数代表 dbMeta.getUserName()
* 2:postgresql 数据库中需要在 jdbcUrl中配置 * schemaPatter,例如:jdbc:postgresql://localhost:15432/djpt?currentSchema= * public,sys,app 最后的参数就是搜索schema的顺序,DruidPlugin 下测试成功
* 3:开发者若在其它库中发现工作不正常,可通过继承 MetaBuilder并覆盖此方法来实现功能 */ protected ResultSet getTablesResultSet() throws SQLException { String schemaPattern = dbMeta.getDriverName().toLowerCase().contains("oracle") ? dbMeta.getUserName() : null; return dbMeta.getTables(conn.getCatalog(), schemaPattern, null, new String[]{"TABLE", "VIEW"}); } protected void buildTableNames(List ret) { try (ResultSet rs = getTablesResultSet()) { while (rs.next()) { String tableName = rs.getString("TABLE_NAME"); if (excludedTables.contains(tableName)) { System.out.println("Skip table :" + tableName); continue; } if (isSkipTable(tableName)) { System.out.println("Skip table :" + tableName); continue; } TableInfo info = new TableInfo(); info.setName(tableName); info.setRemarks(rs.getString("REMARKS")); info.setCatalog(rs.getString("TABLE_CAT")); info.setSchema(rs.getString("TABLE_SCHEM")); info.setType("TABLE_TYPE"); ret.add(info); } } catch (SQLException e) { throw new RuntimeException(e); } } protected void buildPrimaryKey(TableInfo TableInfo) { try (ResultSet rs = dbMeta.getPrimaryKeys(conn.getCatalog(), null, TableInfo.getName())) { StringBuilder primaryKeys = new StringBuilder(); boolean f = false; while (rs.next()) { String primaryKey = rs.getString("COLUMN_NAME"); primaryKeys.append(f ? "," : "").append(primaryKey); f = true; } TableInfo.setPrimaryKey(primaryKeys.toString()); } catch (SQLException e) { throw new RuntimeException(e); } } /** * 文档参考: http://dev.mysql.com/doc/connector-j/en/connector-j-reference-type- * conversions.html *

* JDBC 与时间有关类型转换规则,mysql 类型到 java 类型如下对应关系: DATE java.sql.Date DATETIME * java.sql.Timestamp TIMESTAMP[(M)] java.sql.Timestamp TIME java.sql.Time *

* 对数据库的 DATE、DATETIME、TIMESTAMP、TIME 四种类型注入 new * java.util.Date()对象保存到库以后可以达到“秒精度” 为了便捷性,getter、setter 方法中对上述四种字段类型采用 * java.util.Date,可通过定制 TypeMapping 改变此映射规则 */ protected void buildColumnMetas(TableInfo tableInfo) { String sql = forTableBuilderDoBuild(tableInfo.getName()); try (Statement stm = conn.createStatement(); ResultSet rs = stm.executeQuery(sql)) { ResultSetMetaData rsmd = rs.getMetaData(); for (int i = 1; i <= rsmd.getColumnCount(); i++) { ColumnInfo cm = getColumn(tableInfo, rsmd.getColumnName(i)); tableInfo.getColumnInfos().add(cm); } } catch (SQLException e) { throw new RuntimeException(e); } } public String forTableBuilderDoBuild(String tableName) { String sql = null; if (this.driverName.toLowerCase().contains("mysql")) { sql = "select * from `" + tableName + "` where 1 = 2"; } else { sql = "select * from " + tableName + " where 1 = 2"; } return sql; } /** * 返回指定的列的信息,如果没有找到该列返回null * @param tableInfo 表名 * @param column 列名 * @return 如果没有找到该列返回null * @throws SQLException */ public ColumnInfo getColumn(TableInfo tableInfo, String column) throws SQLException { DatabaseMetaData databaseMetaData = conn.getMetaData(); String schema = tableInfo.getSchema(); String tableName = tableInfo.getName(); int n = tableName.indexOf('.'); if (n > 0) {// 尝试从表名中计算schema schema = tableName.substring(0, n); tableName = tableName.substring(n + 1); } ResultSet rs = null; try { rs = databaseMetaData.getColumns(null, schema, tableName, column); ColumnInfo result = null; if (rs.next()) { result = new ColumnInfo(); populateColumn(result, rs, tableName); } return result; } finally { if (rs != null) { rs.close(); } } } private void populateColumn(ColumnInfo column, ResultSet rs, String tableName) throws SQLException { /* * Notice: Oracle非常变态,当调用rs.getString("COLUMN_DEF")会经常抛出 * "Stream is already closed" Exception。 百思不得其解,google了半天有人提供了回避这个问题的办法 * (https://issues.apache.org/jira/browse/DDLUTILS-29), * 就是将getString("COLUMN_DEF")作为第一个获取的字段, 非常神奇的就好了。叹息啊。。。 */ String defaultVal = rs.getString("COLUMN_DEF"); column.setColumnDef(StringUtils.trimToNull(defaultVal));// Oracle会在后面加上换行等怪字符。 column.setColumnName(rs.getString("COLUMN_NAME")); column.setOrdinal(rs.getInt("ORDINAL_POSITION")); column.setColumnSize(rs.getInt("COLUMN_SIZE")); column.setDecimalDigit(rs.getInt("DECIMAL_DIGITS")); column.setDataType(rs.getString("TYPE_NAME")); column.setSqlType(rs.getInt("DATA_TYPE")); column.setNullable(rs.getString("IS_NULLABLE").equalsIgnoreCase("YES")); column.setRemarks(rs.getString("REMARKS"));// 这个操作容易出问题,一定要最后操作 column.setAutoincrement(rs.getString("IS_AUTOINCREMENT").equalsIgnoreCase("YES")); column.setGeneratedcolumn(rs.getString("IS_GENERATEDCOLUMN").equalsIgnoreCase("YES")); column.setTableName(tableName); } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy