1. 程式人生 > >將表中的資料複製到另一個數據庫的表中

將表中的資料複製到另一個數據庫的表中

1. 在 src 目錄下建立 jdbc.properties

#Oracle
oracle.driver=oracle.jdbc.driver.OracleDriver
oracle.jdbcUrl=jdbc:oracle:thin:@localhost:1521:orcl
oracle.user=scott
oracle.password=tiger

#MySQL
mysql.driver=com.mysql.jdbc.Driver
mysql.jdbcUrl=jdbc:mysql://localhost:3306/test
mysql.user=root
mysql.password=root

#SQL Server
sqlserver.driver=com.microsoft.sqlserver.jdbc.SQLServerDriver
sqlserver.jdbcUrl=jdbc:sqlserver://localhost:1433;DatabaseName=tempdb
sqlserver.user=sa
sqlserver.password=123456

2. 編寫 JdbcUtils 工具類

import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
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;
import java.util.Properties;

public class JdbcUtils {
	
	public static enum DatabaseType {
		Oracle("oracle"), 
		SQL_Server("sqlserver"), 
		MySQL("mysql");
		
		private String name;
		private DatabaseType(String name) {
			this.name = name;
		}
		public String getName() {
			return name;
		}
	};

	private static Properties props;
	
	static {
		try {
			InputStream in = Thread.currentThread()
					.getContextClassLoader()
					.getResourceAsStream("jdbc.properties");
			props = new Properties();
			props.load(in);
		} catch (IOException e) {
			throw new ExceptionInInitializerError(e);
		}
	}
	
	/**
	 *  獲取資料庫連線
	 * @param type 要操作的資料庫
	 * @return
	 * @throws Exception
	 */
	public static Connection getConnection(DatabaseType type) throws Exception {
		Class.forName(props.getProperty(type.getName() + ".driver"));
		String jdbcUrl = props.getProperty(type.getName() + ".jdbcUrl");
		String user = props.getProperty(type.getName() + ".user");
		String password = props.getProperty(type.getName() + ".password");
		return DriverManager.getConnection(jdbcUrl, user, password);
	}
	
	/**
	 * 將查詢的資料複製到另一個數據庫的表中,要求兩張表的欄位名,欄位型別完全相同。
	 * @param src 要查詢的資料庫
	 * @param sql 要查詢的 SQL
	 * @param dest 目標資料庫
	 * @param destTableName 目標表名稱
	 * @return
	 */
	public static int[] copy(DatabaseType src, String sql, DatabaseType dest, String destTableName ) {
		int count[] = new int[0];
		List<Map<String,Object>> query = JdbcUtils.query(DatabaseType.Oracle, sql);
		String insertSql = "insert into %s(%s) values(%s)";
		StringBuilder key = new StringBuilder();
		StringBuilder value = new StringBuilder();
		List<String> columns = new ArrayList<>();
		List<List<Object>> params = new ArrayList<>();
		if(query.size() > 0) {
			for(String column : query.get(0).keySet()) {
				key.append(column).append(",");
				value.append("?,");
				columns.add(column);
			}
			insertSql = String.format(insertSql, 
					destTableName,
					key.substring(0, key.length()-1).toString(),
					value.substring(0, value.length()-1).toString());
			
			for (Map<String, Object> map : query) {
				List<Object> param = new ArrayList<>();
				for (String column : columns) {
					param.add(map.get(column));
				}
				params.add(param);
			}
			count = JdbcUtils.executeBatch(DatabaseType.MySQL, insertSql, params);
		}
		return count;
	}
	
	/**
	 * 批量執行多條 SQL 語句
	 * @param type 要執行的資料庫
	 * @param sqls SQL 語句
	 * @return
	 */
	public static int[] executeBatch(DatabaseType type, List<String> sqls) {
		int count[] = new int[0];
		Connection conn = null;
		Statement stmt = null;
		try {
			conn = getConnection(type);
			boolean autoCommit = conn.getAutoCommit();
			conn.setAutoCommit(false);
			stmt = conn.createStatement();
			
			for (String sql : sqls) {
				stmt.addBatch(sql);
			}
			count = stmt.executeBatch();
			conn.commit();
			conn.setAutoCommit(autoCommit);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			closeStatement(stmt);
			closeConnection(conn);
		}
		return count;
	}
	
	/**
	 * 批量執行一個 SQL 語句,可以傳不同的引數
	 * @param type 要執行的資料庫
	 * @param sql SQL 語句
	 * @param params 引數列表
	 * @return
	 */
	public static int[] executeBatch(DatabaseType type, String sql, List<List<Object>> params) {
		int count[] = new int[0];
		Connection conn = null;
		PreparedStatement pst = null;
		try {
			conn = getConnection(type);
			boolean autoCommit = conn.getAutoCommit();
			conn.setAutoCommit(false);
			pst = conn.prepareStatement(sql);
			
			for (List<Object> list : params) {
				for(int i = 0; i < list.size(); i++) {
					pst.setObject(i + 1, list.get(i));
				}
				pst.addBatch();
			}
			count = pst.executeBatch();
			conn.commit();
			conn.setAutoCommit(autoCommit);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			closeStatement(pst);
			closeConnection(conn);
		}
		return count;
	}
	
	/**
	 * 執行單條 SQL 語句
	 * @param type 要執行的資料庫
	 * @param sql SQL 語句
	 * @param args 引數列表
	 * @return 
	 */
	public static int execute(DatabaseType type, String sql, Object...args) {
		int count = 0;
		Connection conn = null;
		PreparedStatement pst = null;
		try {
			conn = getConnection(type);
			boolean autoCommit = conn.getAutoCommit();
			conn.setAutoCommit(false);
			pst = conn.prepareStatement(sql);
			for(int i = 0; i < args.length; i++) {
				pst.setObject(i + 1, args[i]);
			}
			count = pst.executeUpdate();
			conn.commit();
			conn.setAutoCommit(autoCommit);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			closeStatement(pst);
			closeConnection(conn);
		}
		return count;
	}
	
	/**
	 * 查詢資料並封裝到 List 集合中
	 * @param type 要查詢的資料庫
	 * @param sql SQL 語句
	 * @param args 引數列表
	 * @return List<Map<欄位名, 值>>
	 */
	public static List<Map<String, Object>> query(DatabaseType type, String sql, Object...args) {
		List<Map<String, Object>> result = new ArrayList<>();
		Connection conn = null;
		PreparedStatement pst = null;
		ResultSet rs = null;
		try {
			conn = getConnection(type);
			pst = conn.prepareStatement(sql);
			for(int i = 0; i < args.length; i++) {
				pst.setObject(i + 1, args[i]);
			}
			rs = pst.executeQuery();
			ResultSetMetaData rsmd = rs.getMetaData();
			
			int columnCount = rsmd.getColumnCount();
			List<String> columns = new ArrayList<>(columnCount);
			for(int i = 1; i <= columnCount; i++) {
				columns.add(rsmd.getColumnName(i)); // 欄位名
			}
			while(rs.next()) {
				Map<String, Object> map = new HashMap<>();
				for (String column : columns) {
					map.put(column, rs.getObject(column));
				}
				result.add(map);
			}
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			closeStatement(pst);
			closeConnection(conn);
		}
		return result;
	}
	
	/**
	 * 關閉 Statement
	 * @param stmt
	 * @return
	 */
	public static boolean closeStatement(Statement stmt) {
		boolean flag = true;
		if(stmt != null) {
			try {
				stmt.close();
			} catch (SQLException e) {
				flag = false;
			}
		}
		return flag;
	}
	
	/**
	 * 關閉 ResultSet
	 * @param rs
	 * @return
	 */
	public static boolean closeResultSet(ResultSet rs) {
		boolean flag = true;
		if(rs != null) {
			try {
				rs.close();
			} catch (SQLException e) {
				flag = false;
			}
		}
		return flag;
	}
	
	/**
	 * 關閉 Connection
	 * @param conn
	 * @return
	 */
	public static boolean closeConnection(Connection conn) {
		boolean flag = true;
		if(conn != null) {
			try {
				conn.close();
			} catch (SQLException e) {
				flag = false;
			}
		}
		return flag;
	}
}

3. 編寫測試程式碼

import demo.JdbcUtils.DatabaseType;

public class Test {
	
	public static void main(String[] args) throws Exception {

		// 將 oracle 中的 scott.emp 表中的資料插入到 mysql 的 emp 表中
		long start = System.currentTimeMillis();
		String sql = "select a.* from emp a";
		int[] count = JdbcUtils.copy(DatabaseType.Oracle, sql, DatabaseType.MySQL, "emp");
		long end = System.currentTimeMillis();
		System.out.println(String.format("用時:%s, count.length = %s", end - start, count.length));
		
	}
}

4. 執行結果

用時:1442, count.length = 14