使用Java实现Oracle表结构转换为PostgreSQL的示例方案(AI)
核心代码
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class OracleToPGConverter {
// 类型映射表
private static final Map<String, String> TYPE_MAPPING = new HashMap<>();
static {
TYPE_MAPPING.put("VARCHAR2", "VARCHAR");
TYPE_MAPPING.put("NUMBER", "NUMERIC");
TYPE_MAPPING.put("DATE", "TIMESTAMP");
TYPE_MAPPING.put("CLOB", "TEXT");
TYPE_MAPPING.put("BLOB", "BYTEA");
}
public static void main(String[] args) {
String oracleTable = "EMPLOYEES";
try {
// 1. 连接Oracle数据库
Connection oracleConn = DriverManager.getConnection(
"jdbc:oracle:thin:@host:port:sid", "user", "password");
// 2. 获取表结构元数据
TableMetaData tableMeta = extractMetaData(oracleConn, oracleTable);
// 3. 生成PG DDL
String pgDDL = generatePGDDL(tableMeta);
// 4. 连接PostgreSQL执行
Connection pgConn = DriverManager.getConnection(
"jdbc:postgresql://host:port/dbname", "user", "password");
executeDDL(pgConn, pgDDL);
// 关闭连接
oracleConn.close();
pgConn.close();
System.out.println("转换完成!");
} catch (SQLException e) {
e.printStackTrace();
}
}
// 提取Oracle元数据
private static TableMetaData extractMetaData(Connection conn, String tableName) throws SQLException {
TableMetaData meta = new TableMetaData();
meta.tableName = tableName.toLowerCase(); // PG默认小写
// 获取列信息
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT column_name, data_type, data_length, data_precision, data_scale, nullable " +
"FROM all_tab_columns WHERE table_name = '" + tableName + "'")) {
while (rs.next()) {
Column col = new Column();
col.name = rs.getString("column_name").toLowerCase();
col.type = rs.getString("data_type");
col.length = rs.getInt("data_length");
col.precision = rs.getInt("data_precision");
col.scale = rs.getInt("data_scale");
col.nullable = "Y".equals(rs.getString("nullable"));
meta.columns.add(col);
}
}
// 获取主键信息
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT column_name FROM all_cons_columns " +
"WHERE constraint_name = ( " +
" SELECT constraint_name FROM all_constraints " +
" WHERE table_name = '" + tableName + "' AND constraint_type = 'P'))")) {
while (rs.next()) {
meta.primaryKeys.add(rs.getString("column_name").toLowerCase());
}
}
return meta;
}
// 生成PostgreSQL DDL
private static String generatePGDDL(TableMetaData meta) {
StringBuilder ddl = new StringBuilder();
ddl.append("CREATE TABLE ").append(meta.tableName).append(" (\n");
List<String> columnDefs = new ArrayList<>();
for (Column col : meta.columns) {
String def = " " + col.name + " " + mapDataType(col);
if (!col.nullable) def += " NOT NULL";
columnDefs.add(def);
}
if (!meta.primaryKeys.isEmpty()) {
columnDefs.add(" PRIMARY KEY (" + String.join(", ", meta.primaryKeys) + ")");
}
ddl.append(String.join(",\n", columnDefs));
ddl.append("\n);");
return ddl.toString();
}
// 数据类型转换
private static String mapDataType(Column col) {
String mappedType = TYPE_MAPPING.getOrDefault(col.type, "TEXT");
if ("NUMBER".equals(col.type)) {
if (col.scale > 0) {
return "NUMERIC(" + col.precision + "," + col.scale + ")";
} else if (col.precision > 0) {
return "NUMERIC(" + col.precision + ")";
}
return "NUMERIC";
}
if ("VARCHAR2".equals(col.type)) {
return "VARCHAR(" + (col.length > 0 ? col.length : 255) + ")";
}
return mappedType;
}
// 执行DDL
private static void executeDDL(Connection conn, String ddl) throws SQLException {
try (Statement stmt = conn.createStatement()) {
stmt.executeUpdate(ddl);
}
}
// 元数据存储类
static class TableMetaData {
String tableName;
List<Column> columns = new ArrayList<>();
List<String> primaryKeys = new ArrayList<>();
}
// 列定义类
static class Column {
String name;
String type;
int length;
int precision;
int scale;
boolean nullable;
}
}
使用说明
1.配置数据库连接
- 修改Oracle连接字符串(jdbc:oracle:thin:@host:port)
- 修改PostgreSQL连接字符串(jdbc:postgresql://host/dbname)
- 填写正确的用户名密码
2.功能扩展建议
// 添加索引转换(示例)
private static void extractIndexes(Connection conn, TableMetaData meta) throws SQLException {
try (Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery(
"SELECT index_name, column_name " +
"FROM all_ind_columns " +
"WHERE table_name = '" + meta.tableName.toUpperCase() + "'")) {
while (rs.next()) {
String indexName = rs.getString("index_name");
String column = rs.getString("column_name").toLowerCase();
// 处理索引元数据...
}
}
}
// 处理自增序列(Oracle序列转PG SERIAL)
private static String handleAutoIncrement() {
// Oracle: 使用触发器+序列
// PostgreSQL: 使用SERIAL类型或GENERATED ALWAYS AS IDENTITY
return "SERIAL";
}
// 添加注释支持
private static void addColumnComments() {
// 从Oracle的ALL_COL_COMMENTS获取注释
// 生成PostgreSQL的COMMENT语句
}
3.运行注意事项
- 需要JDBC驱动:
-
- Oracle: ojdbc8.jar
-
- PostgreSQL: postgresql-42.x.jar
- 权限要求:
-
- Oracle用户需要访问ALL_TAB_COLUMNS等系统视图
-
- PG用户需要有建表权限
- 命名规范:
-
- 强制转换为小写(PostgreSQL默认小写)
-
- 特殊字符需用引号处理
4.数据类型映射扩展
// 更完整的类型映射建议
TYPE_MAPPING.put("NVARCHAR2", "VARCHAR");
TYPE_MAPPING.put("RAW", "BYTEA");
TYPE_MAPPING.put("TIMESTAMP(6)", "TIMESTAMP");
TYPE_MAPPING.put("FLOAT", "DOUBLE PRECISION");
这个实现提供了基础的表结构转换功能,实际使用时需要根据具体业务需求进行以下增强:
- 添加索引、外键约束的转换逻辑
- 处理表空间、存储参数等数据库特性
- 添加注释信息的迁移
- 实现数据迁移功能(通过JDBC批量插入)
- 增加错误处理和日志记录
- 支持CLOB/BLOB大字段处理
- 处理分区表等高级特性
建议在实际使用前进行以下验证:
- 对比生成的DDL与原始表结构
- 检查约束和索引的正确性
- 验证数据类型的兼容性
- 测试大数据量场景下的数据类型转换