zoukankan      html  css  js  c++  java
  • MySQL与Oracle之间互相拷贝数据的Java程序

    因为工作需要,先是需要将一个小型的MySQL数据库中的数据拷贝到Oracle中;近期又有需要将一个中型的Oracle数据库拷贝到MySQL中。曾经找过网上各种转换工具,大多收费的,自己写个吧,还一切可控。

    转换的前提是两种数据库中已经存在相同的数据结构,可以自己利用SQL语句在目标数据库生成数据结构;或者是使用工具仅生成数据结构(如:DBMover,它是收费的,但可以免费转换数据结构,好像不包括外键,网址:http://dbmover.com/cn/)。

    第一个程序,从MySQL拷贝到Oracle

    很久以前写的,将一个小型的MySQL数据库中的表拷贝到Oracle数据库中(十万数据量级别,没有优化,大数据量可能很慢):

    package com.clzhang.sample.jdbc;
    
    import java.sql.*;
    
    /**
     * 从MySQL数据库拷贝表数据到Oracle数据库中的程序。
     * 前提:两个数据库中都具有相关的表,且表结构相同,目标数据库中还不能存在冲突的数据。
     * @author acer
     *
     */
    public class CopyMySQL2Oracle {
        // 源数据库,目标数据库的连接配置
        String mysql_jdbc_url = "jdbc:mysql://localhost/xuejia?user=root&password=password1&useUnicode=true&characterEncoding=gb2312";
        
        String jdbc_url = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
        String jdbc_user = "mytest";
        String jdbc_password = "test001";
        
        public void startProcess(String tableName) throws Exception {
            // 创建到两个数据库的连接
            Class.forName("org.gjt.mm.mysql.Driver");
            Connection connSource = DriverManager.getConnection(mysql_jdbc_url);
    
            Class.forName("oracle.jdbc.driver.OracleDriver");
            Connection connDest = DriverManager.getConnection(jdbc_url, jdbc_user,
                    jdbc_password);
            
            // 打开源数据库中相关表
            StringBuilder sb = new StringBuilder();
            sb.append("insert into " + tableName + "(");
            Statement stmt= connSource.createStatement();
            ResultSet rs = stmt.executeQuery("select * from " + tableName);
            
            // 显示共计有多少条记录
            rs.last();
            System.out.println(tableName + "表共计有:"+ rs.getRow() + "条记录,正在处理......");
            rs.beforeFirst();
            
            // 先计算目标数据库的PreparedStatement的SQL语句
            ResultSetMetaData rsmd = rs.getMetaData();
            int numberOfColumns = rsmd.getColumnCount();
            for(int i=1; i<=numberOfColumns;i++) {
                sb.append(rsmd.getColumnName(i) + ",");
            }
            sb.deleteCharAt(sb.length()-1);
            sb.append(")values(");
            for(int i=1; i<=numberOfColumns;i++) {
                sb.append("?,");
            }
            sb.deleteCharAt(sb.length()-1);
            sb.append(")");
            System.out.println(sb.toString());
            
            // 给PreparedStatement赋值,然后更新;如果是大数量的情况,可以考虑Batch处理。因为这里的数据量小,直接单条更新了。
            PreparedStatement pstmt = connDest.prepareStatement(sb.toString());
            while(rs.next()) {
                for(int i=1; i<=numberOfColumns;i++) {
                    pstmt.setObject(i, rs.getObject(i));
                }
                
                System.out.print("-");
                pstmt.executeUpdate();
            }
            
            // 关闭各资源 
            rs.close();
            stmt.close();
            pstmt.close();
            
            connSource.close();
            connDest.close();
        }
    
        public static void main(String[] args) throws Exception {
            CopyMySQL2Oracle ins = new CopyMySQL2Oracle();
            ins.startProcess("PRODUCT");
            
            // ...需要拷贝的表名在下面加入即可,注意顺序,比如有外键的表应该排列在主表之后。
        }
    }


    第二个程序,从Oracle拷贝到MySQL

    最近写的,一个中小型数据库(百万级别,做了适当优化,仍旧挺慢的)的拷贝程序,供参考吧。

    建议在拷贝之前,禁用、或者是删除目标数据库中的相关索引以提高速度;拷贝完成之后,重新建立索引。

    package com.clzhang.sample.jdbc;
    
    import java.sql.*;
    
    /**
     * 这是一个将Oracle数据库中的数据拷贝到MySQL数据库中的简单程序。
     * 仅考虑NUMBER/CHAR/VARCHAR/CLOB/DATE/TIMESTAMP等字段类型。
     * BLOB没有考虑(因为我的数据库中没有BLOB字段,无法测试)。
     * 
     * 前提:两个数据库中都具有相关的表,且表结构相同,目标数据库中还不能存在冲突的数据。
     * @author acer
     *
     */
    public class CopyOracle2MySQL {
        // 源数据库,目标数据库的连接配置
        private final String DEST_MYSQL_JDBC_URL = "jdbc:mysql://localhost/mybbs?user=root&password=password1&useUnicode=true&characterEncoding=utf-8";
        
        private final String SOURCE_JDBC_URL = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";
        private final String SOURCE_JDBC_USER = "mybbs";
        private final String SOURCE_JDBC_PASSWORD = "bbs001";
    
        public void startImport() throws Exception {
            // 创建到两个数据库的连接
            Class.forName("org.gjt.mm.mysql.Driver");
            Class.forName("oracle.jdbc.driver.OracleDriver");
    
            Connection connDest = DriverManager.getConnection(DEST_MYSQL_JDBC_URL);
            Connection connSource = DriverManager.getConnection(SOURCE_JDBC_URL, SOURCE_JDBC_USER,
                    SOURCE_JDBC_PASSWORD);
            
            // 查询出当前用户下面的所有表,依次处理(如果有外键,建议人工输入各表,以保证顺序;如果没有外键,直接运行下面程序即可。)
            try {
                
    /**            
                 // 方式一:自动运行
                Statement stmt = connSource.createStatement();
                ResultSet rs = stmt.executeQuery("select TABLE_NAME from USER_TABLES");
                while(rs.next()) {
                    try {
                        importTable(connSource, connDest, rs.getString("TABLE_NAME"));
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                rs.close();
                stmt.close();
    */            
                
                // 方式二:人工输入各表名(需要保证顺序,以确保有外键的表在主表之后插入数据)
                importTable(connSource, connDest, "BBSDETAIL");
                importTable(connSource, connDest, "BBSCOMMENT");
            } finally {
                // 自动关闭数据库资源?
                connDest.close();
                connSource.close();
            }
        }
        
        private void importTable(Connection connSource, Connection connDest, String tablename) throws Exception {
            Statement stmt = null;
            PreparedStatement pstmt = null;
            try {
                // 给PreparedStatement赋值,然后更新;如果是大数量的情况,可以考虑Batch处理。因为这里的数据量小,直接单条更新了。
                // 打开源数据库中相关表
                StringBuilder insertSQL = new StringBuilder();
                insertSQL.append("insert into " + tablename + "(");
                stmt= connSource.createStatement();
                ResultSet rs = stmt.executeQuery("select * from " + tablename);
                
                // 先计算目标数据库的PreparedStatement的SQL语句
                ResultSetMetaData rsmd = rs.getMetaData();
                int numberOfColumns = rsmd.getColumnCount();
                for(int i=1; i<=numberOfColumns;i++) {
                    insertSQL.append(rsmd.getColumnName(i) + ",");
                }
                insertSQL.deleteCharAt(insertSQL.length()-1);
                insertSQL.append(")values(");
                for(int i=1; i<=numberOfColumns;i++) {
                    insertSQL.append("?,");
                }
                insertSQL.deleteCharAt(insertSQL.length()-1);
                insertSQL.append(")");
                System.out.println(insertSQL.toString());
                
                // 计数
                int count = 0;
                // 每多少条记录提交一次,以提高效率
                int batchCount = 1000;
                pstmt = connDest.prepareStatement(insertSQL.toString());
                while(rs.next()) {
                    pstmt.clearParameters();
                    for(int i=1; i<=numberOfColumns;i++) {
                        if(rsmd.getColumnType(i) == java.sql.Types.NUMERIC) {
                            // 2
                            pstmt.setInt(i, rs.getInt(i));
                        }else if(rsmd.getColumnType(i) == java.sql.Types.DOUBLE) {
                            // 8
                            pstmt.setDouble(i, rs.getDouble(i));
                        }else if(rsmd.getColumnType(i) == java.sql.Types.CHAR
                                || rsmd.getColumnType(i) == java.sql.Types.VARCHAR
                                || rsmd.getColumnType(i) == java.sql.Types.CLOB) {
                            // 1
                            // 12
                            // 2005
                            pstmt.setString(i, rs.getString(i));
                        }else if(rsmd.getColumnType(i) == java.sql.Types.DATE) {
                            // 91
                            pstmt.setDate(i, rs.getDate(i));
                        }else if(rsmd.getColumnType(i) == java.sql.Types.TIMESTAMP) {
                            // 93
                            pstmt.setTimestamp(i, rs.getTimestamp(i));
                        }else {
                            pstmt.setObject(i, rs.getObject(i));
                        }
                    }
                    pstmt.addBatch();
                    
                    // 输出统计信息
                    count++;
                    if(count % batchCount == 0) {
                        // 若干条提交一次
                        System.out.println();
                        System.out.print("正在更新数据库...");
                        pstmt.executeBatch();
                        System.out.println(count);
                    }
                }
                if(count % batchCount != 0) {
                    // 最后提交一次
                    System.out.println();
                    System.out.print("正在更新数据库...");
                    pstmt.executeBatch();
                    System.out.println(count);
                }
                
                rs.close();
            } finally {
                if(stmt != null) stmt.close();
                if(pstmt != null) pstmt.close();
            }
        }
        
        public static void main(String[] args) throws Exception {
            CopyOracle2MySQL ins = new CopyOracle2MySQL();
            ins.startImport();
            
        }
    }
  • 相关阅读:
    Spring编译AOP项目报错
    Intellij新建Spring项目引入用户目录下的Spring jar包
    python如何安装第三方库
    sizeof and strlen整理
    数轴上从左到右有n个点a[0],a[1]…,a[n-1],给定一根长度为L的绳子,求绳子最多能覆盖其中的几个点。要求算法复杂度为o(n)。
    百度笔试题--最长回文字串
    微软笔试题
    人群智商差不多,是什么引起了差距?
    低层次“努力学习”和学习的本质
    集成 solr6.5.1到 tomcat7(8) 中 (解决java.lang.NoSuchMethodError问题)
  • 原文地址:https://www.cnblogs.com/nayitian/p/3423273.html
Copyright © 2011-2022 走看看