OpenCSV + JMS/MDB 行为 + 性能问题

OpenCSV + JMS/MDB behavior + performance issue

我有一个 Web 应用程序,它在 Glassfish 4.1 下运行,其中包含一些需要 JMS/MDB 的功能. 特别是我在使用 JMS/MDB 生成报告时遇到问题,即从 table 获取数据并将它们转储到文件中。

这就是发生的事情,我有一条 JMS/MDB 消息 在 Oracle 数据库中执行几项任务并在 [=102= 中获得最终结果之后],我想从 table(通常是 30M+ 条记录)中获取一份 csv 报告。

因此,在 JMS/MDB 中,生成报告的过程如下:

public boolean handleReportContent() {

    Connection conn = null;

    try {
        System.out.println("Handling report content... " + new Date());
        conn = DriverManager.getConnection(data.getUrl(), data.getUsername(), data.getPassword());
        int reportLine = 1;
        String sql = "SELECT FIELD_NAME, VALUE_A, VALUE_B, DIFFERENCE FROM " + data.getDbTableName() + " WHERE SET_PK IN ( SELECT DISTINCT SET_PK FROM " + data.getDbTableName() + " WHERE IS_VALID=? )";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setBoolean(1, false);
        ResultSet rs = ps.executeQuery();

        List<ReportLine> lst = new ArrayList<>();
        int columns = data.getLstFormats().size();
        int size = 0;
        int linesDone = 0;

        while (rs.next()) {

            ReportLine rl = new ReportLine(reportLine, rs.getString("FIELD_NAME"), rs.getString("VALUE_A"), rs.getString("VALUE_B"), rs.getString("DIFFERENCE"));
            lst.add(rl);
            linesDone = columns * (reportLine - 1);
            size++;
            if ((size - linesDone) == columns) {
                reportLine++;

                if (lst.size() > 4000) {
                    appendReportContentNew(lst);
                    lst.clear();
                }
            }
        }

        if (lst.size() > 0) {
            appendReportContentNew(lst);
            lst.clear();
        }

        ps.close();
        conn.close();
        return true;
    } catch (Exception e) {
        System.out.println("exception handling report content new: " + e.toString());
        return false;
    }

这是可行的,我知道它速度慢且效率低下,很可能有更好的选择来执行相同的操作。 这个方法的作用是:

使用这种方法,在 20 分钟内,它写入了 800k 行(30Mb 文件)它通常达到 4Gb 或更多。如果可能的话,这是我想改进的。

所以我决定尝试 OpenCSV,我得到了以下方法:

public boolean handleReportContentv2() {

    Connection conn = null;

    try {
        FileWriter fw = new FileWriter(data.getJobFilenamePath(), true);
        System.out.println("Handling report content v2... " + new Date());
        conn = DriverManager.getConnection(data.getUrl(), data.getUsername(), data.getPassword());
        String sql = "SELECT NLINE, FIELD_NAME, VALUE_A, VALUE_B, DIFFERENCE FROM " + data.getDbTableName() + " WHERE SET_PK IN ( SELECT DISTINCT SET_PK FROM " + data.getDbTableName() + " WHERE IS_VALID=? )";
        PreparedStatement ps = conn.prepareStatement(sql);
        ps.setBoolean(1, false);
        ps.setFetchSize(500);
        ResultSet rs = ps.executeQuery();

        BufferedWriter out = new BufferedWriter(fw);
        CSVWriter writer = new CSVWriter(out, ',', CSVWriter.NO_QUOTE_CHARACTER);
        writer.writeAll(rs, false);

        fw.close();
        writer.close();
        rs.close();
        ps.close();
        conn.close();
        return true;
    } catch (Exception e) {
        System.out.println("exception handling report content v2: " + e.toString());
        return false;
    }
}

所以我从 ResultSet 收集所有数据,并转储到 CSVWriter。本次操作同样20分钟,只写了7k行.

但是同样的方法,如果我在JMS/MDB之外使用它,它有一个不可思议的区别,就在前4分钟它在文件中写入了 3M 行。 对于同样的 20 分钟,它生成了一个 500Mb+.

的文件

如果我想提高性能,显然使用 OpenCSV 是迄今为止最好的选择,我的问题是为什么它在 JMS/MDB 中的执行方式不同? 如果不可能,是否有任何可能的解决方案可以通过任何其他方式改进同一任务?

感谢您对此事的反馈和帮助,我正在尝试了解 behavior/performance 与 JMS/MDB 的 in/out 不同的原因。

**

编辑:

**

@MessageDriven(activationConfig = {
@ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
@ActivationConfigProperty(propertyName = "destinationLookup", propertyValue = "MessageQueue")})

public class JobProcessorBean implements MessageListener {

private static final int TYPE_A_ID = 0;
private static final int TYPE_B_ID = 1;

@Inject
JobDao jobsDao;

@Inject
private AsyncReport generator;

public JobProcessorBean() {
}

@Override
public void onMessage(Message message) {
    int jobId = -1;
    ObjectMessage msg = (ObjectMessage) message;
    try {
        boolean valid = true;
        JobWrapper jobw = (JobWrapper) msg.getObject();
        jobId = jobw.getJob().getJobId().intValue();

        switch (jobw.getJob().getJobTypeId().getJobTypeId().intValue()) {
            case TYPE_A_ID:
                jobsDao.updateJobStatus(jobId, 0);
                valid = processTask1(jobw);
                if(valid) {
                    jobsDao.updateJobFileName(jobId, generator.getData().getJobFilename());
                    System.out.println(":: :: JOBW FileName :: "+generator.getData().getJobFilename());
                    jobsDao.updateJobStatus(jobId, 0);
                }
                else {
                    System.out.println("error...");
                    jobsDao.updateJobStatus(jobId, 1);
                }
                **boolean validfile = handleReportContentv2();**
                if(!validfile) {
                    System.out.println("error file...");
                    jobsDao.updateJobStatus(jobId, 1);
                }
                break;
            case TYPE_B_ID:
                (...)
        }
        if(valid) {        
            jobsDao.updateJobStatus(jobw.getJob().getJobId().intValue(), 2); //updated to complete
        }
        System.out.println("***********---------Finished JOB " + jobId + "-----------****************");
        System.out.println();
        jobw = null;
    } catch (JMSException ex) {
        Logger.getLogger(JobProcessorBean.class.getName()).log(Level.SEVERE, null, ex);
        jobsDao.updateJobStatus(jobId, 1);
    } catch (Exception ex) {
        Logger.getLogger(JobProcessorBean.class.getName()).log(Level.SEVERE, null, ex);
        jobsDao.updateJobStatus(jobId, 1);
    } finally {
        msg = null;
    }
}

private boolean processTask1(JobWrapper jobw) throws Exception {

    boolean valid = true;
    jobsDao.updateJobStatus(jobw.getJob().getJobId().intValue(), 0);

    generator.setData(jobw.getData());
    valid = generator.deployGenerator();
    if(!valid) return false;
    jobsDao.updateJobParameters(jobw.getJob().getJobId().intValue(),new ReportContent());

    Logger.getLogger(JobProcessorBean.class.getName()).log(Level.INFO, null, "Job Finished");
    return true;
}

因此,如果在 generator.deployGenerator() 中执行相同的方法,handleReportContent() 会产生缓慢的结果。如果我等待该方法中的所有内容并在此 bean 中创建文件 JobProcessorBean 会更快。我只是想弄清楚 why/how 行为会像这样执行。

在 bean 上添加 @TransactionAttribute(NOT_SUPPORTED) 注释可能会解决问题(正如您的评论所指出的那样)。

为什么会这样?因为如果您不在消息驱动的 bean 上放置任何事务注释,则默认值变为 @TransactionAttribute(REQUIRED)(因此 bean 所做的一切都由事务管理器监督)。显然,这会减慢速度。