java批量处理数据库语句_Java项目中调用bat批处理进行多用户数据库备份
Java項(xiàng)目中調(diào)用bat批處理配合使用BCP進(jìn)行多用戶數(shù)據(jù)的備份
一、項(xiàng)目需求
最近項(xiàng)目中需要對(duì)數(shù)據(jù)庫(Sql Server系列數(shù)據(jù)庫)進(jìn)行備份。項(xiàng)目中的需求不是簡單的整個(gè)數(shù)據(jù)庫的備份,而是根據(jù)用戶來備份,具體的備份策略如下:
①系統(tǒng)為某一賽事管理類型的系統(tǒng),整個(gè)系統(tǒng)分為幾部分,前半部分的處理是在服務(wù)器上處理,后半部分的處理,是在用戶自己的客戶端中處理。不同的賽事對(duì)應(yīng)不同的用戶,用戶將需要的數(shù)據(jù)提交給系統(tǒng)進(jìn)行處理。
②系統(tǒng)在處理完數(shù)據(jù)之后,用戶可以導(dǎo)出自己賽事相關(guān)的數(shù)據(jù)了,這個(gè)導(dǎo)出實(shí)際上做的就是個(gè)備份數(shù)據(jù)庫,只不過只備份屬于自己的數(shù)據(jù)庫。然后下載系統(tǒng)的處理結(jié)果,很顯然,各個(gè)用戶的數(shù)據(jù)是不相同的。
③用戶下載自己備份的數(shù)據(jù)庫文件(這些個(gè)文件會(huì)打包成zip壓縮包),再導(dǎo)入自己的客戶端系統(tǒng)中。
整個(gè)系統(tǒng)使用的關(guān)鍵是:程序中調(diào)用bcp命令的時(shí)候傳遞用戶相關(guān)的參數(shù)過去就OK了。處理流程如圖1-1所示:
圖1-1 處理流程
二、解決方案
本文提出的是使用Runtime.getRuntime().exec()調(diào)用批處理文件,程序中傳遞相關(guān)參數(shù)給bcp命令。關(guān)于BCP命令的詳解,微軟的MSDN上面寫的非常的詳細(xì),在此就不贅述了!下面的一段話引用自微軟的msdn上面的一段介紹:
bcp 實(shí)用工具可以在 Microsoft SQL Server 實(shí)例和用戶指定格式的數(shù)據(jù)文件間大容量復(fù)制數(shù)據(jù)。使用 bcp 實(shí)用工具可以將大量新行導(dǎo)入 SQL Server 表,或?qū)⒈頂?shù)據(jù)導(dǎo)出到數(shù)據(jù)文件。除非與 queryout 選項(xiàng)一起使用,否則使用該實(shí)用工具不需要了解 Transact-SQL 知識(shí)。若要將數(shù)據(jù)導(dǎo)入表中,必須使用為該表創(chuàng)建的格式文件,或者必須了解表的結(jié)構(gòu)以及對(duì)于該表中的列有效的數(shù)據(jù)類型。
三、系統(tǒng)的實(shí)現(xiàn)
實(shí)現(xiàn)主要分為批處理文件的編寫和Java程序中的調(diào)用兩部分,這兩部分完成之后,第一部分中的后續(xù)問題就好解決了。
①批處理編寫:
編寫的批處理文件如下,也就是使用bcp工具來進(jìn)行備份
這里只列出部分表,代碼都是一樣的,使用的時(shí)候稍微修改下即可!@Title 根據(jù)userId導(dǎo)出的表
@bcp "SELECT * FROM sportSys.dbo.competitions wheresportSys.dbo.competitions.userId="+%1 queryout %2competitions.xls -T -c>>%3log.txt
@echo competitions表備份已完成!>>%3log.txt
@bcp "SELECT * FROM sportSys.dbo.item wheresportSys.dbo.item.userId="+%1 queryout %2item.xls -T -c>>%3log.txt
@echo item表備份已完成!>>%3log.txt
@bcp "SELECT * FROM sportSys.dbo.itemType wheresportSys.dbo.itemType.userId="+%1 queryout %2itemType.xls -T -c>>%3log.txt
@echo itemType表備份已完成!>>%3log.txt
@bcp "SELECT * FROM sportSys.dbo.agenda wheresportSys.dbo.agenda.userId="+%1 queryout %2agenda.xls -T -c>>%3log.txt
@echo agenda表備份已完成!>>%3log.txt
@bcp "SELECT * FROM sportSys.dbo.allroundInfo wheresportSys.dbo.allroundInfo.userId="+%1 queryout %2allroundInfo.xls -T -c>>%3log.txt
@echo allroundInfo表備份已完成!>>%3log.txt
@bcp "SELECT * FROM sportSys.dbo.athlete wheresportSys.dbo.athlete.userId="+%1 queryout %2athlete.xls -T -c>>%3log.txt
@echo athlete表備份已完成!>>%3log.txt
@exit
下面,我們來分析下這個(gè)批處理
bcp "SELECT * FROM sportSys.dbo.competitions wheresportSys.dbo.competitions.userId="+%1 queryout %2competitions.xls -T -c>>%3log.txt
bcp 這個(gè)是語法
雙引號(hào)里面寫的是Sql語句
%1、%2、%3是要傳遞給bat文件的參數(shù)
%1表示第一個(gè)參數(shù),%2表示第二個(gè)參數(shù),%3表示第三個(gè)參數(shù)。
本人的這三個(gè)參數(shù)的意思分別是:
第一個(gè)參數(shù):查詢條件
第二個(gè)參數(shù):導(dǎo)出文件保存的位置
第三個(gè)參數(shù):輸出日志保存的位置
②Java程序中調(diào)用
導(dǎo)出文件publicString backUp()throwsException {
try{
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
Map session = ActionContext.getContext().getSession();
String userId = session.get("userId").toString();
String homeDir1 = request.getSession().getServletContext()
.getRealPath("/");
//Runtime.getRuntime().exec("notepad");
Runtime.getRuntime().exec(
"cmd /k start /b "+homeDir1+"backUp\\backupBy.bat"+" "+ userId +" "+
homeDir1+"download"+File.separatorChar + userId+File.separatorChar+" "+
homeDir1+"download"+File.separatorChar + userId+File.separatorChar);
}catch(IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
returnINPUT;
}
returnSUCCESS;
}
Java中調(diào)用命令行程序,的方式就是第11行Runtime.getRuntime().exec(
"cmd /k start /b "+homeDir1+"backUp\\backupBy.bat"+" "+ userId +" "+
homeDir1+"download"+File.separatorChar + userId+File.separatorChar+" "+
homeDir1+"download"+File.separatorChar + userId+File.separatorChar);
Runtime:
每個(gè) Java 應(yīng)用程序都有一個(gè)Runtime類實(shí)例,使應(yīng)用程序能夠與其運(yùn)行的環(huán)境相連接。可以通過getRuntime方法獲取當(dāng)前運(yùn)行時(shí)。
應(yīng)用程序不能創(chuàng)建自己的 Runtime 類實(shí)例。public Process exec(String command)
throws IOException在單獨(dú)的進(jìn)程中執(zhí)行指定的字符串命令。
這是一個(gè)很有用的方法。對(duì)于 exec(command) 形式的調(diào)用而言,其行為與調(diào)用 exec(command, null, null) 完全相同。
參數(shù):
command - 一條指定的系統(tǒng)命令。
返回:
一個(gè)新的 Process 對(duì)象,用于管理子進(jìn)程
拋出:
SecurityException - 如果安全管理器存在,并且其 checkExec 方法不允許創(chuàng)建子進(jìn)程
IOException - 如果發(fā)生 I/O 錯(cuò)誤
NullPointerException - 如果 command 為 null
IllegalArgumentException - 如果 command 為空
另請(qǐng)參見:
exec(String[], String[], File), ProcessBuilder
為了使調(diào)用bat文件來運(yùn)行的時(shí)候,不至于彈出一個(gè)黑框,
加入/b參數(shù) 即可解決!
③導(dǎo)入
bcp sportSys.dbo.competitions in %1competitions.xls -c -t
以上便是導(dǎo)入的指令! 同樣也可以設(shè)置將待導(dǎo)入的文件全部放在目錄中,然后導(dǎo)入即可!
④壓縮成Zip文件-工具類(網(wǎng)上有寫好的ZipUtil)
packagecom.yaxing.util;
importjava.io.BufferedInputStream;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.util.jar.JarEntry;
importjava.util.jar.JarOutputStream;
importjava.util.jar.Manifest;
publicclassZipUtil {
protectedstaticbyte[] buf =newbyte[1024];
/**
* 私有構(gòu)造函數(shù)防止被構(gòu)建
*/
privateZipUtil() {
}
/**
* 遍歷目錄并添加文件.
*
* @param jos
* ? ? ? ? ? ?- JAR 輸出流
* @param file
* ? ? ? ? ? ?- 目錄文件名
* @param pathName
* ? ? ? ? ? ?- ZIP中的目錄名
* @throws IOException
* @throws FileNotFoundException
*/
privatestaticvoidrecurseFiles(finalJarOutputStream jos,
finalFile file,finalString pathName)throwsIOException,
FileNotFoundException {
// 文件夾則往下遍歷
if(file.isDirectory()) {
finalString sPathName = pathName + file.getName() +"/";
jos.putNextEntry(newJarEntry(sPathName));
finalString[] fileNames = file.list();
if(fileNames !=null) {
for(inti =0; i < fileNames.length; i++) {
recurseFiles(jos,newFile(file, fileNames[i]), sPathName);
}
}
}
// 讀取文件到ZIP/JAR文件條目
else{
// 使用指定名稱創(chuàng)建新的 ZIP/JAR 條目
finalJarEntry jarEntry =newJarEntry(pathName + file.getName());
finalFileInputStream fin =newFileInputStream(file);
finalBufferedInputStream in =newBufferedInputStream(fin);
// 開始寫入新的 ZIP 文件條目并將流定位到條目數(shù)據(jù)的開始處。
jos.putNextEntry(jarEntry);
intlen;
while((len = in.read(buf)) >=0) {
// 將字節(jié)數(shù)組寫入當(dāng)前 ZIP 條目數(shù)據(jù)
jos.write(buf,0, len);
}
in.close();
// 關(guān)閉當(dāng)前 ZIP 條目并定位流以寫入下一個(gè)條目
jos.closeEntry();
}
}
/**
* 創(chuàng)建 ZIP/JAR 文件.
*
* @param directory
* ? ? ? ? ? ?- 要添加的目錄
* @param zipFile
* ? ? ? ? ? ?- 保存的 ZIP 文件名
* @param zipFolderName
* ? ? ? ? ? ?- ZIP 中的路徑名
* @param level
* ? ? ? ? ? ?- 壓縮級(jí)別(0~9)
* @throws IOException
* @throws FileNotFoundException
*/
publicstaticvoidmakeDirectoryToZip(finalFile directory,
finalFile zipFile,finalString zipFolderName,finalintlevel)
throwsIOException, FileNotFoundException {
FileOutputStream fos =null;
try{
// 輸出文件流
fos =newFileOutputStream(zipFile);
}catch(finalException e) {
// 建立打包后的空文件
newFile(zipFile.getParent()).mkdirs();
zipFile.createNewFile();
fos =newFileOutputStream(zipFile);
}
// 使用指定的 Manifest 創(chuàng)建新的 JarOutputStream。清單作為輸出流的第一個(gè)條目被寫入
finalJarOutputStream jos =newJarOutputStream(fos,newManifest());
jos.setLevel(checkZipLevel(level));
finalString[] fileNames = directory.list();
if(fileNames !=null) {
for(inti =0; i < fileNames.length; i++) {
// 對(duì)一級(jí)目錄下的所有文件或文件夾進(jìn)行處理
recurseFiles(jos,newFile(directory, fileNames[i]),
zipFolderName ==null?"": zipFolderName);
}
}
// 關(guān)閉 ZIP 輸出流和正在過濾的流。
jos.close();
}
/**
* 檢查并設(shè)置有效的壓縮級(jí)別,避免壓縮級(jí)別設(shè)置錯(cuò)的異常
*
* @param level
* ? ? ? ? ? ?- 壓縮級(jí)別
* @return 有效的壓縮級(jí)別或者默認(rèn)壓縮級(jí)別
*/
publicstaticintcheckZipLevel(finalintlevel) {
if(level <0|| level >9) {
return7;
}else{
returnlevel;
}
}
publicstaticvoidmain(finalString args[])throwsFileNotFoundException,
IOException {
// makeDirectoryToZip();
finalString homeDir = System.getProperty("user.dir");
System.out.println(homeDir);
finalFile zipFile =newFile(homeDir,"download"+ File.separatorChar
+"test.zip");
finalFile pagesDirectory =newFile(homeDir,"src");
System.out.println("Making zip file from folder /src to "+ zipFile);
ZipUtil.makeDirectoryToZip(pagesDirectory, zipFile,"",9);
System.out.println("Zip file "+ zipFile +" has been made.");
}
}
⑤Struts2執(zhí)行Action里面的方法
publicString execute()throwsException {
HttpServletRequest request = ServletActionContext.getRequest();
HttpServletResponse response = ServletActionContext.getResponse();
Map session = ActionContext.getContext().getSession();
String userId = session.get("userId").toString();
finalString homeDir = request.getSession().getServletContext()
.getRealPath("/");// 打包后文件的位置及名稱
finalFile zipFile =newFile(homeDir,"download"+ File.separatorChar
+ userId + File.separatorChar + userId +"bak.zip");// 要打包的文件夾路徑
// if((new File(userId).isDirectory())){
// System.out.println("文件夾"+userId+"已存在!創(chuàng)建失敗!");
// }else{
// new File(userId).mkdir();
// System.out.println("創(chuàng)建文件夾"+userId+"成功!");
// }
finalFile pagesDirectory =newFile(homeDir,"download/"+ userId);
LOG.info("Making zip file from folder /"+ userId +" to "+ zipFile);// 壓縮文件
ZipUtil.makeDirectoryToZip(pagesDirectory, zipFile,"",9);
LOG.info("Zip file "+ zipFile +" has been made.");
response.sendRedirect("../download/"+ userId +"/"+ userId
+"bak.zip");
returnnull;
// return super.execute();
}
壓縮文件創(chuàng)建之后,返回該壓縮包,提供用戶下載!用戶將下載的文件導(dǎo)入客戶端系統(tǒng)中,即可,
四、總結(jié)
本文總結(jié)了Java中調(diào)用批處理文件,給批處理文件傳遞參數(shù)的使用方法。依據(jù)此,可以實(shí)現(xiàn)項(xiàng)目中多種用途的數(shù)據(jù)備份。
歡迎各位交流,如有更好的方法,歡迎指出,謝謝!
總結(jié)
以上是生活随笔為你收集整理的java批量处理数据库语句_Java项目中调用bat批处理进行多用户数据库备份的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何申请博客 下面是申请博客的步骤
- 下一篇: 什么是合理化烟雾 合理化烟雾是啥