(文章本人原创,若转载请注明出处)
下面看一下一些具体的实现,先看一下Sender接口的commitData方法的MySql实现,即SenderMySqlImp类:
public void commitData(String path, String file) {
......
Connection connect = null;
try {
//根据配置由Helper来确定是否用连接池,这只调用getConnection()即可
connect = Helper.getConnection();
connect.setAutoCommit(false);
FileInputStream fis = new FileInputStream(path + file);
//insert语句,有三个参数分别为id,image,filename字段。
ps = connect.prepareStatement(sql.toString());
ps.setString(1, UUID.randomUUID().toString());
//将图片文件流化,用jdbc直接写到数据库
ps.setBinaryStream(2, fis, fis.available());
ps.setString(3, file);
ps.executeUpdate();
connect.commit();
count++;
Logger.writeLog("已处理文件数:"+count+",时间:"+new java.util.Date());
} catch (Exception e) {
........
}
很简单吧,其实就是用Stream来做,另外在网上可以找到有关Oracle上传blob的实现,一般都是先insert一条记录,blob字段用empty_blob()函数插入一个空数据,然后再取出这个blob字段,最后按字节写入blob,具体参考SenderOracleImp类吧。个人感觉还是在mysql的这个效率高些并且看起来简单了很多。
然后来看看使用线程池的ProcessMulti类:
public class ProcessMulti implements Process{
private String path;
private Vector<String> files = new Vector<String>();
private Properties prop;
ProcessMulti() {
prop = ConfigMgr.getProperties(); //取config.properties中配置信息
this.path = prop.getProperty("path");
this.files = Helper.getFiles(prop.getProperty("filetype"), this.path);
}
public void doProcess() {
//正如前面两篇所说,这里是线程池构建器,传入相关参数
BlobSenderThreadPool tpe = new BlobSenderThreadPool(Integer
.valueOf(prop.getProperty("corePoolSize")), Integer
.valueOf(prop.getProperty("maxPoolSize")), Integer.valueOf(prop
.getProperty("keepAliveTime")), TimeUnit.SECONDS,
new ArrayBlockingQueue<Runnable>(Integer.valueOf(prop
.getProperty("maxPoolSize"))),
new BlobSenderThreadPool.DiscardPolicy(), files.size());
Logger.writeLogForce("开始处理." + new java.util.Date());
for (int i = 0; i < this.files.size(); i++) {
//向线程池提交要处理的任务,线程池根据其配置进行处理
//Helper.getSender()会根据配置取得支持mysql或是oracel的写入方法
tpe.execute(new Runner(path, files.get(i), Helper.getSender()));
Logger.writeLog("已提交第" + (int)(i+1) + "个文件" + ",时间为:"
+ new java.util.Date());
}
//可以在这里写一个打印输出,实际上程序很快就执行完上面的for,运行到这里,但是处理并没有完成,
//主程序好像职业经理人,他的工作就是分配任务给下属,自已就完成工作了,但下属们还要接着忙活呵呵...
System.out.println("任务已分配...");
}
//线程池类
class BlobSenderThreadPool extends ThreadPoolExecutor {
volatile int planTask;//计划任务,即计划要写的文件数
public BlobSenderThreadPool(int corePoolSize, int maximumPoolSize,
long keepAliveTime, TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler, int planTask) {
super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
this.planTask = planTask;
}
@Override
//当某个线程处理完时会调用此方法
protected void afterExecute(Runnable r, Throwable t) {
Logger.writeLog("当前已完成任务数:" + (int)(this.getCompletedTaskCount()+1)
+ "计划任务数:" + planTask);
//若已处理完任务和计划的任务数相同说明所有线程已完成处理,终止线程池处理
if ((this.getCompletedTaskCount()+1)== planTask)
this.terminated();
super.afterExecute(r, t);
}
@Override
protected void terminated() {
Logger.writeLogForce("所有任务已完成 ,处理结束时间===>>" + new java.util.Date());
System.exit(0);
}
}
//要使用线程进行处理,类要实现Runable接口
class Runner implements Runnable {
String file;
String path;
Sender sender;
Runner(String path, String file, Sender sender) {
this.file = file;
this.path = path;
this.sender = sender;
}
//Runer的实例会被传入线程池,线程被运行时会调用run方法
public void run() {
sender.commitData(path, file);
}
}
posted @
2009-03-21 10:40 依然Fantasy 阅读(616) |
评论 (0) |
编辑 收藏
(文章本人原创,若转载请注明出处)
在实际当中的情况是系统数据库中需要上传大量照片到数据库中,数据量比较大,且不能在界面中通过操作逐个上传,要批量自动进行。其实起来也比较简单直接利用线程池将照片数据读取成流再存入BLOB字段即可。但是在实现后些功能后又进入了一些改造,实现了线程池、单线程、是否使用用连接池、不同数据库等不同的配置,这样在不同配置下可以观察到程序性能的不同。并且经过设计切换这些配置不需要修改程序。
使用DbAccess接口的getConnect()取得数据库连接,DbImp和DbPoolingImp实现了不使用连接池和使用连接池的两个版本。Sender接口的commitData()用来把BLOB数据写到数据库中,因为不同数据库可能写法有点不同所以这里SenderMySqlImp和SenderOracleImp分别是Mysql和Oracle的实现。Process接口的doProcess()是开始进行处理的方法,无论是单线程还是多线程。因此ProcessMulti和ProcessSingle是分别使用线程池以及单线程处理的类。ConfigMgr用于取得config.properties文件内配置信息,Logger是日志类,Helper中汇集了一些共用的静态方法。最后DataSender是主程序的类:)
posted @
2009-03-21 10:25 依然Fantasy 阅读(297) |
评论 (0) |
编辑 收藏