我从一个数据库表中提取数千行并插入另一个数据库表。我不想将所有记录加载到内存中,然后插入到其他数据库中。
因此,我尝试使用BlockingQueue使用一个线程加载提取器结果,并使用另一个线程同时插入另一个数据库。我使用Spring JdbcTemplate来访问我的数据库。
这是我的计划
public void performExtractionInsertion(JdbcTemplate inboundJdbcTemplate, JdbcTemplate outboundJdbcTemplate){
final BlockingQueue queue = new LinkedBlockingQueue<Transaction>(50);
ExecutorService executor = Executors.newFixedThreadPool(2);
final String SELECT_QUERY = "SELECT acc_number, date, type FROM transactions";
final String INSERT_QUERY = "INSERT INTO analysis(col1, col2, col3) VALUES(?,?,?)";
executor.execute(new Runnable() {
@Override
public void run() {
queue.put(/*IMPLEMENTATION OF EXTRACTOR USING inboundJdbcTemplate*/);
}
});
executor.execute(new Runnable() {
@Override
public void run() {
queue.take(/*IMPLEMENTATION OF INSERTER USING outboundJdbcTemplate*/)
}
});
}
有人可以告诉我如何实现EXTRACTOR和INSERTER,以便他们使用相同的BlockingQueue来限制内存中的行数吗?
这是正确的做法吗?我还可以使用jdbcTemplate吗? 最聪明,最方便的方法是什么?
谢谢你们
BTW,Transaction是要保存要插入的提取元素的对象的类。
答案 0 :(得分:1)
我有相同的情况(在稍微不同的设置中)。我不是为JdbcTemplate而是为了MappingSQLQuery。我认为,至少对于查询它更适合我的需求。鉴于您愿意改变,代码可能看起来像这样
MappingSQLQuery selector = ...;
executor.execute(new Runnable() {
public void run() {
List<WrapObject> list = selector.execute();
for (WrapObject object : list) {
while (!queue.offer(object)) {
Thread.sleep(100);
}
}
while (!queue.offer(WrapObject.NULL_OBJECT)) {
Thread.sleep(100);
}
}
});
executor.execute(new Runnable() {
public void run() {
WrapObject object;
while ((object = queue.take) != WrapObject.NULL_OBJECT) {
outboundJdbcTemplate.update(INSERT_QUERY, object.getParam1(),...)
}
}
});
给定一个合适的WrapObject定义,这应该可以解决问题。
在性能关键型数据库系统上工作很多我发现了以下两点。
通常,重新实现Spring映射器可以更好地控制数据库发生的事情(特别是批量更新,PreparedStatements的编译时,设置批量大小)
如果您看一下代码,您将了解到,与您相关的过度通用Spring-JDBC类的部分大多数是10-20行,并且可以轻松地为您的特定情况重新实现,同时加速显着提高您的申请
根据您的数据库,您可能希望使用多个读取器/写入器。我曾与Oracle-Clusters合作,其中八个并行读取进程甚至没有开始对硬件施加重大负担