并发运行时,多个Java线程访问同一个DB记录

时间:2012-06-25 15:36:57

标签: java mysql multithreading

我在这里有一个相当简单的Java类,它创建了2个线程池......

  • 连接到正在运行的URL流并逐行读入条目,将每个条目提交到后端MySQL数据库。

  • 产生几个线程,每个线程将执行相同的过程(如下)

  

1.从上面获取最旧的DB条目

     

2.Parse并相应地处理

     

3.将几个部分保存到另一个数据库表

     

4.从运行表中删除此DB条目以表示分析已完成

     

5.End Thread

我需要2个池的原因是因为读取过程比分析快得多,如果我阅读&分析每个条目,因为它通过条目备份太快而传入的流中断。通过实现这种分离,读取可以在需要的时候尽快发生,并且分析可以尽可能快地进行,因为它可以知道要赶上的记录是安全的并且可以跟上。

我遇到的问题是每个并发线程都获得了相同的最旧记录。我需要知道最好的方法是确保单独的线程全部并发运行,但每个线程都访问唯一最旧的DB条目。

提前致谢。

EDIT =================================

感谢大家到目前为止的回复......

为了进一步扩展我在此尝试的当前设置,这个代码段可能会有用......

try
    {
        String strQuery1 = "SELECT lineID,line FROM lineProcessing ORDER BY lineID ASC LIMIT 1;";
        String strQuery2 = "DELETE from lineProcessing WHERE lineID = ?";

        DBConnector dbc = new DBConnector(driver,url,userName,passwd); 
        Connection con = dbc.getConnection();
        con.setAutoCommit(false);
        PreparedStatement pstmt = con.prepareStatement(strQuery1);
        rs = pstmt.executeQuery();

        //Now extract the line & Id from the returned result set
        while (rs.next()) {
            lineID = Integer.parseInt(rs.getString(1));
            line = rs.getString(2);
        } //end while 

        //Now delete that entry so that it cannot be analysed again...
        pstmt = con.prepareStatement(strQuery2);
        pstmt.setString(1, lineID.toString());
        int res=pstmt.executeUpdate();

        con.commit();
        con.setAutoCommit(true);
        con.close();
    }
    catch (SQLException e) {
        System.out.println(">>>EXCEPTION FOUND IN QUERY = " + strQuery1 + " __or__ " + strQuery2);
        e.printStackTrace();
    }

...因此,您可以看到基本上打开数据库连接,将其设置为“Autocommit = false”,执行QUERY1,执行QUERY2,提交两个事务,最后关闭连接。这应该是每个单独的线程都需要完成的。问题是我在分析线程池中运行的每个X线程都被生成并且所有这些代码同时执行(这是我期望的)但是不尊重对DB的单连接访问我认为我已经设置以上。然后他们都返回同一条线进行分析。当线程接下来循环进行迭代#2时,它们都会返回这个新的最后一行,以便在上一次删除之后进行分析。

请进一步提出建议 - 包括通过java强制执行事务SQL的一个很好的例子吗?

再次感谢大家。

2 个答案:

答案 0 :(得分:1)

首先,添加一个可为空的datetime列,表示该行已在某个时间“被拾取”。

然后在你的处理线程中:

  1. 开始交易
  2. 找到“获取”时间为空的最旧行
  3. 更新获取当前系统时间的时间
  4. 提交交易。
  5. 确保您的isolation level设置为至少READ UNCOMMITTED,并且没有两个线程应该获得相同的行。此外,如果处理线程死亡并放弃它的行,您可以通过定期查询“拾取”时间早于某个值的行来找到它,并通过将拾取时间设置为空来重新处理这些行。

    或者只是切换到事务性消息队列,它会自动为您完成大部分操作。

答案 1 :(得分:0)

另一个解决方案是让工作线程等待包含该行键的单例。写入行,将键放在对象中,然后通知。 “下一个”工作线程将获取密钥并对其进行操作。你需要确保一个工人在等待什么不是。