使用多个连接的单个事务。 (MYSQL / JDBC)

时间:2011-11-29 08:53:29

标签: java mysql jdbc transactions infobright

我正在处理的应用程序是一个基于Java的ETL过程,它将数据加载到多个表中。 DBMS是Infobright(基于MYSQL的DBMS,适用于数据仓库)。

数据加载应以原子方式完成;但是,出于性能原因,我想同时将数据加载到多个表中(使用LOAD DATA INFILE命令)。这意味着我需要打开多个连接。

是否有任何解决方案允许我原子地并行地进行负载? (我猜测答案可能取决于我加载的表格的引擎;大多数是Brighthouse,它允许事务,但没有XA,也没有保存点。)

为了进一步澄清,我想避免让我们说:

的情况
  • 我将数据加载到5个表中
  • 我提交前4个表的负载
  • 第5个表的提交失败

在这种情况下,我无法回滚前4个加载,因为它们已经被提交了。

2 个答案:

答案 0 :(得分:5)

简介

正如我所承诺的,我已经破解了一个完整的例子。我使用MySQL并创建了三个表,如下所示:

CREATE TABLE `test{1,2,3}` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `data` varchar(255) NOT NULL UNIQUE,
  PRIMARY KEY (`id`)
);

test2最初包含一行。

INSERT INTO `test2` (`data`) VALUES ('a');

I've posted the full code to http://pastebin.com。)

以下示例执行了几项操作。

  1. threads设置为3,以确定将并行运行的作业数。
  2. 创建threads个连接数。
  3. 为每个表分发一些示例数据(默认情况下,每个表的数据为a
  4. 创建要运行的threads个作业,并使用数据加载它们。
  5. threads个帖子中运行作业并等待其完成(成功与否)。
  6. 如果没有发生异常,则提交每个连接;否则它会回滚每一个。
  7. 关闭连接(但这些连接可以重复使用)。
  8. (注意,我在SQLTask.call()中使用了Java 7的自动资源管理功能。)

    逻辑

    public static void main(String[] args) throws SQLException, InterruptedException {
      int threads = 3;
      List<Connection> connections = getConnections(threads);
      Map<String, String> tableData = getTableData(threads);
      List<SQLTask> tasks = getTasks(threads, connections);
      setData(tableData, tasks);
      try {
        runTasks(tasks);
        commitConnections(connections);
      } catch (ExecutionException ex) {
        rollbackConnections(connections);
      } finally {
        closeConnections(connections);
      }
    }
    

    数据

    private static Map<String, String> getTableData(int threads) {
      Map<String, String> tableData = new HashMap<>();
      for (int i = 1; i <= threads; i++)
        tableData.put("test" + i, "a");
      return tableData;
    }
    

    任务

    private static final class SQLTask implements Callable<Void> {
    
      private final Connection connection;
    
      private String data;
      private String table;
    
      public SQLTask(Connection connection) {
        this.connection = connection;
      }
    
      public void setTable(String table) {
        this.table = table;
      }
    
      public void setData(String data) {
        this.data = data;
      }
    
      @Override
      public Void call() throws SQLException {
        try (Statement statement = connection.createStatement()) {
          statement.executeUpdate(String.format(
            "INSERT INTO `%s` (data) VALUES  ('%s');", table, data));
        }
        return null;
      }
    }
    
    private static List<SQLTask> getTasks(int threads, List<Connection> connections) {
      List<SQLTask> tasks = new ArrayList<>();
      for (int i = 0; i < threads; i++)
        tasks.add(new SQLTask(connections.get(i)));
      return tasks;
    }
    
    private static void setData(Map<String, String> tableData, List<SQLTask> tasks) {
      Iterator<Entry<String, String>> i = tableData.entrySet().iterator();
      Iterator<SQLTask> j = tasks.iterator();
      while (i.hasNext()) {
        Entry<String, String> entry = i.next();
        SQLTask task = j.next();
        task.setTable(entry.getKey());
        task.setData(entry.getValue());
      }
    }
    

    运行

    private static void runTasks(List<SQLTask> tasks) 
        throws ExecutionException, InterruptedException {
      ExecutorService executorService = Executors.newFixedThreadPool(tasks.size());
      List<Future<Void>> futures = executorService.invokeAll(tasks);
      executorService.shutdown();
      for (Future<Void> future : futures)
        future.get();
    }
    

    结果

    鉴于getTableData(...)

    返回的默认数据
    test1 -> `a`
    test2 -> `a`
    test3 -> `a`
    

    以及test2已包含a(且data唯一)的事实,第二个作业将失败并抛出异常,因此每个连接将被回滚。

    如果您返回a而不是b,则会安全地提交连接。

    这可以与LOAD DATA类似地完成。


    OP对我的回答做出回应后,我意识到她/他想做的事情不可能以简单明了的方式做到。

    基本上问题是成功提交后,无法回滚已提交的数据,因为操作是原子操作。鉴于在给定的情况下需要多次提交,除非一个跟踪所有数据(在所有事务中)并且如果发生某些事情,则删除所有已成功提交的内容,否则无法回滚所有内容。

    有一个nice answer与提交和回滚问题有关。

答案 1 :(得分:0)

实际上在较新版本的IEE中,而不是ICE,还有一个名为DLP(分布式加载处理)的附加功能。网站上有一个PDF文件,从这里链接:

http://www.infobright.com/Products/Features/