使用java實(shí)現(xiàn)備份和恢復(fù)SQLServer表數(shù)據(jù)
需求
近來工作中遇到一個(gè)問題,內(nèi)網(wǎng)辦公系統(tǒng)中的數(shù)據(jù)需要導(dǎo)出到外網(wǎng)中進(jìn)行查詢,外網(wǎng)的數(shù)據(jù)庫中還有一些表存儲(chǔ)外網(wǎng)的數(shù)據(jù),因此無法使用全庫備份恢復(fù)功能來滿足需求。即只從內(nèi)網(wǎng)數(shù)據(jù)庫中導(dǎo)出若干表的內(nèi)容至外網(wǎng)數(shù)據(jù)庫的對(duì)應(yīng)表。
其他解決方案:使用SQL Server自身的導(dǎo)出SQL語句的方法其實(shí)也可以,但是涉及到幾十個(gè)表,一一手工導(dǎo)出工作量較大。
因此自己寫了個(gè)函數(shù),將內(nèi)網(wǎng)中的表數(shù)據(jù)導(dǎo)出,根據(jù)數(shù)據(jù)生成insert into 語句,然后使用批處理的方式導(dǎo)入到外網(wǎng)數(shù)據(jù)庫中。
1.表結(jié)構(gòu)的分析
生成insert語句時(shí),不得不面對(duì)的是引號(hào)的使用,對(duì)于int等類型無需引號(hào),但是對(duì)于char、text等必須加上引號(hào),一個(gè)表動(dòng)輒幾十個(gè)字段,人工用數(shù)組等方式記錄字段的類型、名稱再進(jìn)行處理,也比較耗費(fèi)精力,尤其是數(shù)據(jù)表的結(jié)構(gòu)時(shí)常還在變化,而且是另一個(gè)開發(fā)公司在維護(hù),何時(shí)變化也不得而知。這里通過分析建表語句完成了自動(dòng)的字段類型的對(duì)應(yīng),從而大大減輕了人工維護(hù)字段及其類型的工作量。
譬如建表語句如下(在SQL Server企業(yè)管理器中選中表,Ctrl+C即可得到),這里存放一個(gè)文件中:
CREATE TABLE [Import_BizDescrs] ( [DescrId] [char] (10) COLLATE Chinese_PRC_CI_AS NULL , [DescrType] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [DescrAt] [datetime] NULL , [Descr] [text] COLLATE Chinese_PRC_CI_AS NULL , [DescrBy] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [BizId] [char] (10) COLLATE Chinese_PRC_CI_AS NULL , [SampId] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [AssistTaskId] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [CreatePerson] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [CreateDate] [datetime] NULL , [UpdatePerson] [char] (20) COLLATE Chinese_PRC_CI_AS NULL , [UpdateDate] [datetime] NULL ) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY] GO
從以上文字中,做出如下處理,即可獲得表名、字段名、字段類型以及附帶的是否需要引號(hào)。
public static void exportTableDataByCreateSQL(String createSQLFileName){
ArrayList <String> fieldNames = new ArrayList<String>();
ArrayList <String> fieldtypes = new ArrayList<String>();
ArrayList <Boolean> needQuotationMark = new ArrayList<Boolean>();
String tableName = "";
String filePath = "C:\\importSQLs\\";
String tmpString;
try {
BufferedReader reader = new BufferedReader(new FileReader(createSQLFileName));
String line = reader.readLine();
//從第一行獲取表名
tableName = line.substring(line.indexOf("[")+1,line.indexOf("]"));;
System.out.println(tableName) ;
//后面獲取其他信息
while ((line = reader.readLine()) != null) {
if(line.startsWith(")")){
break;
}
tmpString = line.substring(line.indexOf("[")+1,line.indexOf("]"));
fieldNames.add(tmpString);
line = line.substring(line.indexOf("]")+1);
tmpString = line.substring(line.indexOf("[")+1,line.indexOf("]"));
fieldtypes.add(tmpString);
if(tmpString.contains("char")
||tmpString.contains("text")
||tmpString.contains("datetime")){
needQuotationMark.add(true);
}else{
needQuotationMark.add(false);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}2.備份表
獲取到完整的字段、字段屬性后,就可以開始生成SQL文件了,對(duì)于值為null的數(shù)據(jù),略去相應(yīng)的插入語句,同時(shí)由于是全表全量導(dǎo)入,開始時(shí)增加了delete from tableName;的語句
全部代碼如下:
public static void exportTableDataByCreateSQL(String createSQLFileName){
ArrayList <String> fieldNames = new ArrayList<String>();
ArrayList <String> fieldtypes = new ArrayList<String>();
ArrayList <Boolean> needQuotationMark = new ArrayList<Boolean>();
String tableName = "";
String filePath = "C:\\importSQLs\\";
String tmpString;
try {
BufferedReader reader = new BufferedReader(new FileReader(createSQLFileName));
String line = reader.readLine();
//從第一行獲取表名
tableName = line.substring(line.indexOf("[")+1,line.indexOf("]"));;
//后面獲取其他信息
while ((line = reader.readLine()) != null) {
if(line.startsWith(")")){
break;
}
tmpString = line.substring(line.indexOf("[")+1,line.indexOf("]"));
fieldNames.add(tmpString);
line = line.substring(line.indexOf("]")+1);
tmpString = line.substring(line.indexOf("[")+1,line.indexOf("]"));
fieldtypes.add(tmpString);
if(tmpString.contains("char")
||tmpString.contains("text")
||tmpString.contains("datetime")){
needQuotationMark.add(true);
}else{
needQuotationMark.add(false);
}
}
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//開始生成insert語句
Connection conn;
try {
Class.forName("net.sourceforge.jtds.jdbc.Driver");
conn = DriverManager.getConnection(GlobalVar.ConnURL,GlobalVar.ConnUser,GlobalVar.ConnPWD);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM " + tableName);
FileWriter writer = new FileWriter(filePath + tableName+".lims2", false);
BufferedWriter bufferedWriter = new BufferedWriter(writer);
bufferedWriter.write("delete from "+tableName + ";");
bufferedWriter.newLine();
while (rs.next()) {
String FieldsString="";
String ValuesString="";
for(int i=0; i< needQuotationMark.size();i++){
tmpString = rs.getString(fieldNames.get(i));
if(tmpString != null){
if(FieldsString.equals("")){
FieldsString += fieldNames.get(i);
ValuesString += (needQuotationMark.get(i)?"'":"")+ tmpString.trim() +(needQuotationMark.get(i)?"'":"");
}else{
FieldsString += "," + fieldNames.get(i);
ValuesString += "," + (needQuotationMark.get(i)?"'":"")+ tmpString.trim() + (needQuotationMark.get(i)?"'":"");
}
}
}
bufferedWriter.write("insert into "+ tableName + "("+FieldsString+") values("+ValuesString+");");
bufferedWriter.newLine();
}
bufferedWriter.close();
writer.close();
rs.close();
stmt.close();
conn.close();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}調(diào)用以上函數(shù)時(shí),只需將保存建表語句的sql文件位置作為參數(shù)即可,在本項(xiàng)目中,生成的sql文件以.lims2結(jié)尾。
3.還原表
由于生成的表數(shù)據(jù)文件較多,這里寫了個(gè)批處理文件,將導(dǎo)出的表數(shù)據(jù)文件和該批處理文件一起拷貝到外網(wǎng)服務(wù)器中,運(yùn)行批處理即完成了導(dǎo)入操作。以后準(zhǔn)備寫個(gè)上傳的頁面,省去了遠(yuǎn)程桌面的麻煩。批處理文件如下:
osql -S 127.0.0.1 -U 用戶名 -P 密碼 -d lims2 -i Import_table1.lims2 -o Rst_Import_table1.log
osql -S 127.0.0.1 -U 用戶名 -P 密碼 -d lims2 -i import_table2.lims2 -o Rst_import_table2.log
osql -S 127.0.0.1 -U 用戶名 -P 密碼 -d lims2 -i Import_table3.lims2 -o Rst_Import_table3.log
osql -S 127.0.0.1 -U 用戶名 -P 密碼 -d lims2 -i import_table4.lims2 -o Rst_import_table4.log
osql -S 127.0.0.1 -U 用戶名 -P 密碼 -d lims2 -i import_table5.lims2 -o Rst_import_table5.log
........
結(jié)語
此方法適用于同步部分表而不是整庫的情況,尤其是兩個(gè)數(shù)據(jù)庫無法直接通信,需要手工同步的場景。
到此這篇關(guān)于使用java實(shí)現(xiàn)備份和恢復(fù)SQLServer表數(shù)據(jù)的文章就介紹到這了,更多相關(guān)java備份和恢復(fù)SQLServer表數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
解決Springboot啟動(dòng)報(bào)錯(cuò):類文件具有錯(cuò)誤的版本61.0,應(yīng)為?52.0
這篇文章主要給大家介紹了關(guān)于解決Springboot啟動(dòng)報(bào)錯(cuò):類文件具有錯(cuò)誤的版本?61.0,應(yīng)為?52.0的相關(guān)資料,這是查閱了網(wǎng)上的很多資料才解決的,分享給大家,需要的朋友可以參考下2023-01-01
SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析
這篇文章主要介紹了SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03
SpringBoot整合resilience4j實(shí)現(xiàn)接口限流
最近在開發(fā)項(xiàng)目的時(shí)候,需要用到限流的功能,本文主要介紹了SpringBoot整合resilience4j實(shí)現(xiàn)接口限流,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01
Jenkins Pipeline為Kubernetes應(yīng)用部署增加狀態(tài)檢測腳本優(yōu)化
這篇文章主要為大家介紹了Jenkins Pipeline為Kubernetes應(yīng)用部署增加狀態(tài)檢測腳本優(yōu)化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12
基于Spring中的線程池和定時(shí)任務(wù)功能解析
下面小編就為大家?guī)硪黄赟pring中的線程池和定時(shí)任務(wù)功能解析。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-09-09
Spring中的@Value和@PropertySource注解詳解
這篇文章主要介紹了Spring中的@Value和@PropertySource注解詳解,@PropertySource:讀取外部配置文件中的key-value保存到運(yùn)行的環(huán)境變量中,本文提供了部分實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-11-11
Debian 7 和 Debian 8 用戶安裝 Java 8的方法
Oracle Java 8 穩(wěn)定版本近期已發(fā)布,有很多新的特征變化。其中,有功能的程序支持通過“Lambda項(xiàng)目 ”,收到了一些安全更新和界面改進(jìn)上的bug修復(fù),使得開發(fā)人員的工作更容易。2014-03-03
使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類
這篇文章主要為大家詳細(xì)介紹了如何使用Java編寫導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03
java項(xiàng)目中讀取jdbc.properties文件操作
這篇文章主要介紹了java項(xiàng)目中讀取jdbc.properties文件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-08-08

