3

我正试图围绕Java Transactions API (JTA) 及其实现之一 Bitronix 下的价值但是随着我对文档的深入挖掘,我不禁想到了以下简单的示例:

public interface Transactional {
    public void commit(Object);
    public void rollback();
}

public class TransactionalFileWriter extends FileWriter implements Transactional {
    @Override
    public void commit(Object obj) {
        String str = (String)obj;

        // Write the String to a file.
        write(str);
    }

    @Override
    public void rollback() {
        // Obtain a handler to the File we are writing to, and delete the file.
        // This returns the file system to the state it was in before we created a file and started writing to it.
        File f = getFile();

        // This is just pseudo-code for the sake of this example.
        File.delete(f);
    }
}

// Some method in a class somewhere...
public void doSomething(File someFile) {
    TransactionalFileWriter txFileWriter = getTxFW(someFile);
    try {
        txFileWriter.commit("Create the file and write this message to it.");
    } catch(Throwable t) {
        txFileWriter.rollback();
    }
}

不要太沉迷于上面的实际代码。这个想法很简单:一个事务文件编写器,它创建一个文件并写入它。它的rollback()方法删除文件,从而将文件系统返回到commit(Object).

我在这里错过了什么吗?这就是 JTA 提供的全部内容吗?还是我上面的简单示例没有代表交易性的一组完全不同的维度/方面?我猜是后者,但尚未在 JTA 文档中看到任何具体内容。如果我遗漏了什么,那是什么,有人可以给我看具体的例子吗?我可以看到事务性是 JDBC 的一个重要组成部分,但希望获得一个 JTA 的示例,它与数据库以外的东西一起使用。

4

2 回答 2

8

正如其他人所提到的,JTA 的主要好处不是单个事务案例,而是多个事务的编排。

在适当的上下文中使用时,您的“事务文件”是一个出色的概念性示例。

考虑一个人为的用例。

您正在上传一张具有关联元数据的图片,然后您想提醒基础设施该文件已到达。

这个“简单”的任务充满了可靠性问题。

例如,此工作流程:

String pathName = saveUploadedFile(myFile);
saveMetaData(myFile.size(), myFile.type(), currentUser, pathName);
queueMessageToJMS(new FileArrivalEvent(user, pathName);

那段代码涉及文件系统和 2 个不同的服务器(DB 和 JMS)。

如果 saveUploadedFile 成功,但 saveMetaData 没有,那么您现在在文件系统上有一个孤立文件,可以说是“文件泄漏”。如果 saveMetaData 成功,但队列没有成功,则您已保存文件,但“没人知道”。交易的成功依赖于所有 3 个组件成功执行其任务。

现在,输入 JTA(不是真正的代码):

beginWork();
try {
    String pathName = saveUploadedFile(myFile);
    saveMetaData(myFile.size(), myFile.type(), currentUser, pathName);
    queueMessageToJMS(new FileArrivalEvent(user, pathName);
} catch(Exception e) {
    rollbackWork();
} finally {
    commitWork();
}

现在它“一切正常”,或者“都不起作用”。

通常情况下,人们会跳过箍以使这种事情安全地工作,因为大多数系统都没有事务管理器。但是使用事务管理器(即 JTA),您 TM 会为您管理所有的箍,并且您可以保持您的代码干净。

如果你调查这个行业,你会发现很少有交易经理。最初它们是“企业”级系统使用的专有程序。TIBCO是有名的,IBM有,微软有。燕尾服曾经很流行。

但是对于 Java、JTA 和无处不在的 Java EE(等)服务器,“每个人”都有一个事务管理器。我们在 Java 世界中“免费”获得了这种编排。拥有它很方便。

Java EE 使事务管理器无处不在,事务处理成为背景考虑。Java EE 意味着“永远不必再次编写 commit()”。(显然 Spring 提供了类似的设施)。

对于大多数系统,这不是必需的。这就是为什么大多数人对它知之甚少,或者根本不会错过它的原因。大多数系统填充单个数据库,或者根本不担心围绕多个系统编排的问题。这个过程可能是有损的,他们已经建立了自己的清理机制,无论如何。

但是当你需要它时,它非常好。同时提交多个系统可以解决很多问题。

于 2014-07-01T14:43:40.137 回答
1

JTA 的最大特点是您可以在一个应用程序中组合多个事务存储,并运行跨越这些独立存储的事务。

例如,您可以拥有一个数据库、一个分布式事务键值存储和您的简单 FileWriter,并拥有一个对所有这些执行操作并一次提交所有存储中的所有更改的事务。

看看infinispan。这是一个事务数据网格,它使用 JTA 并且可以与其他 JTA 事务服务结合使用。

编辑:

基本上,JTA 连接到X/Open XA标准,它提供了直接在 Java 代码中与 X/Open XA 资源交互的方法。您可以使用现有的保存 X/Open XA 兼容资源的数据存储,例如数据库、分布式数据网格等。或者您可以通过实现javax.transaction.xa.XAResource来定义自己的资源。然后,当您的用户事务使用这些资源时,事务管理器将为您编排一切,无论资源位于何处,在哪个数据存储中。

整个业务由负责同步独立数据存储的事务管理器管理。JTA 没有附带事务管理器。JTA 只是一个 API。如果您愿意(javax.transaction.TransactionManager),您可以自己编写,但显然这是一项艰巨的任务。相反,您想要的是使用一些已经实现的具有事务管理器的 JTA 服务/库。例如,如果您在应用程序中使用 infinispan,您可以使用其事务管理器来允许您的事务也与不同的数据存储进行交互。最好从 JTA 接口的实现者那里寻求有关如何完成此操作的更多信息。

您可以在此处找到完整的 JTA API 文档,尽管它很长。还有一些可用的教程讨论如何使用 Java EE 事务管理器和更新多个数据存储,但它非常晦涩且不提供任何代码示例。

您可以查看 Infinispan 的文档和教程,尽管我看不到任何将 Infinispan 与其他数据存储相结合的示例。

编辑2:

从评论中回答您的问题:您的理解或多或少是正确的,但我会尝试进一步澄清。

用图片来解释架构和回答你的问题会更容易。以下内容取自 JTA 规范 1.1

这是 X/Open XA 架构:

X/Open XA 架构

每个数据存储(数据库、消息队列、SAP ERP 系统等)都有自己的资源管理器。在关系数据库的情况下,JDBC 驱动程序是一个资源适配器,它在 Java 中代表数据库的资源管理器。每个资源都必须通过 XAResource 接口可用(以便事务管理器即使不知道特定数据存储的实现细节也可以管理它们)。

您的应用程序通过资源适配器与资源管理器(以访问特定资源)进行通信,并通过 UserTransaction 接口与事务管理器(以启动/完成事务)进行通信。每个资源管理器都需要首先初始化,并且必须针对全局事务进行配置(即跨越多个数据存储)。

所以基本上,是的,数据存储是对一些资源进行分组的独立逻辑单元。它们还展示了允许执行本地事务的接口(仅限于该特定数据存储)。此接口可能性能更好,或者可能会公开一些特定于该数据存储的附加功能,而这些功能无法通过 JTA 接口使用。

这是JTA环境的架构:

JTA 架构

小半圆代表 JTA 接口。在您的情况下,您最感兴趣的是 JTA UserTransaction 接口。您也可以使用 EJB(事务性 bean),而 Application Server 会为您管理事务,但这是另一种方式。

从事务管理器的角度来看,事务服务的实际实现不需要暴露;只需要定义高级接口以允许从事务服务的用户驱动事务划分、资源征用、同步和恢复过程。

所以事务管理器可以理解为一个接口,它只代表了用于管理事务的实际机制,例如 JTS 实现,但从整体上考虑也不是错误的。

据我了解,如果您运行例如 JBoss 应用程序服务器,那么您已经配备了具有底层事务服务实现的事务管理器。

于 2014-07-01T14:00:54.720 回答