以有效的方式循环遍历结果集并将列值添加到列表<String>



我正在一个多线程项目中工作,其中每个线程将randomly find columns for that table,我将在我的SELECT sql query中使用这些列,然后我将执行SELECT sql查询。在执行该查询之后,我将遍历结果集,并将每个列的数据添加到List<String>中。

这里columnsList将包含由comma分隔的columns。例如,

col1, col2, col3

下面是我的代码。

class ReadTask implements Runnable {
public ReadTask() {
}

@Override
public run() {
  ...
  while ( < 60 minutes) {
    .....
    final int id = generateRandomId(random);
    final String columnsList = getColumns(table.getColumns());
    final String selectSql = "SELECT " + columnsList + "  from " + table.getTableName() + " where id = ?";
    resultSet = preparedStatement.executeQuery();
    List<String> colData = new ArrayList<String>(columnsList.split(",").length);
    boolean foundData = false;
    if (id >= startValidRange && id <= endValidRange) {
        if (resultSet.next()) {
            foundData = true;
            for (String column : columnsList.split(",")) {
                colData.add(resultSet.getString(column.trim()));
            }
            resultSet.next();//do I need this here?
        }
    } else if (resultSet.next()) {
        addException("Data Present for Non Valid ID's", Read.flagTerminate);
    }
    ....
      }
   }

    private static void addException(String cause, boolean flagTerminate) {
        AtomicInteger count = exceptionMap.get(cause);
        if (count == null) {
            count = new AtomicInteger();
            AtomicInteger curCount = exceptionMap.putIfAbsent(cause, count);
            if (curCount != null) {
                count = curCount;
            }
        }
        count.incrementAndGet();
        if(flagTerminate) {
            System.exit(1);
        }
    }
}

问题陈述:-

执行SELECT sql查询后。下面是我的两个场景——

  1. 我需要看看id是否在有效范围内。如果在Valid Range之间,则检查resultSet是否有任何数据。如果它有数据,那么使用columnsList中的columns循环resultSet,并开始将其添加到字符串的coldData列表中。
  2. 否则,如果id不在有效范围内,那么我需要检查我没有从resultSet获得任何数据。但不知何故,如果我得到的数据,并标志为真,停止程序,然后退出程序。否则,如果我正在获取数据,但标志为false以停止程序,则计算发生了多少次。因此,我创建了addException方法。

有没有人可以帮助我,我在这里为我上面两个scenarios做的方式是正确的还是不?看起来,我可以改进if/else loop代码更多,我想我的上述两个场景。

您可以做一些事情来让代码更快一点:

关于查询部分,如果表从未更改,您可以将columnsList初始化移到while循环之外,如果所有线程使用相同的查询,甚至可以将其设置为静态。同样,您将为每个查询结果重新计算该变量的拆分和修剪列列表。这可以在循环外一次性完成。

关于测试本身,确实可以反转嵌套。您当前正在执行的操作如下:

if (B) {
   if (A) ok;
}
else if (A) error;

可以更简单地写成:

if (A){
   if (B) ok;
   else error;
}

您的代码可以更好地表述如下:

if (resultSet.next()) {
    if (id >= startValidRange && id <= endValidRange) {
        foundData = true;
        for (String column : columnsList.split(",")) {
            colData.add(resultSet.getString(column.trim()));
        }
    }
    else
        addException("Data Present for Non Valid ID's", Read.flagTerminate);
} 

关于异常日志部分,您应该避免使用静态方法直接在映射中处理存储,这是一个非常强大的争用来源,并且会阻止线程专注于执行它们的实际工作,即启动和处理查询。通常,在O(log n)中访问map具有时间复杂度,并且查看您的代码,您将进行两次访问,并进行各种检查以确保会计正确。相比之下,在队列中推送值是一个常量时间操作,同步由队列本身处理。

所以,我的建议是把map的处理委托给一个专用的线程,并为你的查询线程添加一个同步队列来给它异常。这样就不需要处理对映射的并发访问(这可能会很混乱)。同样,从查询线程的角度来看,日志记录过程将是一个简单的"即发即忘"操作,日志记录线程只需要从队列中提取新消息并将它们添加到映射中。

如果您还不知道如何构建这样的设置,可以参考Oracle教程。关于这个主题(生产者-消费者)也有几个问题和答案。

更新:如果你甚至想减少争用,你可以为每个查询线程创建一个队列,并让map线程依次检查所有队列。并发访问的风险减少到同时有两个线程:一个查询线程和一个映射线程。它将在map线程中引入更多的工作,但同时将避免许多线程重新调度(每次线程被锁阻塞时都会发生这种情况)。重新调度发生得越少,花在线程管理上的时间就越少,有更多的时间可用于实际工作。

注意,无论如何,您都应该注意不要有太多的项堆积在队列中。如果这种情况很可能发生(我怀疑,但我不知道您的数据的细节是肯定的),您可能希望使用BlockingQueues(查找类描述,并进一步详细了解主题的SO问题)。

相关内容

  • 没有找到相关文章

最新更新