linminqin 2011-07-21
首先说一下这个大批量,是指有上千万的数据量。
例子:
有一张短信历史表,其数据有上千万条数据,要进行数据备份到文本文件,就是执行如下SQL然后将结果集写入到文件中!
selectt.msisdn,t.source,t.seq,t.area,t.send_date,t.msg,t.optcodefromhnsms.SMS_SEND_10086_HIS_102t
数据库:Oracle
下面主要列一下我写文件操作的不同实现方法,及运行结果:
第一种:-----------------------------------------------------------------------------
packagewap.ftp;
importjava.io.File;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.HashMap;
importjava.util.Map;
importwap.util.PublicUtil;
publicclassFileWriteTest{
privateConnectionconn_a=null;
privatePreparedStatementpstmt_a=null;
privateResultSetrs_a=null;
privateStringFilePath="";
privateFilefileName=null;
privateFileWriterwriter;
privatePrintWriterpw;
privateStringfileAllPath="";
Mapmap=newHashMap();
publicvoidinit(){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
map=PublicUtil.readConfigFile();
conn_a=DriverManager.getConnection((String)map.get("URL"),(String)map.get("USERNAME"),(String)map.get("PASSWORD"));
FilePath=PublicUtil.readServerPath();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*读取数据库表内容并生成文件把数据写到文件中
*/
publicvoidreadDataToFile(){
longtotalStart=System.currentTimeMillis();
init();
try{
Datedate=newDate();
SimpleDateFormatsdf=newSimpleDateFormat("yyyyMMdd");
//SimpleDateFormatsdf2=newSimpleDateFormat("yyyy/MM/ddHH:mm");
StringnowDateStr=sdf.format(date);
fileAllPath=FilePath+nowDateStr+".txt";
fileName=newFile(fileAllPath);
try{
writer=newFileWriter(fileAllPath);
pw=newPrintWriter(writer);
}catch(IOExceptione){
e.printStackTrace();
}
//createFile("");
//读配置文件--取SQL
Stringsql_a=(String)map.get("SQL");
System.out.println(sql_a);
pstmt_a=conn_a.prepareStatement(sql_a);
rs_a=pstmt_a.executeQuery();
intnum=0;//记录写文件写了多少行
while(rs_a.next()){
longstartTime=System.currentTimeMillis();
Stringsize=(String)map.get("SIZE");
Strings="";
for(inti=1;i<=Integer.parseInt(size);i++){
s+=rs_a.getString(i)+"|";
}
s=s.substring(0,s.length()-1);
createFile(s);
num++;
longendTime=System.currentTimeMillis();
System.out.println("写入文件第"+num+"行,耗时"+(endTime-startTime)+"毫秒.");
}
}catch(SQLExceptione){
e.printStackTrace();
}finally{
finish();//关闭输入流
closeDB();
}
longtotalEnd=System.currentTimeMillis();
System.out.println("-----总耗时:"+(totalEnd-totalStart)+"毫秒");
}
publicvoidcreateFile(Strings){
pw.println(s);
}
publicvoidfinish(){//关闭输入流,将文字从缓存写入文件
try{
writer.close();
}catch(IOExceptioniox){
System.err.println(iox);
}
}
publicvoidcloseDB(){//关闭数据库连接
if(rs_a!=null){
try{
rs_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}finally{
if(pstmt_a!=null){
try{
pstmt_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}finally{
if(conn_a!=null){
try{
conn_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}
}
}
}
}
}
}
}
主要是通过FileWriter+PrintWriter实现文件数据的写操作!
第二种-------------------------------------------------------------------------------------
packagewap.ftp;
importjava.io.BufferedOutputStream;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.HashMap;
importjava.util.Map;
importwap.util.PublicUtil;
publicclassBuffOutPutStreamTest{
privateConnectionconn_a=null;
privatePreparedStatementpstmt_a=null;
privateResultSetrs_a=null;
privateStringFilePath="";
privateFilefileName=null;
privateFileOutputStreamfos;
privateBufferedOutputStreambos;
privateStringfileAllPath="";
Mapmap=newHashMap();
publicvoidinit(){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
map=PublicUtil.readConfigFile();
conn_a=DriverManager.getConnection((String)map.get("URL"),(String)map.get("USERNAME"),(String)map.get("PASSWORD"));
FilePath=PublicUtil.readServerPath();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*读取数据库表内容并生成文件把数据写到文件中
*/
publicvoidreadDataToFile(){
longtotalStart=System.currentTimeMillis();
init();
try{
Datedate=newDate();
SimpleDateFormatsdf=newSimpleDateFormat("yyyyMMdd");
SimpleDateFormatsdf2=newSimpleDateFormat("yyyy/MM/ddHH:mm");
StringnowDateStr=sdf.format(date);
fileAllPath=FilePath+nowDateStr+".txt";
fileName=newFile(fileAllPath);
try{
fos=newFileOutputStream(fileName);
bos=newBufferedOutputStream(fos);
}catch(IOExceptione){
e.printStackTrace();
}
createFile("");
//读配置文件--取SQL
Stringsql_a=(String)map.get("SQL");
System.out.println(sql_a);
pstmt_a=conn_a.prepareStatement(sql_a);
rs_a=pstmt_a.executeQuery();
intnum=0;//记录写文件写了多少行
while(rs_a.next()){
longstartTime=System.currentTimeMillis();
Stringsize=(String)map.get("SIZE");
Strings="";
for(inti=1;i<=Integer.parseInt(size);i++){
s+=rs_a.getString(i)+"|";
}
s=s.substring(0,s.length()-1);
createFile(s);
num++;
longendTime=System.currentTimeMillis();
System.out.println("写入文件第"+num+"行,耗时"+(endTime-startTime)+"毫秒.");
if(num>=1000000){
break;
}
//-----------定量清缓存一次,如果数据量大(上百万),请开启这个机制
if(num%100000==0){
System.out.println("===============清缓存一次===========");
try{
bos.flush();
}catch(IOExceptione){
e.printStackTrace();
}
}
//-----------清缓存机制end--------------------------------------
}
}catch(SQLExceptione){
e.printStackTrace();
}finally{
finish();//关闭输入流
closeDB();
}
longtotalEnd=System.currentTimeMillis();
System.out.println("----总耗时:"+(totalEnd-totalStart)+"毫秒");
}
publicvoidcreateFile(Strings){
try{
bos.write(s.getBytes());
}catch(IOExceptione){
e.printStackTrace();
}
}
publicvoidfinish(){//关闭输入流,将文字从缓存写入文件
try{
bos.flush();
bos.close();
fos.close();
}catch(IOExceptioniox){
System.err.println(iox);
}
}
publicvoidcloseDB(){//关闭数据库连接
if(rs_a!=null){
try{
rs_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}finally{
if(pstmt_a!=null){
try{
pstmt_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}finally{
if(conn_a!=null){
try{
conn_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}
}
}
}
}
}
}
}
主要用BufferedOutputStream的缓冲机制
第三种:-----------------------------------------------------------------------------
packagewap.ftp;
importjava.io.BufferedWriter;
importjava.io.File;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.io.PrintWriter;
importjava.sql.Connection;
importjava.sql.DriverManager;
importjava.sql.PreparedStatement;
importjava.sql.ResultSet;
importjava.sql.SQLException;
importjava.text.SimpleDateFormat;
importjava.util.Date;
importjava.util.HashMap;
importjava.util.Map;
importwap.util.PublicUtil;
publicclassFileWriteBufferTest{
privateConnectionconn_a=null;
privatePreparedStatementpstmt_a=null;
privateResultSetrs_a=null;
privateStringFilePath="";
privateFilefileName=null;
privateFileWriterwriter;
privatePrintWriterpw;
privateStringfileAllPath="";
Mapmap=newHashMap();
publicvoidinit(){
try{
Class.forName("oracle.jdbc.driver.OracleDriver");
map=PublicUtil.readConfigFile();
conn_a=DriverManager.getConnection((String)map.get("URL"),(String)map.get("USERNAME"),(String)map.get("PASSWORD"));
FilePath=PublicUtil.readServerPath();
}catch(Exceptione){
e.printStackTrace();
}
}
/**
*读取数据库表内容并生成文件把数据写到文件中
*/
publicvoidreadDataToFile(){
longtotalStart=System.currentTimeMillis();
init();
try{
Datedate=newDate();
SimpleDateFormatsdf=newSimpleDateFormat("yyyyMMdd");
SimpleDateFormatsdf2=newSimpleDateFormat("yyyy/MM/ddHH:mm");
StringnowDateStr=sdf.format(date);
fileAllPath=FilePath+nowDateStr+".txt";
fileName=newFile(fileAllPath);
try{
writer=newFileWriter(fileAllPath);
pw=newPrintWriter(newBufferedWriter(writer));
}catch(IOExceptione){
e.printStackTrace();
}
createFile("");
//读配置文件--取SQL
Stringsql_a=(String)map.get("SQL");
System.out.println(sql_a);
pstmt_a=conn_a.prepareStatement(sql_a);
rs_a=pstmt_a.executeQuery();
intnum=0;//记录写文件写了多少行
while(rs_a.next()){
longstartTime=System.currentTimeMillis();
Stringsize=(String)map.get("SIZE");
Strings="";
for(inti=1;i<=Integer.parseInt(size);i++){
s+=rs_a.getString(i)+"|";
}
s=s.substring(0,s.length()-1);
createFile(s);
num++;
longendTime=System.currentTimeMillis();
System.out.println("写入文件第"+num+"行,耗时"+(endTime-startTime)+"毫秒.");
if(num>=1000000){
break;
}
//-----------定量清缓存一次,如果数据量大(上百万),请开启这个机制
/*if(num%300000==0){
try{
pw.flush();
}catch(Exceptione){
e.printStackTrace();
}
}*/
//-----------清缓存机制end--------------------------------------
}
}catch(SQLExceptione){
e.printStackTrace();
}finally{
finish();//关闭输入流
closeDB();
}
longtotalEnd=System.currentTimeMillis();
System.out.println("----总耗时:"+(totalEnd-totalStart)+"毫秒");
}
publicvoidcreateFile(Strings){
pw.println(s);
}
publicvoidfinish(){//关闭输入流,将文字从缓存写入文件
try{
pw.flush();
writer.close();
}catch(IOExceptioniox){
System.err.println(iox);
}
}
publicvoidcloseDB(){//关闭数据库连接
if(rs_a!=null){
try{
rs_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}finally{
if(pstmt_a!=null){
try{
pstmt_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}finally{
if(conn_a!=null){
try{
conn_a.close();
}catch(SQLExceptione){
e.printStackTrace();
}
}
}
}
}
}
}
}
主要用的是FileWriter(加缓冲)的机制。
------------------------------------------------------------------------------
在写不同量的数据的情况下运行结果:
/*当只写数据为100000条时(取三次结果):
*fileWriter:总耗时:30500、26250、25078毫秒
*fileWriter(加缓冲):总耗时:23781、20875、20688毫秒
*OutputStreamBuffer:总耗时:21157、23094、22484毫秒
*
*当只写数据为1000000条时(取三次结果):
*fileWriter:总耗时:213844、218250、216985毫秒
*fileWriter(加缓冲):总耗时:249672、238094、207203毫秒
*OutputStreamBuffer:总耗时:239563、234234、229829毫秒
*发现当写数据量为10万时,加缓冲机制的写数据效率更高些!当写数据量达到100万时
*加缓冲机制的写数据效率反倒低了,我想因为是数据放入缓存>再从缓存写入文件当数据
*量大时,这个额外的开销就会加大,反而对整体写数据影响会大。
*那我就在想如果定量的清缓存,是不是会效率高些呢?
*-----------------------------------------------------------------
*当只写数据为1000000条时(取三次结果)
*启动定时将缓存中的数据写入文件:(每20万就清缓存一次)
*fileWriter(加缓冲):总耗时:232875毫秒
*OutputStreamBuffer:总耗时:229172、216594、234421毫秒
*
*当只写数据为1000000条时(取三次结果)
*启动定时将缓存中的数据写入文件:(每10万就清缓存一次)
*fileWriter(加缓冲):总耗时:毫秒
*OutputStreamBuffer:总耗时:227156、224047、210891毫秒
*
*当只写数据为1000000条时(取三次结果)
*启动定时将缓存中的数据写入文件:(每30万就清缓存一次)
*fileWriter(加缓冲):总耗时:248735、213172毫秒
*OutputStreamBuffer:总耗时:224703、235828、220765毫秒
*
*---------------------------------------------------------------
*总的来说,100万数据时,需要约3.5分钟1000万需要40分钟,如果表没有索引,
*会需要更长时间
*而且,如果要写的数据小于百万时,调缓冲的会好些!
*如果数据量上百万,若要调缓冲,请开启定量清缓冲机制
*@paramargs
*/
总结,当然我这个测试只是去验证三种写文件方式的机制的在不同数据量时的效率问题!
如果想更快的去完成上千万数量的写操作,最好是启多个线程去操作,这样可以解决时间问题
但要注意数据库连接的释放,要不对数据库是有影响的,特别是我拿的生产数据库测试的。
打完收工。