使用java實(shí)現(xiàn)備份和恢復(fù)SQLServer表數(shù)據(jù)
需求
近來(lái)工作中遇到一個(gè)問(wèn)題,內(nèi)網(wǎng)辦公系統(tǒng)中的數(shù)據(jù)需要導(dǎo)出到外網(wǎng)中進(jìn)行查詢,外網(wǎng)的數(shù)據(jù)庫(kù)中還有一些表存儲(chǔ)外網(wǎng)的數(shù)據(jù),因此無(wú)法使用全庫(kù)備份恢復(fù)功能來(lái)滿足需求。即只從內(nèi)網(wǎng)數(shù)據(jù)庫(kù)中導(dǎo)出若干表的內(nèi)容至外網(wǎng)數(shù)據(jù)庫(kù)的對(duì)應(yīng)表。
其他解決方案:使用SQL Server自身的導(dǎo)出SQL語(yǔ)句的方法其實(shí)也可以,但是涉及到幾十個(gè)表,一一手工導(dǎo)出工作量較大。
因此自己寫(xiě)了個(gè)函數(shù),將內(nèi)網(wǎng)中的表數(shù)據(jù)導(dǎo)出,根據(jù)數(shù)據(jù)生成insert into 語(yǔ)句,然后使用批處理的方式導(dǎo)入到外網(wǎng)數(shù)據(jù)庫(kù)中。
1.表結(jié)構(gòu)的分析
生成insert語(yǔ)句時(shí),不得不面對(duì)的是引號(hào)的使用,對(duì)于int等類(lèi)型無(wú)需引號(hào),但是對(duì)于char、text等必須加上引號(hào),一個(gè)表動(dòng)輒幾十個(gè)字段,人工用數(shù)組等方式記錄字段的類(lèi)型、名稱再進(jìn)行處理,也比較耗費(fèi)精力,尤其是數(shù)據(jù)表的結(jié)構(gòu)時(shí)常還在變化,而且是另一個(gè)開(kāi)發(fā)公司在維護(hù),何時(shí)變化也不得而知。這里通過(guò)分析建表語(yǔ)句完成了自動(dòng)的字段類(lèi)型的對(duì)應(yīng),從而大大減輕了人工維護(hù)字段及其類(lèi)型的工作量。
譬如建表語(yǔ)句如下(在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
從以上文字中,做出如下處理,即可獲得表名、字段名、字段類(lèi)型以及附帶的是否需要引號(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.備份表
獲取到完整的字段、字段屬性后,就可以開(kāi)始生成SQL文件了,對(duì)于值為null的數(shù)據(jù),略去相應(yīng)的插入語(yǔ)句,同時(shí)由于是全表全量導(dǎo)入,開(kāi)始時(shí)增加了delete from tableName;的語(yǔ)句
全部代碼如下:
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(); } //開(kāi)始生成insert語(yǔ)句 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í),只需將保存建表語(yǔ)句的sql文件位置作為參數(shù)即可,在本項(xiàng)目中,生成的sql文件以.lims2結(jié)尾。
3.還原表
由于生成的表數(shù)據(jù)文件較多,這里寫(xiě)了個(gè)批處理文件,將導(dǎo)出的表數(shù)據(jù)文件和該批處理文件一起拷貝到外網(wǎng)服務(wù)器中,運(yùn)行批處理即完成了導(dǎo)入操作。以后準(zhǔn)備寫(xiě)個(gè)上傳的頁(yè)面,省去了遠(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é)語(yǔ)
此方法適用于同步部分表而不是整庫(kù)的情況,尤其是兩個(gè)數(shù)據(jù)庫(kù)無(wú)法直接通信,需要手工同步的場(chǎng)景。
到此這篇關(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ò):類(lèi)文件具有錯(cuò)誤的版本61.0,應(yīng)為?52.0
這篇文章主要給大家介紹了關(guān)于解決Springboot啟動(dòng)報(bào)錯(cuò):類(lèi)文件具有錯(cuò)誤的版本?61.0,應(yīng)為?52.0的相關(guān)資料,這是查閱了網(wǎng)上的很多資料才解決的,分享給大家,需要的朋友可以參考下2023-01-01SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析
這篇文章主要介紹了SpringSecurity權(quán)限控制實(shí)現(xiàn)原理解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-03-03SpringBoot整合resilience4j實(shí)現(xiàn)接口限流
最近在開(kāi)發(fā)項(xiàng)目的時(shí)候,需要用到限流的功能,本文主要介紹了SpringBoot整合resilience4j實(shí)現(xiàn)接口限流,具有一定的參考價(jià)值,感興趣的可以了解一下2024-01-01Jenkins Pipeline為Kubernetes應(yīng)用部署增加狀態(tài)檢測(cè)腳本優(yōu)化
這篇文章主要為大家介紹了Jenkins Pipeline為Kubernetes應(yīng)用部署增加狀態(tài)檢測(cè)腳本優(yōu)化示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-12-12基于Spring中的線程池和定時(shí)任務(wù)功能解析
下面小編就為大家?guī)?lái)一篇基于Spring中的線程池和定時(shí)任務(wù)功能解析。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-09-09Spring中的@Value和@PropertySource注解詳解
這篇文章主要介紹了Spring中的@Value和@PropertySource注解詳解,@PropertySource:讀取外部配置文件中的key-value保存到運(yùn)行的環(huán)境變量中,本文提供了部分實(shí)現(xiàn)代碼,需要的朋友可以參考下2023-11-11Debian 7 和 Debian 8 用戶安裝 Java 8的方法
Oracle Java 8 穩(wěn)定版本近期已發(fā)布,有很多新的特征變化。其中,有功能的程序支持通過(guò)“Lambda項(xiàng)目 ”,收到了一些安全更新和界面改進(jìn)上的bug修復(fù),使得開(kāi)發(fā)人員的工作更容易。2014-03-03使用Java編寫(xiě)導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類(lèi)
這篇文章主要為大家詳細(xì)介紹了如何使用Java編寫(xiě)導(dǎo)出不確定行數(shù)列數(shù)數(shù)據(jù)的工具類(lèi),文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下2024-03-03java項(xiàng)目中讀取jdbc.properties文件操作
這篇文章主要介紹了java項(xiàng)目中讀取jdbc.properties文件操作,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-08-08