这两天遇到一个问题,就是如何把Oracle中的数据转换到Mysql库中来,而且表名,字段等都不对应。
经过查找资料,发现了一种实现性很高的方案,原理如下:写个JAVA 应用程序,通过JDBC 创建一个oracle连接,查询得到结果集,再通过jdbc创建一个mysql连接,把前者结果循环插入mysql表中
用了一个下午的时间,写了一个转数据库的demo,通用性也是蛮强的,以后遇到这种问题也可以把代码拿出来参考一下,下面是这个demo的整体架构
db.properties主要是存储了两个数据库的驱动,url,用户名和密码,当然转数据库肯定是需要提供驱动包的,放在lib下面
sql.drivername=com.mysql.jdbc.Driver
sql.url=jdbc:mysql://localhost:3306/witn?useUnicode=true&characterEncoding=UTF-8
sql.uname=root
sql.password=password
sql.drivername2=oracle.jdbc.driver.OracleDriver
sql.url2=jdbc:oracle:thin:@localhost:1521:orcl
sql.uname2=scott
sql.password2=password
然后是提供了一个MyPro单例函数,来获取db.properties里面的信息
package dao;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class MyPro extends Properties {
private static final long serialVersionUID = 1L;
private static MyPro instance=null; //这是对外提供的一个实例
/**
* 外部调用这个方法来获取唯一的一个实例
*/
public synchronized static MyPro getInstance(){
if(instance!=null){
return instance;
}else{
instance=new MyPro();
return instance;
}
}
//单例模式最核心的是构造方法私有化
private MyPro(){
//从db.properties文件中读取所有的配置信息
InputStream is=this.getClass().getResourceAsStream("/db.properties");
//通过类的反射实例找到classpath路径下的资源文件,文件是db.properties,并建立一个流
try {
this.load(is); //将流里面的字节码加载到MyPro对象中
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
接着是提供了一个DBHelper函数,用来获取连接,主要提供的是查询和插入方法
package dao;
import java.sql.*;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author wangjw13244
*/
public class DBHelper {
private Connection con=null;
private PreparedStatement pstmt=null;
private ResultSet rs=null;
SimpleDateFormat sdf=new SimpleDateFormat("yyyy-MM-dd");
private int datanum;
// static{
// try {
// if( datanum==1 ){
//
// }
// } catch (ClassNotFoundException e) {
// System.out.println(e.toString());
// }
// }
public DBHelper(int datanum) {
this.datanum = datanum;
try {
if( datanum==1 ){
Class.forName(MyPro.getInstance().getProperty("sql.drivername"));
}else{
Class.forName(MyPro.getInstance().getProperty("sql.drivername2"));
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
/**
* 获取连接
*/
public Connection getConnection(){
try {
if( datanum==1 ){
con= DriverManager.getConnection(MyPro.getInstance().getProperty("sql.url"), MyPro.getInstance().getProperty("sql.uname"), MyPro.getInstance().getProperty("sql.password"));
}else{
con= DriverManager.getConnection(MyPro.getInstance().getProperty("sql.url2"), MyPro.getInstance().getProperty("sql.uname2"), MyPro.getInstance().getProperty("sql.password2"));
}
} catch (SQLException e) {
System.out.println(e.toString());
}
return con;
}
/**
* 关闭的方法
*/
public void closeAll(Connection con,PreparedStatement pstmt,ResultSet rs){
if(rs!=null){
try {
rs.close();
} catch (SQLException e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
if(pstmt!=null){
try {
pstmt.close();
} catch (SQLException e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
if(con!=null){
try {
con.close();
} catch (SQLException e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
}
/**
* 设置PreparedStatement对象的sql语句中的参数?
*/
public void setValues(PreparedStatement pstmt,List<Object> params){
if(pstmt!=null&¶ms!=null&¶ms.size()>0){
for(int i=0;i<params.size();i++){
Object o=params.get(i);
if(o!=null && !"".equals(o)){
try {
if("javax.sql.rowset.serial.SerialBlob".equals(o.getClass().getName())){
pstmt.setBlob(i+1, (Blob)params.get(i));
}else if("java.lang.Integer".equals(o.getClass().getName())){
pstmt.setInt(i+1,(Integer)params.get(i));
}else if("java.lang.Double".equals(o.getClass().getName())){
pstmt.setDouble(i+1,(Double)params.get(i));
}else{
pstmt.setString(i+1,(String)params.get(i));
}
} catch (SQLException e) {
System.out.println(e.toString());
e.printStackTrace();
}
}else{
try {
pstmt.setString(i+1,null);
} catch (SQLException e) {
System.out.println(e.toString());
e.printStackTrace();
}
}
}
}
}
/**
* 通过事物增加
* @param sqls
*/
public synchronized void thingUpdate( List<String> sqls,List<String> showSqls,List<List<Object>> params ){
con=getConnection();
try {
con.setAutoCommit(false);
for(int i=0;i<sqls.size();i++ ){
String sql = sqls.get(i);
List<Object> param = params.get(i);
System.out.println( "预加载"+showSqls.get(i) );
pstmt=con.prepareStatement(sql); //预编译对象
setValues(pstmt,param);
pstmt.executeUpdate();
}
con.commit();
} catch (SQLException e) {
e.printStackTrace();
try {
con.rollback();
} catch (SQLException e1) {
e1.printStackTrace();
}
}finally{
try {
con.setAutoCommit(true);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
/**
* @param sql:查询语句
* @param params: 查询语句中?所对应的值
* @return:结果集,存在一个List表中,用Map一对一的存放
* @throws SQLException
*/
public List<Map<String,String>> findResult(String sql,List<Object> params){
List<Map<String,String>> result=new ArrayList<Map<String,String>>(); //将结果一次存在list中返回
con=this.getConnection();
try {
pstmt=con.prepareStatement(sql);
this.setValues(pstmt, params);
rs=pstmt.executeQuery();
ResultSetMetaData md=rs.getMetaData(); //获取结果集的元数据
String[] colnames=new String[md.getColumnCount()]; //获取结果集中的列名
for(int i=0;i<colnames.length;i++){
colnames[i]=md.getColumnName(i+1);
}
while(rs.next()){
Map<String,String> map = new HashMap<String,String>();
for(int i=0;i<colnames.length;i++){//循环列名
map.put(colnames[i], rs.getString(i+1));
}
result.add(map);
}
} catch (SQLException e) {
e.printStackTrace();
}finally{
this.closeAll(con, pstmt, rs);
}
return result;
}
}
最后的核心是CDataBase.java这个函数,取数,和拼接数据库语句都是在这里完成的,注释也很清晰
package biz;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import dao.DBHelper;
public class CDataBase {
private String sql = "";
private String sql2 = ""; //插入语句
private String tablename = ""; //插入的表名
private DBHelper db;
private DBHelper db2;
private List<Map<String,String>> oResult;
private BufferedWriter bw;
public CDataBase(String sql,String tablename) {
super();
this.sql = sql;
this.tablename = tablename;
db = new DBHelper(1); //mysql 库
db2 = new DBHelper(2); //oracle库
File file = new File("D:\\"+tablename+".sql");
try {
bw = new BufferedWriter(new FileWriter(file));
} catch (IOException e) {
e.printStackTrace();
}
}
public void StartChange(){
oResult = db2.findResult(sql, null); //得到结果集
List<String> sqls = new ArrayList<String>();
List<String> showSqls = new ArrayList<String>();
List<List<Object>> params = new ArrayList<List<Object>>();
StringBuffer buffer = new StringBuffer();
try {
if( oResult!=null && oResult.size()>0 ){
//生成sql2 insert 的前部分语句
String insertSql = "";
String showSql = "";
sql2 = "insert into "+tablename+"(";
Map<String,String> OneMap = oResult.get(0);
Set<String> keys = OneMap.keySet(); //得到Key键
for( String key : keys ){
sql2 += key+",";
}
//去掉最后一个逗号
sql2 = sql2.substring(0,sql2.length()-1);
sql2 += ") values(";
for( int i=0;i<oResult.size();i++ ){
Map<String,String> map = oResult.get(i);
insertSql = sql2;
showSql = sql2;
List<Object> param = new ArrayList<Object>();
for(String key:keys){
insertSql += "?,";
showSql += map.get(key)+",";
param.add( map.get(key) );
}
showSql = showSql.substring(0,showSql.length()-1)+")";
insertSql = insertSql.substring(0,insertSql.length()-1)+")";
sqls.add(insertSql);
showSqls.add(showSql);
buffer.append(showSql + ";\r\n");
//防止溢出 每2000条清除一下buffer 加上控制
if( i%2000==0 ){
bw.write(buffer.toString());
bw.flush();
buffer = new StringBuffer();
}
insertSql = "";
showSql = "";
params.add(param);
}
bw.flush();
bw.close();
db.thingUpdate(sqls,showSqls,params);
}else{
System.out.println( "通过语句"+sql+"得到的结果集为空" );
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
最后提供了一个测试的用例
package main;
import biz.CDataBase;
public class InitSecu_Stock {
public static void main(String[] args) {
String sql = "select d.vc_scode,d.vc_code,d.vc_sname,d.vc_name as VC_COMPANY_NAME,d.vc_spell_abbr "
+ "as VC_SHORT_NAME,(select t.vc_item_name from tdatadict t where t.l_dict_id=101101 and "
+ "t.l_item_id=d.l_market) as VC_ISSUT_MARKET,d.l_offer_date as L_ISSUT_TIME,1 as L_SI_STATUS "
+ "from dm_bsc_security d where d.l_kind=1";
CDataBase cdb = new CDataBase(sql,"Secu_StockInfo");
cdb.StartChange();
}
}
注意观察这个用例,发现查询出来的字段名后面都会加一个as,这个as后面的字段名需要和你的Mysql数据库表字段名一一对应,才能够完美的插入数据。
等到下次有时间和精力的时候可以提供一个可视化的界面更加容易的转数