3

I'm trying to wrap my head around the value underneath the Java Transactions API (JTA) and one of its implementations, Bitronix. But as I dig deeper and deeper into the documentation, I just can't help but think of the following, simple example:

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();
    }
}

Don't get too caught up in the actual code above. The idea is simple: a transactional file writer that creates a file and writes to it. It's rollback() method deletes the file, thus returning the file system to the same state it was in before the commit(Object).

Am I missing something here? Is this all the JTA offers? Or is there a whole different set of dimensionality/aspects to transactionality that isn't represented by my simple example above? I'm guessing the latter but have yet to see anything concrete in the JTA docs. If I am missing something, then what is it, and can someone show me concrete examples? I can see transactionality being a huge component of JDBC but would hopefully like to get an example of JTA in action with something other than databases.

IAmYourFaja
  • 55,468
  • 181
  • 466
  • 756
  • 2
    Have you thought of distributed transactions & `Transactional.getStatus()`, `begin()`, `setTransactionTimeout()`. Beside Databases, have you thought of JMS? JTA offers more that that simple interface. Also have you thought of the "current active transaction" and joining it? – V G Jul 01 '14 at 14:00
  • Thanks @AndreiI (+1) - can you please explain what a "current active transaction" is, and what it means to "join" it? – IAmYourFaja Jul 01 '14 at 14:41
  • On "current active transaction": sometimes you need a mechanism to decide whether you want or not to join a transaction. In JTA you have (as far as I know) a single current active transaction attached to the thread (which can be suspended), and in your code you can decide dynamically that your `EntityManager` (JPA specification) joins it, in order to commit the changes that you made in some other requests. – V G Jul 01 '14 at 15:01
  • I wonder how long it would have taken for this question to be closed as either too broad or opinion-based if not for protection from closing due to bounty. – Oleg Estekhin Jul 01 '14 at 15:15
  • @OlegEstekhin it will probably take 7 days (if ever) :) because questions with bounty cannot be closed. – V G Jul 01 '14 at 15:54
  • Thanks @OlegEstekhin - this question is 2 days old (60+ views) and has received no downvotes or closevotes. Seeing that the SO community is extremely active and responsive to bad questions, this tells me that the community at large is genuinely interested in hearing an answer to this one. As far as being too broad, I could argue that JTA framework is a pretty narrow topic. As far as being opinion-based, nothing about the existing answers is opinionated (at all). All answers are substantiated by facts that, I argue, will help provide guidance and direction to JTA newcomers down the road. – IAmYourFaja Jul 01 '14 at 18:26

2 Answers2

8

As every one else has mentioned, the primary benefit of JTA is not the single transaction case, but the orchestration of multiple transactions.

Your "Transactional File" is an excellent, conceptual, example when used in the proper context.

Consider a contrived use case.

You're uploading a picture that has associate meta data and you want to then alert the infrastructure that the file as arrived.

This "simple" task is fraught with reliability issues.

For example, this workflow:

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

That bit of code involves the file system and 2 different servers (DB and JMS).

If the saveUploadedFile succeeds, but the saveMetaData does not, you now have a orphaned file on the file system, a "file leak" so to speak. If the saveMetaData succeeds, but the queue does not, you have saved the file, but "nobody knows about it". The success of the transaction relies upon all 3 components successfully performing their tasks.

Now, throw in JTA (not real code):

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

Now it "all works", or "none of it works".

Normally folks jump through hoops to make this kind of thing work safely, since most systems do not have transaction managers. But with a transaction manager (i.e. JTA), you the TM manages all of the hoops for you, and you get to keep your code clean.

If you survey the industry you will find very few transaction managers. Originally they were proprietary programs used by "Enterprise" grade systems. TIBCO is a famous one, IBM has one, Microsoft has one. Tuxedo used to be popular.

But with Java, and JTA, and the ubiquitous Java EE (etc) servers "everyone" has a transaction manager. We in the Java world get this orchestration for "free". And it's handy to have.

Java EE made transaction managers ubiquitous, and transaction handling a background consideration. Java EE means "never having to write commit() again". (Obviously Spring offers similar facilities).

For most systems, it's not necessary. That's why most people don't know much about it, or simply don't miss it. Most systems populate a single database, or simply don't worry about the issues surrounding orchestration of multiple systems. The process can be lossy, they have built in their own clean up mechanisms, whatever.

But when you need it, it's very nice. Committing to multiple system simultaneously cleans up a lot of headaches.

Arjan Tijms
  • 37,782
  • 12
  • 108
  • 140
Will Hartung
  • 115,893
  • 19
  • 128
  • 203
1

The biggest feature of JTA is that you can compose several transactional stores in one application and run transactions that span across these independent stores.

For instance, you can have a DB, a distributed transactional key-value store and your simple FileWriter and have a transaction that performs operations on all of these and commit all the changes in all the stores at once.

Take a look at infinispan. That's a transactional data grid, it uses JTA and can be used in combination with other JTA transactional services.

Edit:

Basically JTA is connected to the X/Open XA standard and it provides means to interact with X/Open XA resources directly in Java code. You can use alredy existing data-stores which hold X/Open XA compliant resources, such as databases, distributed data-grids and so on. Or you can define your own resources by implementing javax.transaction.xa.XAResource. Then, when your User transaction uses these resources, the transaction manager will orchestrate everything for you, no matter where the resources are located, in which data-store.

The whole bussiness is managed by the transaction manager which is responsible for synchronizing independent data-stores. JTA doesn't come with a transaction manager. JTA is just an API. You could write your own if you wish to (javax.transaction.TransactionManager), but obviously that's a difficult task. Instead what you want is to use some already implemented JTA service/library which features a transaction manager. For instance, if you use infinispan in your application you can use its transaction manager to allow your transactions to interact with different data-stores as well. It's best to seek further information on how to accomplish this from the implementators of JTA interface.

You can find full JTA API documentation here, though it's pretty long. There are also some tutorials available that talk about how to use Java EE Transaction Manager and update multiple data-stores but it is pretty obscure and doesn't provide any code samples.

You can check out Infinispan's documentation and tutorials, though I can't see any example that would combine Infinispan with other data-store.

Edit 2:

To answer your question from the comment: your understanding is more or less correct, but I'll try to clarify it further.

It'll be easier to explain the architecture and answer your question with a picture. The below are taken from the JTA spec 1.1

This is the X/Open XA architecture:

X/Open XA achitecture

Each data-store (a database, message queue, SAP ERP system, etc) has its own resource manager. In case of a relational database, the JDBC driver is a resource adapter that represents the Resource Manager of the database in Java. Each resource has to be available through the XAResource interface (so that Transaction Manager can manage them even without knowing the implementation details of a specific data-store).

Your application communicates with both the Resource Managers (to get access to the specific resources) by the resource adapters, as well with the Transaction Manager (to start/finish a transaction) by the UserTransaction interface. Each Resource Manager needs to be initialized first and it has to be configured for global transactions (i.e. spanning across several data-stores).

So basically, yes, data-stores are independent logical units that group some resources. They also exhibit interface that allows to perform local transactions (confined to that specific data-store). This interface might be better-performing or might expose some additional functionality specific to that data-store which is not available through the JTA interface.

This is the architecture of JTA environment:

JTA architecture

The small half-circle represents the JTA interface. In your case you're mostly interested in the JTA UserTransaction interface. You could also use EJB (transactional beans) and the Application Server would manage transactions for you, but that's a different way to go.

From the transaction manager’s perspective, the actual implementation of the transaction services does not need to be exposed; only high-level interfaces need to be defined to allow transaction demarcation, resource enlistment, synchronization and recovery process to be driven from the users of the transaction services.

So the Transaction Manager can be understood as an interface which only represents the actual mechanism used to manage transactions such as JTS implementation, but thinking about it as a whole is not an error neither.

From what I understand, if you run for instance a JBoss application server, you're already equipped with a Transaction Manager with the underlying transaction service implementation.

ciamej
  • 6,918
  • 2
  • 29
  • 39
  • Thanks @ciamej (+1) - so a few followups regarding your distributed transaction example. (1) Can you explain what you mean by "**transactional store**" and maybe provide a few examples? (2) From your example, it seems that JTA is for coordinating commits to each of these transactional stores? Does it handle orchestration (calling the right transactional store at the right time, etc.? And (3) Can you provide a code example (even a GitHub gist or link to code that demonstrates this) that shoes an example of JTA committing changes to multiple stores at the same time? Thanks again! – IAmYourFaja Jul 01 '14 at 14:46
  • 1
    @IAmYourFaja Please see my edit. (1) by transactional store I mean any JTA compliant database (with a JDBC driver which implements X/Open XA interface part of JTA), data-grid, file server etc. (2) yes, its the responsibility of Transaction Manager (3) I haven't found yet a specific code sample. I guess that's because everybody just wants to show how to use their product standalone and only hint that's possible to combine it with other products as well, though they don't give concrete code examples. – ciamej Jul 01 '14 at 15:47
  • 1
    Also Hibernate exposes a JTA interface so you can use it as a data-store in your JTA transactions. – ciamej Jul 01 '14 at 15:49
  • 1
    According to [this](http://www.laliluna.de/jpa-hibernate-guide/ch13s02.html): "One option is to use the transaction management of your application server. Every JEE application server provides the Java Transaction API (JTA), for example Orion, Jonas, Bea Weblogic, Websphere, Jboss." So maybe, for instance, JBoss has some tutorial on how to orchestrate several data-stores. – ciamej Jul 01 '14 at 15:51
  • Thanks again @ciamej (+3 for all) - one last question **just** to make sure I have JTA terminology down correctly: "*Transaction stores*" are logical, JTA-compliant units requiring transactionality, and "*Transaction Managers*" are servers that oversee distributed transactions across multiple transaction stores. Is this assessment true or does it need correcting? Thanks again! – IAmYourFaja Jul 01 '14 at 18:31
  • 1
    @IAmYourFaja Please see the edit. Your understanding is nearly correct, though I wouldn't say that data-stores require transactionality, rather they offer it, and it can be composed. Also I think that a Transaction Manager does not have to be a separate server. – ciamej Jul 01 '14 at 21:39
  • Amazing, amazing answer @ciamej (+1)! So in the case of Tomcat, it seems I would need to use a standalone transaction manager like Atomikos or Bitronix (probably the latter). It looks like Bitronix downloads and deploys as an executable JAR. Would I put this on its own VM (like an app server or a DB) and connect to it remotely, or do arre you supposed to just include it on the runtime classpath of my app (a Tomcat WAR), like any other Java lib? – IAmYourFaja Jul 02 '14 at 01:12
  • @IAmYourFaja Simply include it in the classpath. Should run smoothly :) – ciamej Jul 02 '14 at 01:28