生成json的任务中的许多查询

eri*_*old 1 coldfusion

所以我有一个任务要构建,它将把我们数据库中的大量数据存档到JSON中.

为了让您更好地了解正在发生的事情; X有100s的Ys,Y有100s的Zs,依此类推.我正在为每个X,Y和Z创建一个json文件.但是每个X json文件都有一个子数组,其中包含X的子Ys,同样Ys存储了一个子Zs数组.

它比许多情况下更复杂,但你应该从我认为的那个例子中了解所涉及的复杂性.

我正在使用ColdFusion,但它似乎是一个不好的选择,因为它因内存错误而崩溃.在我看来,如果它正在从运行任务时不再引用的内存中删除查询(即:垃圾收集),那么任务应该有足够的内存,但是根据ColdFusion根本没有进行任何垃圾收集,并且必须在请求完成后执行此操作.

因此,我正在寻找有关如何更好地完成我在CF中的任务的建议,或者寻求使用其他语言的建议.

谢谢.

Mar*_*ark 5

1)如果启用了调试,coldfusion将继续查询,直到页面完成.把它关掉!

2)您可能需要structDelete()查询变量以允许它被垃圾收集,否则它可能会持久存在,只要存在引用它的范围.例如., <cfset structDelete(variables,'myQuery') />

3)cfquery将整个ResultSet拉入内存.大多数时候这很好.但是对于大型结果集的报告,您不希望这样.一些JDBC驱动程序支持设置fetchSize,它以前向只读方式允许您一次获得一些结果.这样,您可以处理成千上万行,而不会淹没内存.我只用了不到100mb的堆就在~80秒内生成了一个1GB的csv文件.这需要退出Java.但它一石二鸟.它减少了JDBC驱动程序一次带入的数据量,并且由于您直接使用ResultSet,因此不会遇到提到的cfloop问题@orangepips.当然,它不适合那些没有Java排骨的人.

你可以这样做(你的构建路径中需要cfusion.jar):

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.sql.ResultSet;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;

import au.com.bytecode.opencsv.CSVWriter;
import coldfusion.server.ServiceFactory;

public class CSVExport {
    public static void export(String dsn,String query,String fileName) {
        Connection conn = null;
        Statement stmt = null;
        ResultSet rs = null;
        FileWriter fw = null;
        BufferedWriter bw = null;


        try {
            DataSource ds = ServiceFactory.getDataSourceService().getDatasource(dsn);
            conn = ds.getConnection();
            // we want a forward-only, read-only result.
            // you may want need to use a PreparedStatement instead.
            stmt = conn.createStatement(
                ResultSet.TYPE_FORWARD_ONLY,
                ResultSet.CONCUR_READ_ONLY
            );
            // we only want to go forward!
            stmt.setFetchDirect(ResultSet.FETCH_FORWARD);
            // how many records to pull back at a time.
            // the hard part is balancing memory usage, and round trips to the database.
            // basically sacrificing speed for a lower memory hit.
            stmt.setFetchSize(256);
            rs = stmt.executeQuery(query);
            // do something with the ResultSet, for example write to csv using opencsv
            // the key is to stream it. you don't want it stored in memory.
            // so excel spreadsheets and pdf files are out, but text formats like 
            // like csv, json, html, and some binary formats like MDB (via jackcess)
            // that support streaming are in.
            fw = new FileWriter(fileName);
            bw = new BufferedWriter(fw);
            CSVWriter writer = new CSVWriter(bw);
            writer.writeAll(rs,true);
        }
        catch (Exception e) {
            // handle your exception.
            // maybe try ServiceFactory.getLoggingService() if you want to do a cflog.
            e.printStackTrace();
        }
        finally() {
            try {rs.close()} catch (Exception e) {}
            try {stmt.close()} catch (Exception e) {}
            try {conn.close()} catch (Exception e) {}
            try {bw.close()} catch (Exception e) {}
            try {fw.close()} catch (Exception e) {}
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

弄清楚如何传递参数,记录,将其转换为后台进程(提示:扩展线程)等是不同的问题,但是如果你了解这个代码,那应该不会太困难.

4)也许看杰克逊生成你的json.它支持流式传输,并结合fetchSize和BufferedOutputStream,您应该能够保持内存使用率下降.