第一次寫博客,希望能幫到別人,同時願意相互進行一些討論,互相進步。
最近在做有關項目的時候,由於服務器數據庫被其他人算法讀取,導致我讀取的時候很慢,於是乎打算將自己需要的表導入到本地的mysql數據庫進行處理,剛開始當然是不想寫代碼,嘗試用kettle實現表遷移,但是無奈數據量較大,可kettle內存溢出。痛下決心自己實現。
基本思路就是先從數據庫中抽取出數據存儲到ResultSet的一個集合中,一個next,存到一個List<List<String>>,為避免內存溢出,設置數組大小超過一個閾值就寫入數據庫,然后清空又重新讀取,在寫入。其實這個也是借鑒於kettle的提交Size;
首先是分別建立MySQL和Oracle的鏈接方法。
Oracle數據連接
其實mysql方法和Oracle一樣的,只是換成mysql的驅動和數據庫罷了:public static Connection getConnection(){
Connection conn = null;
String DRIVER="oracle.jdbc.driver.OracleDriver";
String url = "jdbc:oracle:" + "thin:@127.0.0.1:1521:XE";// 127.0.0.1是本機地址,XE是精簡版Oracle的默認數據庫名
String user = "user";// 用戶名,系統默認的賬戶名
String password = "***";// 你安裝時選設置的密碼
try {
Class.forName(DRIVER);// 加載數據庫驅動程序
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
try {
conn = DriverManager.getConnection(url, user, password);// 獲得Connection對象
} catch (SQLException e) {
e.printStackTrace();
}
return conn;
}
Class.forName("com.mysql.jdbc.Driver");然后是抽取數據了:
String url = "jdbc:mysql://localhost:3306/spider";
String user = "root";
String password = "***";
executeManySql(FindList)函數如下,因為數據量比較大,所以我設置的每次提交大小為10000,這樣就不會內存溢出了。public static List<List<String>> tableInput() throws FileNotFoundException,
SQLException {
List<List<String>> FindList = new ArrayList<List<String>>();
Connection con = Oracle_con.getConnection();
PreparedStatement pre = null;
ResultSet resultSet = null;
String sql = "SELECT ID,MEDID,COMMODITYNAME,JBBM,JBMC,JZHOSPITALID,DOCTORNAME FROM DISEASE_DRUG_ASSOCIATE_test";
try {
pre = con.prepareStatement(sql);
resultSet = pre.executeQuery();
String[] columu = {"ID","MEDID","COMMODITYNAME","JBBM","JBMC","JZHOSPITALID","DOCTORNAME"};
int i=0;
while (resultSet.next()) {
List<String> minList = new ArrayList<String>();
for(String each:columu){
minList.add(resultSet.getString(each));
}
FindList.add(minList);
i++;
if(i%10000==0){ //設置的每次提交大小為10000
executeManySql(FindList);
FindList.removeAll(FindList);
System.out.println(i);
}
}
executeManySql(FindList);//最后別忘了提交剩余的
return FindList;
} catch (SQLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} finally {
try {
pre.close();// 關閉Statement
} catch (SQLException e) {
e.printStackTrace();
}
try {
con.close();// 關閉Connection
} catch (SQLException e) {
e.printStackTrace();
}
}
return null;
}
public static void executeManySql(List<List<String>> FindList) throws SQLException {同時我還設置了計時的函數,可以看到這個從數據抽取到完成數據遷移的時間。
Connection con = mysqlConnection.getConnection();
con.setAutoCommit(false);
Statement stat = null;
PreparedStatement pst = (PreparedStatement) con
.prepareStatement("insert into disease_drug_associate_view values (?,?,?,?,?,?,?)");
for (List<String> minList: FindList) {
for(int i=0;i<minList.size();i++){
pst.setString(i+1, minList.get(i));
}
// 把一個SQL命令加入命令列表
pst.addBatch();
}
// 執行批量更新
pst.executeBatch();
// 語句執行完畢,提交本事務
con.commit();
pst.close();
con.close();//一定要記住關閉連接,不然mysql回應為too many connection自我保護而斷開。
}
其實用時真不好說,這個和程序本身、抽取數據的主機以及本機的硬盤讀取速度有比較大的關系。public static void main(String[] args) throws FileNotFoundException,
SQLException {
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss:SS");
TimeZone t = sdf.getTimeZone();
t.setRawOffset(0);
sdf.setTimeZone(t);
Long startTime = System.currentTimeMillis();
//此段為要放置測取時間的函數
mysqlConnection.executeSql("TRUNCATE table disease_drug_associate_view");
List<List<String>> newDrug = tableInput();
Long endTime = System.currentTimeMillis();
System.out.println("用時:" + sdf.format(new Date(endTime - startTime)));
}
最終我抽取的數據是84800000,將近2G的數據,
用時:00:57:13:313,五十七分鍾還是可以了。