用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 }
執行過程中的日誌輸入: