一直用的系统是 Oracle的数据库,现在一个客户比较小,不想投入钱购买数据库软件,所以只能使用Mysql,需要将框架中的一些表结构、记录从Oracle导入到Mysql中去。网上没找到好用的软件,所以决定自己弄一个小程序实现异构库备份:
思路比较简单, 先生成建表语句并在mysql库中执行,在生成insert语句在mysql中执行。
一: 生成建表语句重点是需要获取表的字段,默认值,是否为空, 字段类型、字段长度等, 万幸的是这些jdbc都有实现,通过Connect获取数据库的DatabaseMetaData--dmd,
System.out.println("加载Oracle链接0...");
connect = connect(0);
System.out.println("加载Mysql链接1...");
insertConnect = connect(1);
System.out.println("获取dmd...");
dmd = connect.getMetaData();
再通过DatabaseMetaData--dmd查询表单字段信息,
ResultSet colrs = dmd.getColumns("%", dmd.getUserName(),table.toUpperCase(), "%");
然后解析获取到的ResultSet信息后即可获取到字段的全部信息,生成建表语句:
二:取生成insert语句类似,需要适用select语句查询表的信息,然后循环解析每一行的记录,生成insert插入,此处执行sql的是PreparedStatement,可以循环适用insert语句,仅需要改变每一次动态设置的值属性即可。
全部代码比较简单,直接上代码:
有两个类:jdbc工具类:JDBCUtil.java
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
public class JDBCUtil {
public static Connection connect(int type) {
Connection conn;
if (type == 0) {//oracle
conn = connectOracle();
} else { //Mysql
conn = connectMysql();
}
return conn;
}
/**
* 连接Oracle
*
* @return
*/
public static Connection connectMysql() {
// 连接MySql数据库,用户名和密码
String username = "111212";
String password = "2121";
String url = "jdbc:mysql://192.168.1.1/training?user=" + username+ "&password=" + password + "";
Connection conn = null;
try {
// 加载MySql的驱动类
Class.forName("com.mysql.jdbc.Driver");
conn = DriverManager.getConnection(url);
} catch (ClassNotFoundException e) {
System.out.println("找不到驱动程序类 ,加载驱动失败!");
e.printStackTrace();
} catch (SQLException se) {
System.out.println("数据库连接失败!");
se.printStackTrace();
}
return conn;
}
/**
* 连接Oracle
*
* @return
*/
public static Connection connectOracle() {
String url = "jdbc:oracle:thin:@192.168.1.1:1521:orcl";
// 连接MySql数据库,用户名和密码都是root
String username = "abcaf";
String password = "syjgagagac";
Connection conn = null;
try {
// 加载MySql的驱动类
Class.forName("oracle.jdbc.OracleDriver");
conn = DriverManager.getConnection(url, username, password);
} catch (ClassNotFoundException e) {
System.out.println("找不到驱动程序类 ,加载驱动失败!");
e.printStackTrace();
} catch (SQLException se) {
System.out.println("数据库连接失败!");
se.printStackTrace();
}
return conn;
}
public static List getColumnNames(ResultSetMetaData meta) throws SQLException{
List list = new ArrayList();
for (int i = 1; i <= meta.getColumnCount(); i++) {
list.add(meta.getColumnName(i));
}
return list;
}
// ResultSetMetaData 使用示例
// 此方法参考 http://blog.csdn.net/yirentianran/article/details/2950321
public static void demoResultSetMetaData(ResultSetMetaData data)
throws SQLException {
for (int i = 1; i <= data.getColumnCount(); i++) {
// 获得所有列的数目及实际列数
int columnCount = data.getColumnCount();
// 获得指定列的列名
String columnName = data.getColumnName(i);
// 获得指定列的列值
// String columnValue = rs.getString(i);
// 获得指定列的数据类型
int columnType = data.getColumnType(i);
// 获得指定列的数据类型名
String columnTypeName = data.getColumnTypeName(i);
// 所在的Catalog名字
String catalogName = data.getCatalogName(i);
// 对应数据类型的类
String columnClassName = data.getColumnClassName(i);
// 在数据库中类型的最大字符个数
int columnDisplaySize = data.getColumnDisplaySize(i);
// 默认的列的标题
String columnLabel = data.getColumnLabel(i);
// 获得列的模式
String schemaName = data.getSchemaName(i);
// 某列类型的精确度(类型的长度)
int precision = data.getPrecision(i);
// 小数点后的位数
int scale = data.getScale(i);
// 获取某列对应的表名
String tableName = data.getTableName(i);
// 是否自动递增
boolean isAutoInctement = data.isAutoIncrement(i);
// 在数据库中是否为货币型
boolean isCurrency = data.isCurrency(i);
// 是否为空
int isNullable = data.isNullable(i);
// 是否为只读
boolean isReadOnly = data.isReadOnly(i);
// 能否出现在where中
boolean isSearchable = data.isSearchable(i);
System.out.println(columnCount);
System.out.println("获得列" + i + "的字段名称:" + columnName);
// System.out.println("获得列" + i + "的字段值:" + columnValue);
System.out.println("获得列" + i + "的类型,返回SqlType中的编号:" + columnType);
System.out.println("获得列" + i + "的数据类型名:" + columnTypeName);
System.out.println("获得列" + i + "所在的Catalog名字:" + catalogName);
System.out.println("获得列" + i + "对应数据类型的类:" + columnClassName);
System.out.println("获得列" + i + "在数据库中类型的最大字符个数:"
+ columnDisplaySize);
System.out.println("获得列" + i + "的默认的列的标题:" + columnLabel);
System.out.println("获得列" + i + "的模式:" + schemaName);
System.out.println("获得列" + i + "类型的精确度(类型的长度):" + precision);
System.out.println("获得列" + i + "小数点后的位数:" + scale);
System.out.println("获得列" + i + "对应的表名:" + tableName);
System.out.println("获得列" + i + "是否自动递增:" + isAutoInctement);
System.out.println("获得列" + i + "在数据库中是否为货币型:" + isCurrency);
System.out.println("获得列" + i + "是否为空:" + isNullable);
System.out.println("获得列" + i + "是否为只读:" + isReadOnly);
System.out.println("获得列" + i + "能否出现在where中:" + isSearchable);
}
}
// 演示 DatabaseMetaData
public static void demoDatabaseMetaData() {
try {
Connection con = connect(0);
//
DatabaseMetaData dmd = con.getMetaData();
System.out.println("当前数据库是:" + dmd.getDatabaseProductName());
System.out.println("当前数据库版本:" + dmd.getDatabaseProductVersion());
System.out.println("当前数据库驱动:" + dmd.getDriverVersion());
System.out.println("当前数据库URL:" + dmd.getURL());
System.out.println("当前数据库是否是只读模式?:" + dmd.isReadOnly());
System.out.println("当前数据库是否支持批量更新?:" + dmd.supportsBatchUpdates());
System.out .println("当前数据库是否支持结果集的双向移动(数据库数据变动不在ResultSet体现)?:" + dmd.supportsResultSetType(ResultSet.TYPE_SCROLL_INSENSITIVE));
System.out .println("当前数据库是否支持结果集的双向移动(数据库数据变动会影响到ResultSet的内容)?:" + dmd.supportsResultSetType(ResultSet.TYPE_SCROLL_SENSITIVE));
System.out.println("========================================");
// ResultSet rs = dmd.getTables(null, null, "%", null);
// System.out.println("表名" + "," + "表类型");
/*
* while (rs.next()) { String tname =
* rs.getString("TABLE_NAME").toLowerCase();
* if(!tname.startsWith("t_")){ continue; }
* System.out.println(rs.getString("TABLE_NAME") + ","+
* rs.getString("TABLE_TYPE")); }
*/
System.out.println("========================================");
ResultSet rs = dmd.getPrimaryKeys(null, "SYJC", "t_mz_djlr".toUpperCase());
while (rs.next()) {
System.out .println(rs.getString(3) + "表的主键是:" + rs.getString(4));
}
System.out.println("========================================");
rs = dmd.getColumns("%", "SYJC", "t_mz_djlr", "%");
System.out.println("t_student表包含的字段:");
while (rs.next()) {
System.out.println(rs.getString(4) + " " + rs.getString(6) + "(" + rs.getString(7) + ");");
}
System.out.println("========================================");
} catch (Exception e) {
System.out.println("数据库操作出现异常");
}
}
}
还有一个实现 解析字段信息生成建表语句、解析结果生成insert语句的类DBBackUtil.java
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DBBackUtil extends JDBCUtil{
public static Connection connect;
public static Connection insertConnect;
public static DatabaseMetaData dmd;
public static Map dataTypesMap = new HashMap();
public static List<String> types = new ArrayList();
public static Map<String,Boolean> unneedLength = new HashMap();
static{
/**
* 此处对象的是 jdbcType 将要转换到mysql的数据类型
*/
dataTypesMap.put(12+"","VARCHAR");
dataTypesMap.put(3+"","DECIMAL");
dataTypesMap.put(93+"","TIMESTAMP");
dataTypesMap.put(1+"","CHAR");
dataTypesMap.put(6+"","DECIMAL");
dataTypesMap.put(2005+"","LONGTEXT");
dataTypesMap.put(1111+"","VARCHAR");
/***不需要长度的字段, clob(longtext)、TIMESTAMP*/
unneedLength.put(93+"",true);
unneedLength.put(2005+"",true);
types.add("VARCHAR2");
types.add("NUMBER");
types.add("DATE");
types.add("CHAR");
types.add("FLOAT");
types.add("CLOB");
types.add("NCHAR");
}
public static void main(String[] args) throws SQLException {
System.out.println("加载Oracle链接0...");
connect = connect(0);
System.out.println("加载Mysql链接1...");
insertConnect = connect(1);
System.out.println("获取dmd...");
dmd = connect.getMetaData();
String[] tables = { "t_base_zg" };
String table = null;
for (int j = 0; j < tables.length; j++) {
table = tables[j];
System.out.println("===========================================================");
createCreateSQL(table);
System.out.println("===========================================================");
System.out.println("插入开始表:"+table);
createInsertSQL(table);
System.out.println("插入表结束:"+table);
System.out.println("===========================================================");
}
// System.out.println("*******************************************");
// for (String ty : types) {
// System.out.println(ty);
// }
// System.out.println("*******************************************");
connect.close();
}
private static void createInsertSQL(String table) throws SQLException {
Statement stmt = createStmt(connect);
String sql = "select * from "+table;
System.out.println("查询表数据 "+table);
ResultSet rs = stmt.executeQuery(sql);
System.out.println("获取表字段。。。。"+table);
List<String> columns = getColumnNames(rs.getMetaData());
StringBuffer insertSql = new StringBuffer("INSERT INTO "+table+"(");
for (String col : columns) {
insertSql.append(col+",");
}
insertSql.delete(insertSql.length()-1, insertSql.length());
insertSql.append(") \n values(");
for (String col : columns) {
insertSql.append("?,");
}
insertSql.delete(insertSql.length()-1, insertSql.length());
insertSql.append(")");
System.out.println(insertSql.toString());
System.out.println("循环插入数据......");
PreparedStatement preStmt = null;
while(rs.next()){
preStmt = createPreStmt(insertConnect, insertSql.toString());
//循环结果集 执行插入操作
for (int i = 0; i < columns.size(); i++) {
Object obj = rs.getObject(columns.get(i));
//System.out.println(obj+"\t"+(obj!=null?obj.getClass():""));
preStmt.setObject(i+1, obj);
}
int count = preStmt.executeUpdate();
System.out.println("插入 "+count+"条");
preStmt.clearBatch();
preStmt.clearParameters();
preStmt.close();
}
rs.close();
}
/**
* 生成建表语句
* @param table
* @return
* @throws SQLException
*/
public static String createCreateSQL(String table) throws SQLException{
ResultSet colrs = dmd.getColumns("%", dmd.getUserName(),table.toUpperCase(), "%");
StringBuffer sb = new StringBuffer("create table " + table + "(\n");
System.out.println("获取表 【"+table+"】的字段创建按create语句");
while (colrs.next()) {
String columnName = colrs.getString("COLUMN_NAME"); //字段名
int dataType = colrs.getInt("DATA_TYPE"); //数据类型 数字表示
String dataTypeName = (String) dataTypesMap.get(dataType+"");
String typeName = colrs.getString("TYPE_NAME"); //类型名 varchar2等,数据库的实际字段类型
if(!types.contains(typeName)){
types.add(typeName);
}
int columnSize = colrs.getInt("COLUMN_SIZE");
String remarks = colrs.getString("REMARKS");
int nullable = colrs.getInt("NULLABLE");
String columnDef = colrs.getString("COLUMN_DEF");
sb.append("\t"+columnName.toLowerCase()+"\t");//字段名
if( columnSize == 4000 && "VARCHAR".equals(dataTypeName)){
sb.append("Text");//daatype
}else{
sb.append(dataTypeName);//daatype
}
Boolean unNeedLength = unneedLength.get(dataType+"");
if(!(unNeedLength!=null && unNeedLength.booleanValue())){
if("DECIMAL".equals(dataTypeName)){
sb.append("("+(columnSize>10?10:columnSize)); //字段长度
}else{
sb.append("("+columnSize); //字段长度
}
sb.append(")");
}
sb.append("\t");
//sb.append("typeName:"+typeName+"\t");
//sb.append("dataType:"+dataType+"\t");
if(columnDef!=null && !"".equals(columnDef.trim())){
sb.append("default "+columnDef+" \t"); //默认值
}
//sb.append("remarks:"+remarks+"\t");
sb.append((nullable == 0 ? " not null " : "")+","); //是否为空
sb.append("\n");
}
//去掉最后的逗号
sb.replace(sb.length()-3, sb.length(), "");
System.out.println("获取表 【"+table+"】的主键....");
/**
* 生成主键
*/
String keySql = createKeySqlByTableName(table);
if(keySql!=null && keySql.length()>0){
sb.append(",\n");
sb.append("\t"+keySql+"\n");
}
sb.append(") ENGINE=INNODB ;");
System.out.println(sb.toString());
Statement stmt = createStmt(insertConnect);
System.out.println("执行表 【"+table+"】的建表语句 ....");
boolean runRs = stmt.execute(sb.toString());
System.out.println("上述建表语句 执行完成");
return sb.toString();
}
/**
* 获取表主键集合
* @return
* @throws SQLException
*/
private static List getTableKeys(String tableName) throws SQLException{
ResultSet rs = dmd.getPrimaryKeys(null, "SYJC", tableName.toUpperCase());//此处旭要将表名设置成大写 oracle 只认大写
List list = new ArrayList();
while (rs.next()) {
list.add(rs.getString(4).toLowerCase());
}
rs.close();
return list;
}
/**
* 将表名拼接成Key sql
* @param tableName
* @return
* @throws SQLException
*/
public static String createKeySqlByTableName(String tableName) throws SQLException{
List list = getTableKeys(tableName);
return createKeySql(list);
}
/**
* 将字段拼接成Key sql
* @param list
* @return
*/
public static String createKeySql(List<String> list){
if(list==null || list.size()<=0){
return null;
}
StringBuffer keySql = new StringBuffer();
keySql.append("primary key (");
for (int i = 0; i < list.size(); i++) {
if(i!=0 ){
keySql.append(",");
}
keySql.append(list.get(i));
}
keySql.append(")");
return keySql.toString();
}
public static PreparedStatement createPreStmt(Connection conn, String sql) {
PreparedStatement pstmt = null;
try {
pstmt = conn.prepareStatement(sql);
} catch (SQLException e) {
System.out.println("生成预处理stmt失败");
e.printStackTrace();
}
return pstmt;
}
public static Statement createStmt(Connection conn) {
Statement pstmt = null;
try {
pstmt = conn.createStatement();
} catch (SQLException e) {
System.out.println("生成预处理stmt失败");
e.printStackTrace();
}
return pstmt;
}
/**
* 解析ResultSet的单条记录,不进行 ResultSet 的next移动处理
*
* @param rs
* @return
*/
private static Map<String, Object> parseResultSetToMap(ResultSet rs) {
//
if (null == rs) {
return null;
}
//
Map<String, Object> map = new HashMap<String, Object>();
//
try {
ResultSetMetaData meta = rs.getMetaData();
//
int colNum = meta.getColumnCount();
//
for (int i = 1; i <= colNum; i++) {
// 列名
String name = meta.getColumnLabel(i); // i+1
Object value = rs.getObject(i);
// 加入属性
map.put(name, value);
}
} catch (SQLException e) {
e.printStackTrace();
}
//
return map;
}
// /**
// * varchar2 number date char clob nchar
// *
// * @return
// */
// public static Map createMappingRelation() {
// Map map = new HashMap();
// map.put("varchar2", "varchar");
// map.put("number", "varchar");
// map.put("date", "datetime");
// map.put("char", "charo");
// map.put("clob", "mediumtext");
// map.put("nchar", "varchar");
// return map;
// }
}
通过dmd 获取字段信息 请参考:http://blog.sina.com.cn/s/blog_707a9f0601014y1y.html