【问题标题】:Store the same ID in both the tables in multithreaded code在多线程代码中的两个表中存储相同的 ID
【发布时间】:2013-02-10 22:30:30
【问题描述】:

我已经开始从事一个项目,其中我在不同的数据库中有两个具有不同架构的表。所以我将有两个不同的连接参数来连接到数据库。并且在连接到每个数据库后,我需要使用对应表中给出的sql插入这两个表中。

我应该根据命令行参数使用 JDBC 插入所有两个表或其中任何一个表。这意味着单个线程将插入 Table1 和 Table2 或其中任何一个。

命令行参数:- 这里10是线程数,100是任务数,table1和table2是表名。

10 100 table1 table2

下面是我的代码。在这段代码中会发生什么 - 假设如果我们只传递一个名为 table1 的表,那么它将使用用于 table1 的 SQL 插入到该表中。

我还需要在table1table2 中插入相同的id,并且id 被作为AtomicInteger 传递给构造函数Task。这意味着如果id is 1,那么这个1 id 应该在table1table2 中都存在。

 final AtomicInteger id = new AtomicInteger(1);

 ExecutorService service = Executors. newFixedThreadPool(noOfThreads);

 for (int i = 0; i < noOfTasks * noOfThreads; i++) {

      for (String arg : tableNames) {
          String url = (String) prop.get(arg + ".url");
          String user = (String) prop.get(arg + ".user");
          String password = (String) prop.get(arg + ".password");
          String driver = (String) prop.get(arg + ".driver");
          String suffix = (String) prop.get(arg + ".suffix");
          String sql = (String) prop.get(arg + ".sql");

          service.submit( new Task(id, url, user, password, driver, sql, suffix));
        }
    }

下面是实现Runnable接口的Task类

class Task implements Runnable {

    private final AtomicInteger id ;
    private final String url ;
    private final String username ;
    private final String password ;
    private final String sql ;
    private final String driver ;
    private final String suffix ;

    public Task(AtomicInteger id, String url, String user, String password, String driver, String sql, String suffix) {
        this.id = id;
        this.url = url;
        this.username = user;
        this.password = password;
        this.driver = driver;
        this.sql = sql;
        this.suffix = suffix;
    }

    @Override
    public void run() {

        try {

           dbConnection = getDBConnection(url , username , password , driver );
           callableStatement = dbConnection .prepareCall(sql);

           int userId = id .getAndIncrement();

           callableStatement.setString(1, String.valueOf(userId));

        //other callableStatement


        callableStatement.executeUpdate();
       }
    }

因此,如果我使用多个线程运行上述程序,例如线程数为10,任务数为1000id,如果我选择1

那么在两个表中相同的 id 不存在,这意味着 id 1 将仅在一个表中存在 table1table2。我能想到的唯一原因是-idAtomicInteger,所以每次它都会为每个线程获得一个新的id。有什么方法可以使用相同的 id 在每个表中插入?然后确保 id 为PrimaryKey,这样如果每个线程再次插入这些表中,它就会获得一个新的 id。

【问题讨论】:

  • 让你的计数器静态化,所以只有一个?当然,那么你必须同意谁负责增加它。
  • 感谢您的建议。所以你是说,我应该在 Task 类中将这个private final AtomicInteger id ; 设为静态,对吗?我尝试通过像这样private static AtomicInteger id ; 更改为静态,但结果是相同的并且它不起作用。 id 1 只在一张桌子上。
  • 就像我说的,你必须同意每次更新操作只有一个线程增加它。其他的只是引用增加的值。
  • 对我有意义。那么我怎样才能实现这个目标呢?任何示例都会让我更好地理解。谢谢

标签: java database multithreading concurrency atomic


【解决方案1】:

如果我理解正确,您应该将计数器定义为静态以避免重复 PrimaryKey

static AtomicInteger id;

然后像这样将增量代码移动到主循环(不要忘记删除Task类中的int userId = id .getAndIncrement();):

for (int i = 0; i < noOfTasks * noOfThreads; i++) {
  // add following line
  int userId = id.getAndIncrement();

  for (String arg : tableNames) {
      String url = (String) prop.get(arg + ".url");
      String user = (String) prop.get(arg + ".user");
      String password = (String) prop.get(arg + ".password");
      String driver = (String) prop.get(arg + ".driver");
      String suffix = (String) prop.get(arg + ".suffix");
      String sql = (String) prop.get(arg + ".sql");

      service.submit( new Task(id, url, user, password, driver, sql, suffix));
    }
}

此外,由于id 计数器保存在内存中,您可能需要将其持久化,否则在重新启动应用程序后它会重置为 0。

【讨论】:

    猜你喜欢
    • 2023-03-15
    • 2021-06-28
    • 1970-01-01
    • 2019-01-16
    • 2018-03-10
    • 1970-01-01
    • 2018-04-07
    • 2015-10-21
    • 1970-01-01
    相关资源
    最近更新 更多