用Java寫了一個程式,將一個Mysql庫中的表,遷移到另外一個server上的Mysql庫中

用Navicat做數據遷移,因為數據量比較大,遷移過過程中一個是進展不直觀,另外就是cpu佔用率高的時候,螢幕跟死機了一樣點不動按鈕,不好中斷。

想了想,乾脆自己寫一個。

在網上找了一個sqllite遷移mysql數據的基礎程式碼,然後在這基礎上做了修改。

1、用這一個程式就能搞定指定資料庫表的數據遷移執行工作。

2、目前每次可以執行指定的資料庫表數組,但是不能僅僅單獨指定庫遷移所有表。

3、對於超大表的讀取和數據遷移做了優化,每次讀取1000條數據,每次遷移1000條數據。

4、整這程式碼的時間就兩個小時左右,所以觀賞性不佳,能執行數據遷移就ok。

5、支援mysql中中文數據的遷移,mysql庫要求用utf-8編碼。

6、如果遷移的表存在,則會先把表刪除,然後重建對應的表。

還有很多不足,敬請包涵。

  1 package com.alex;
  2 
  3 import java.sql.Connection;
  4 import java.sql.DriverManager;
  5 import java.sql.PreparedStatement;
  6 import java.sql.ResultSet;
  7 import java.sql.SQLException;
  8 import java.sql.Statement;
  9 
 10 
 11 
 12 public class TransDbData {
 13     //author [email protected]
 14     private Connection connSource=null;
 15     private Connection connDest=null;
 16     
 17     ///transTables=要傳輸的數據表名字的數組,如果是多個表,則完善此數組即可
 18     public static String[] transTables={"table-1","talbe-2","table-3"};
 19     private static  int curLine=0;
 20     
 21     public static void main(String[] args) {
 22         TransDbData test = new TransDbData();
 23         int k=0;
 24         int tableLineCount=0;
 25         int offset=1000;
 26         int start=0;
 27         int loopTimes=0;
 28         try {
 29             for(int i=0;i<transTables.length;i++) {
 30                 test.createDestTable(transTables[i]);
 31                 tableLineCount=test.getTableLineCount(transTables[i]);
 32                 int xx=tableLineCount%1000;
 33                 loopTimes=(int) Math.ceil(tableLineCount/offset);
 34                 for(int loopN=0;loopN<loopTimes;loopN++) {
 35                     curLine++;
 36                     System.out.println("正在處理第"+curLine+"批(每批數據1000條)數據");
 37                     test.deal(transTables[i],tableLineCount,loopN,offset);
 38                 }
 39             }
 40         } catch (SQLException e) {
 41             e.printStackTrace();
 42         }
 43     }
 44  
 45     
 46     
 47     private Connection getSourceConn(){
 48         try {
 49             Class.forName("com.mysql.jdbc.Driver");
 50             String connStr="jdbc:mysql://mysql-server-數據源-ip:3306/yourdb?useSSL=false&Charset=utf8&characterEncoding=utf-8";
 51             connSource = DriverManager.getConnection(connStr,"root","abcdef");
 52             if(connSource!=null) {
 53                 System.out.println("源資料庫連上了"+connStr);
 54                 
 55             }
 56             return connSource;
 57         } catch (ClassNotFoundException | SQLException e) {
 58             e.printStackTrace();
 59         }
 60         return null;
 61     }
 62     
 63     private Connection getDestConn(){
 64         try {
 65             Class.forName("com.mysql.jdbc.Driver");
 66             String connStr="jdbc:mysql://mysql-server-目標庫-ip:3306/your-db?useSSL=false&Charset=utf8&characterEncoding=utf-8";
 67             connDest = DriverManager.getConnection(connStr,"root","123456");
 68             if(connDest!=null) {
 69                 System.out.println("目標資料庫連上了"+connStr);
 70             }
 71             return connDest;
 72         } catch (ClassNotFoundException | SQLException e) {
 73             e.printStackTrace();
 74         }
 75         return null;
 76     }
 77 
 78    /**
 79     * 獲得表的數據總量
 80     * @param transTableName
 81     * @return
 82     */
 83    public int getTableLineCount(String transTableName) {
 84        Connection srcConn = this.getSourceConn();
 85        Statement srcStmt;
 86        int count=0;
 87     try {
 88         srcStmt = srcConn.createStatement();
 89          ResultSet srcRsCount = srcStmt.executeQuery("select count(*) from "+ transTableName);
 90            while(srcRsCount.next()) {
 91                count=srcRsCount.getInt(1);
 92                System.out.println("一共有["+srcRsCount.getInt(1)+"]條數據要傳輸");
 93            }
 94            srcRsCount.close();
 95            srcStmt.close();
 96            srcConn.close();
 97     } catch (SQLException e) {
 98         e.printStackTrace();
 99     }
100     return count;
101    }
102     
103     
104     /**
105      * 
106      * @param transTableName 被傳輸的資料庫表名稱
107      * @throws SQLException
108      */
109     public void deal(String transTableName,int tableLineCount,int loopN,int offset) throws SQLException {
110         //數據源資料庫
111         Connection srcConn = this.getSourceConn();
112         Statement srcStmt =srcConn.createStatement();
113     
114         int startPosition = loopN*offset +1;
115         ResultSet srcRs = srcStmt.executeQuery("select * from "+ transTableName +" limit "+startPosition+" ,"+offset+" ");
116         //結果集獲取到的長度
117         int size = srcRs.getMetaData().getColumnCount();
118         //比較懶,拼接insert into 語句
119         StringBuffer sbf =new StringBuffer();
120         sbf.append("insert into "+transTableName+" values (");
121         String link ="";
122         for (int i = 0; i <size ; i++) {
123             sbf.append(link).append("?");
124             link=",";
125         }
126         sbf.append(")");
127         //MySQL資料庫
128         Connection destconn = getDestConn();
129         PreparedStatement destPstmt = destconn.prepareStatement(sbf.toString());
130         //System.out.println(sbf.toString());
131         //取出結果集並向MySQL資料庫插入數據 ( 使用批處理 )
132         //完成條數
133         int count =0;
134         int num=0;
135         //取消事務(不寫入日誌)
136         destconn.setAutoCommit(false);
137         long start = System.currentTimeMillis();
138         //循環原表,從原表中讀取數據
139         while (srcRs.next()) {
140             ++count;
141             System.out.print(".");
142             //System.out.println("讀取第"+count+"條數據");
143             for (int i=1;i<= size;i++) {
144                 destPstmt.setObject(i, srcRs.getObject(i));
145             }
146 
147             //將預先語句存儲起來,這裡還沒有向資料庫插入
148             destPstmt.addBatch();
149             //當count 到達 20000條時 向資料庫提交
150             if (count % 20000 ==0 ){
151                 ++num;
152                 destPstmt.executeBatch();
153                 System.out.println("表【"+transTableName+"】數據傳輸第"+num+"次提交,耗時:"+(System.currentTimeMillis()-start)/1000.0+"s");
154             }
155         }
156         //防止有數據未提交
157         destPstmt.executeBatch();
158         //提交
159         destconn.commit();
160         System.out.println("本次完成【"+count+"】條數據,耗時:"+(System.currentTimeMillis()-start)/1000.0+"s");
161         //恢復事務
162        // mysqlconn.setAutoCommit(true);
163 
164         //關閉資源
165         close(destconn,destPstmt,null);
166         close(srcConn,srcStmt,srcRs);
167 
168     }
169 
170     
171     /**
172      * 根據源表名,在目的庫中創建對應表
173      * @param srcTableName
174      */
175     public void createDestTable(String srcTableName) {
176         String tableName = srcTableName;
177         Connection src_conn = this.getSourceConn();
178         Connection dest_conn= this.getDestConn();
179         String sql = String.format("SHOW CREATE TABLE %s", tableName);//查詢sql
180         //String sql = "SHOW CREATE TABLE ?";
181         PreparedStatement ps = null;
182         PreparedStatement ps_dest = null;
183         String dropTable="drop table "+srcTableName;
184         try {
185             System.out.println("如果表存在,先刪除:"+srcTableName);
186             ps_dest=dest_conn.prepareStatement(dropTable);
187             ps_dest.execute();
188             ps_dest.close();
189             System.out.println("刪除成功:"+srcTableName);
190             
191         } catch (SQLException e1) {
192             System.err.println(e1.getMessage());
193             System.out.println("表原先不存在:"+srcTableName);
194             
195         }
196         
197         try {
198             
199             ps = src_conn.prepareStatement(sql);
200             //ps.setString(1, tableName);
201             ResultSet resultSet = ps.executeQuery();
202             while (resultSet.next()) {
203                 //System.out.println(resultSet.getString(1));//第一個參數獲取的是tableName
204                 String destTableName=resultSet.getString(1);
205                // System.out.println(resultSet.getString(2));//第二個參數獲取的是表的ddl語句
206                 String ddl=resultSet.getString(2);
207                 ps_dest = dest_conn.prepareStatement(ddl);
208                 ps_dest.execute();
209                 System.out.println("目標庫中創建表成功:" +destTableName);
210                 ps_dest.close();
211 
212             }
213         } catch (SQLException e) {
214             e.printStackTrace();
215         } finally {
216             if(null != ps){
217                 try {
218                     ps.close();
219                 } catch (SQLException e) {
220                     e.printStackTrace();
221                 }
222             }
223             if(null != ps_dest){
224                 try {
225                     ps_dest.close();
226                 } catch (SQLException e) {
227                     e.printStackTrace();
228                 }
229             }
230             if(null != src_conn) {
231                 try {
232                     src_conn.close();
233                 } catch (SQLException e) {
234                     e.printStackTrace();
235                 }
236             }
237             if(null != dest_conn) {
238                 try {
239                     dest_conn.close();
240                 } catch (SQLException e) {
241                     e.printStackTrace();
242                 }
243             }
244         }
245 
246     }
247 
248     //關閉資料庫連接    
249     public  void  close(Connection conn,Statement stmt,ResultSet rs){
250 
251         if(rs!=null){
252             try {
253                 rs.close();
254             } catch (SQLException e) {
255                 e.printStackTrace();
256             }
257         }
258         if(stmt!=null){
259             try {
260                 stmt.close();
261             } catch (SQLException e) {
262                 e.printStackTrace();
263             }
264         }
265         if(conn!=null){
266             try {
267                 conn.close();
268             } catch (SQLException e) {
269                 e.printStackTrace();
270             }
271         }
272     }
273 
274 }

 

執行過程中的日誌輸入:

 

 

Tags: