在實際工作中,我們可能會遇到幾十個常用table,每個表有幾十個column,很難一下子把它們都記住。
每次使用desc TableA
手動查詢,效率比較低。特別是碰到DB slowness,就只能干等着,很急。
所以需要做一個可以便捷更新的數據庫文檔。
最終,我選用了開源的screw
來實現。Github的地址在這里:https://github.com/pingfangushi/screw/tree/master
功能
支持多種數據庫(主要是傳統的關系型數據庫)
- Oracle
- MySQL
- SqlServer
- PostgreSQL
支持多種生成文檔的格式
- html
- word
- markdown
最終生成的文件是這樣的
所有表名匯總
每個表的信息
原理
個人分析,screw
的實現應該是這樣的:
- 首先,通過一個Connector連接到DB,這里用的是
HikariCP
,因為輕量,且速度快。(https://github.com/brettwooldridge/HikariCP) - 然后,通過一系列的Query得到Table Schema。
舉例Oracle的Query如下:
- get all schema
SELECT
USERNAME AS SCHEMA_NAME
FROM SYS.ALL_USERS
ORDER BY USERNAME;
- get all table_name under the schema
SELECT
OWNER,
TABLE_NAME
FROM SYS.ALL_TABLES
WHERE OWNER = 'YOUR_SCHEMA';
- get the table_schema of the table, this is equivalent to using
desc
SELECT
COLUMN_NAME "Name",
NULLABLE "Null?",
CONCAT(CONCAT(CONCAT(DATA_TYPE,'('),DATA_LENGTH),')') "Type"
FROM USER_TAB_COLUMNS
WHERE TABLE_NAME='YOUR_TABLE';
實現
第一步,引入依賴,其中,screw和HikariCP是必須的,driver根據自己的數據庫進行選擇。
<!-- screw -->
<dependency>
<groupId>cn.smallbun.screw</groupId>
<artifactId>screw-core</artifactId>
<version>1.0.4</version>
</dependency>
<!-- HikariCP -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>3.4.5</version>
</dependency>
<!-- driver -->
<dependency>
<groupId>com.oracle.ojdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>19.3.0.0</version>
</dependency>
<dependency>
<groupId>cn.easyproject</groupId>
<artifactId>orai18n</artifactId>
<version>12.1.0.2.0</version>
</dependency>
第二步,編寫代碼實現。
這里需要配置三個地方:
- 數據庫(從哪里讀取數據)
- 輸出文件(讀取之后存到什么地方)
- 讀取哪些數據表(讀取哪些數據)
import cn.smallbun.screw.core.Configuration;
import cn.smallbun.screw.core.engine.EngineConfig;
import cn.smallbun.screw.core.engine.EngineFileType;
import cn.smallbun.screw.core.engine.EngineTemplateType;
import cn.smallbun.screw.core.execute.DocumentationExecute;
import cn.smallbun.screw.core.process.ProcessConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.util.ArrayList;
public class DbSchemaHelper {
public static void main(String args[]) {
new DbSchemaHelper().documentGeneration();
}
void documentGeneration() {
//配置 - 數據源
HikariDataSource ds = new HikariDataSource();
ds.setJdbcUrl("jdbc:oracle:thin:@//somelink:port/dbname");
ds.setUsername("user");
ds.setPassword("password");
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setSchema("schema_name");
//配置 - 輸出文件
String fileOutputDir = "C:\\my_test";
EngineConfig engineConfig = EngineConfig.builder()
//生成文件路徑
.fileOutputDir(fileOutputDir)
//打開目錄
.openOutputDir(true)
//文件類型
.fileType(EngineFileType.HTML)
//生成模板實現
.produceType(EngineTemplateType.freemarker)
//自定義文件名稱
.fileName("test_file")
.build();
//配置 - 讀取哪些數據表
ArrayList<String> ignoreTableName = new ArrayList<>();
ignoreTableName.add("test_user");
ignoreTableName.add("test_group");
ArrayList<String> ignorePrefix = new ArrayList<>();
ignorePrefix.add("test_");
ArrayList<String> ignoreSuffix = new ArrayList<>();
ignoreSuffix.add("_test");
ArrayList<String> tablePrefix = new ArrayList<>();
tablePrefix.add("Acc_");
ProcessConfig processConfig = ProcessConfig.builder()
//指定生成邏輯、當存在指定表、指定表前綴、指定表后綴時,將生成指定表,其余表不生成、並跳過忽略表配置
//根據名稱指定表生成
.designatedTableName(new ArrayList<>())
//根據表前綴生成
.designatedTablePrefix(tablePrefix)
//根據表后綴生成
.designatedTableSuffix(new ArrayList<>())
//忽略表名
//.ignoreTableName(ignoreTableName)
//忽略表前綴
//.ignoreTablePrefix(ignorePrefix)
//忽略表后綴
//.ignoreTableSuffix(ignoreSuffix)
.build();
Configuration config = Configuration.builder()
//版本
.version("1.0.0")
//描述
.description("DB Schema Doc")
//數據源
.dataSource(ds)
//生成配置
.engineConfig(engineConfig)
//生成配置
.produceConfig(processConfig)
.build();
//執行生成
System.out.println("start");
new DocumentationExecute(config).execute();
System.out.println("end");
}
}
除此之外,也可以使用SpringBoot,或者Maven Plugin,所做的事大概是把一部分Java代碼放到了XML里面,但是萬變不離其宗,保證上面的三個點都配置好即可。
常見錯誤
java.lang.AbstractMethodError: oracle.jdbc.driver.T4CConnection.getSchema()Ljava/lang/String;
這是因為oracle驅動版本過低造成的,比如ojdbc6
,升級下即可。