1. 程式人生 > >使用jdbc獲取資料庫全部表、表包含欄位

使用jdbc獲取資料庫全部表、表包含欄位

1.  建立資料來源Vo, 封裝資料來源相關資訊;

//資料來源資訊
public class DataSource implements Serializable {    
    //資料庫型別
    private JdbcType          jdbcType;
	//url
	private String            jdbcUrl;
	//user
	private String            jdbcUser;
	//pwd
	private String            jdbcPassword;
	//表名 | 檢視名
	private String            tvname;
   
    //getter 、setter...
}

2.  抽象出介面

public interface JdbcService {
	/**
	 * 測試資料庫的連通性
	 * @return true表示成功
	 */
	public boolean test();
	
	/**
	 * 列出所有的表和檢視
	 * @return 所有的表和檢視
	 */
	public List<String> listAllTables();
	
	/**
	 * 列出所有包含某些欄位的表和檢視
	 * @param fields 欄位
	 * @return 所有包含某些欄位的表和檢視
	 */
	public List<String> listAllTablesFields(String... fields);
	
	/**
	 * 列出所有的欄位
	 * @param tableName表名或檢視名
	 * @return 所有的欄位
	 */
	public List<String> listAllFields(String tableName);
	
}

3.  介面抽象實現類

public abstract class AbstractJdbcService implements JdbcService {
	private final DataSource dataSource;
	
	public AbstractJdbcService(DataSource dataSource) {
		this.dataSource = dataSource;
		checkDataSource(dataSource);
	}
	
	/**
	 * 校驗資料來源資訊是否有效
	 * @param dataSource 資料來源
	 */
	private void checkDataSource(DataSource dataSource){
		if(dataSource == null){
			throw new IllegalArgumentException("dataSource is null. ");
		}
		if(StringUtils.isBlank(dataSource.getJdbcUrl())){
			throw new IllegalStateException("jdbc url is null. ");
		}
		if(StringUtils.isAnyBlank(dataSource.getJdbcUser(), dataSource.getJdbcPassword())){
			throw new IllegalStateException("jdbc user or password is null. ");
		}
	}
	
	protected DataSource getDataSource() {
		return dataSource;
	}
	
	/**
	 * 關閉(釋放)資源
	 * @param conn Connection
	 */
	protected void close(Connection conn){
		close(conn, null, null);
	}
	
	/**
	 * 關閉(釋放)資源
	 * @param conn Connection
	 * @param ps PreparedStatement
	 * @param rs ResultSet
	 */
	protected void close(Connection conn, Statement ps, ResultSet rs){
		//關閉ResultSet
		if(rs != null){
			try {
				rs.close();
			} catch (SQLException e) {
				rs = null;
			}
		}
		//關閉PreparedStatement
		if(ps != null){
			try {
				ps.close();
			} catch (SQLException e) {
				ps = null;
			}
		}
		//關閉Connection
		if(conn != null){
			try {
				conn.close();
			} catch (SQLException e) {
				conn = null;
			}
		}
	}
	
	@Override
	public boolean test() {
		Connection conn = null;
		try {
			conn = getConnection();
			if(conn == null){
				return false;
			}
			
			DatabaseMetaData meta =  conn.getMetaData();
			if(meta == null){
				return false;
			}
		} catch (SQLException e) {
			
		} finally {
			close(conn);
		}
		return true;
	}
	
	/**
	 * 獲取連線
	 * @return Connection
	 */
	protected Connection getConnection(){
		Connection conn = null;
		try {
			Class.forName(loadDriverClass());
			conn = DriverManager.getConnection(dataSource.getJdbcUrl(), dataSource.getJdbcUser(), dataSource.getJdbcPassword());
		} catch (Exception e) {
			
		}
		return conn;
	}
	
	@Override
	public List<String> listAllTables() {
		Connection conn = getConnection();
		if(conn == null){
			return null;
		}
		
		List<String> result = new ArrayList<>();
		ResultSet rs = null;
		try{
		    //引數1 int resultSetType
		    //ResultSet.TYPE_FORWORD_ONLY 結果集的遊標只能向下滾動。
		    //ResultSet.TYPE_SCROLL_INSENSITIVE 結果集的遊標可以上下移動,當資料庫變化時,當前結果集不變。
		    //ResultSet.TYPE_SCROLL_SENSITIVE 返回可滾動的結果集,當資料庫變化時,當前結果集同步改變。

		    //引數2 int resultSetConcurrency
		    //ResultSet.CONCUR_READ_ONLY 不能用結果集更新資料庫中的表。
		    //ResultSet.CONCUR_UPDATETABLE 能用結果集更新資料庫中的表
		    
		    conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY);
			DatabaseMetaData meta = conn.getMetaData();
			//目錄名稱; 資料庫名; 表名稱; 表型別;
			rs = meta.getTables(catalog(), schemaPattern(), tableNamePattern(), types());
			while(rs.next()){
				result.add(rs.getString("TABLE_NAME"));
			}
		}catch(Exception e){
			e.printStackTrace();
		}finally {
			close(conn, null, rs);
		}
		
		return result;
	}
	
	@Override
	public List<String> listAllFields(String tableName) {
		Connection conn = getConnection();
		if(conn == null){
			return null;
		}
		List<String> result = new ArrayList<>();
        ResultSet rs = null;
        try{
            DatabaseMetaData meta = conn.getMetaData();
            rs = meta.getColumns(catalog(), schemaPattern(), tableOrViewName.trim(), null);
            while(rs.next()){
                result.add(rs.getString("COLUMN_NAME"));
            }
        }catch(Exception e){
            
        }finally{
            close(conn, null, rs);
        }
		return result;
	}
	
	@Override
	public List<String> listAllTablesFields(String... fields) {
		//如果欄位為空, 則返回null
		if(fields == null || fields.length == 0){
			return null;
		}
		//如果表結構(檢視)為空, 則返回null
		List<String> tvs = listAllTables();
		if(tvs == null || tvs.size() == 0){
			return null;
		}
		
		List<String> result = new CopyOnWriteArrayList<>();
		//併發篩選包含特定欄位的表結構
		tvs.parallelStream().forEach(tv -> {
			List<String> fieldsList = listAllFields(tv);
			if(fieldsList != null && fieldsList.size() > 0){
				if(fieldsList.containsAll(Arrays.asList(fields))){
					result.add(tv);
				}
			}
		});
				
		return result;
	}
	
	/**
	 * a catalog name; must match the catalog name as it is stored in the database; "" retrieves those without a catalog; null means that the catalog name should not be used to narrow the search
	 */
	protected String catalog(){
		return null;
	}
	
	/**
	 * a table name pattern; must match the table name as it is stored in the database
	 */
	protected String tableNamePattern(){
		return "%";
	}
	
	/**
	 * a list of table types, which must be from the list of table types returned from {@link DatabaseMetaData.getTableTypes},to include; null returns all types
	 */
	protected String[] types(){
		
		return new String[]{"TABLE", "VIEW"};
	}
	
	/**
	 * 載入驅動class
	 * @return class
	 */
	protected abstract String loadDriverClass();
	
	/**
	 * a schema name pattern; must match the schema name as it is stored in the database; "" retrieves those without a schema; null means that the schema name should not be used to narrow the search
	 */
	protected abstract String schemaPattern();
}

4.  工廠類

public class JdbcServiceFactory {
	
	/**
	 * 獲取jdbc service
	 * @param dataSource 資料來源
	 * @return jdbc service
	 */
	public static JdbcService getJdbcService(DataSource dataSource){
		if(dataSource.getJdbcType() == JdbcType.MYSQL){
			return new MySQLJdbcService(dataSource);
		}else if(dataSource.getJdbcType() == JdbcType.ORACLE){
			return new OracleJdbcService(dataSource);
		}
		return null;
	}
	
}

5. mysql對應jdbc實現

public class MySQLJdbcService extends AbstractJdbcService {
    
	public MySQLJdbcService(DataSource dataSource) {
		super(dataSource);
	}
	
	@Override
	protected String loadDriverClass() {
		return "com.mysql.jdbc.Driver";
	}
	
	@Override
	protected String schemaPattern() {
		//mysql的schemaPattern為資料庫名稱
		String url = getDataSource().getJdbcUrl();
		//jdbc:mysql://localhost:3306/iso_db?useUnicode=true&characterEncoding=UTF-8
		String database = url.substring(url.indexOf("/", 13) + 1);
		int index = database.indexOf("?");
		if(index > 0){
			database = database.substring(0, index);
		}
		return database;
	}
}

6. oracle對應jdbc實現

public class OracleJdbcService extends AbstractJdbcService {
	
	public OracleJdbcService(DataSource dataSource) {
		super(dataSource);
	}
	
	@Override
	protected String loadDriverClass() {
		
		return "oracle.jdbc.driver.OracleDriver";
	}
	
	/**
	 * 注意:oracle使用者名稱稱須大寫
	 */
	@Override
	protected String schemaPattern() {
		//oracle的schemaPattern為使用者名稱
		return getDataSource().getJdbcUser().toUpperCase();
	}
}