Bitronix Transaction Manager (BTM)

repository·master·Indexed 19 days ago

https://github.com/scalar-labs/btm

A Java-based implementation of the JTA 1.1 specification providing XA transaction management services. BTM includes features for transaction engine settings, disk journal recovery, and resource loading. It supports both JDBC3 and JDBC4 and can be configured via a properties file or direct manipulation of the Configuration singleton object.

Tokens
30K
Snippets
72
Records
113
Agent score
65%

What's inside Bitronix Transaction Manager

  1. Overview of Bitronix Transaction Manager (BTM)

    master

    Bitronix Transaction Manager (BTM) is a JTA 1.0.1B compliant implementation designed to provide a fully working XA transaction manager. It is optimized for simplicity and provides high-quality error reporting and logging to simplify debugging XA semantics.

    Key use cases include:

    • Integrating with the Spring framework using the JtaTransactionManager facade.
    • Mixing JDBC and JMS accesses within a single unified transaction.
    • Integrating with web containers like Tomcat or Jetty to provide raw JTA access for tools like Hibernate (for automatic session context management).

    BTM includes efficient built-in connection pools for both JDBC and JMS resources.

  2. What is Bitronix Transaction Manager (BTM)?

    master
    Bitronix Transaction Manager (BTM) is a complete implementation of the JTA 1.1 API. It functions as a fully working XA transaction manager designed to provide all services required by the JTA API while maintaining code simplicity to facilitate understanding of XA semantics. Its primary design goal is to make JTA a commodity by providing trivial configuration and high-quality error reporting and logging to simplify troubleshooting.
  3. What is the Resource Loader and when to use it

    master

    The Resource Loader is a facility that automates the configuration and management of resource pools (JDBC and JMS). When enabled, pools defined in a properties file are automatically created during the transaction manager's startup and closed during its shutdown.

    When to use it:

    • Instead of manually creating resource pools via the BTM API.
    • When BTM is embedded in a servlet container (like Tomcat) where the container's configuration files are difficult to extend.

    Note: The Resource Loader does not support Ant-like references (${...}) in its configuration files.

  4. Understand the Disk Journal and Recovery Engine

    master

    BTM uses a Disk Journal and a Recovery Engine to ensure transaction integrity:

    • Disk Journal: A write-ahead log (append-only journal) that uses a two-file rollover system (fragments). It records transaction states to allow the engine to report and recover transactions that reached the 'prepare' phase but failed before 'commit' or 'rollback' could complete. It includes optimizations like pre-allocated storage, journal compacting, and disk sync batching.
    • Recovery Engine: Responsible for cleaning up unfinished transactions. It uses the Disk Journal to identify transactions that need resolution and interacts with the resource (e.g., a database) to finalize them.
  5. Benefits of using JTA and BTM

    master

    Using JTA (and specifically Bitronix Transaction Manager) provides several architectural advantages:

    • Future-Proofing for 2PC: If you later need to coordinate between two different databases or between a database and a JMS provider, your transaction management code remains unchanged. The system will automatically transition to 2-Phase Commit (2PC).
    • 1PC Optimization: If you only use a single database, BTM uses a 'Last Resource Commit' optimization to avoid the performance overhead of full 2PC, even without an XADataSource.
    • Resource Protection (Timeouts): You can set transaction timeouts to ensure database connections are not held indefinitely. BTM allows for configurable default timeout values.
    • Transactional Safeguards: BTM can be configured to ensure that pooled connections can only be used while a transaction is actively running. This can be enabled via the allowLocalTransactions datasource property.
  6. Configure XA connection pooling requirements

    master

    BTM requires connection pools with specific knowledge of transaction states.

    Important Constraints:

    • You cannot use non-XA connection pools like C3P0 or Apache DBCP with the BTM transaction manager.
    • BTM provides an abstract XA connection pooling framework that supports JDBC and JMS layers.
    • The framework handles pooling and caching for:
      • JDBC/JMS connections
      • JDBC prepared statements
      • JMS sessions, producers, and consumers.
    • It also provides optimizations such as automatic enlisting/delisting, connection recycling, and Last Resource Commit.
  7. Requirements for JDBC XA transactions

    master

    To participate in global XA transactions via JDBC, the driver must implement the javax.sql.XADataSource interface. Additionally, the underlying database must support XA functionality.

    If your database or driver does not natively support XA, BTM provides a workaround called the Last Resource Commit optimization, which allows non-XA JDBC drivers to participate in a global transaction.

  8. Use Last Resource Commit (LRC) optimization for JMS

    master

    The Last Resource Commit (LRC) optimization (also known as Last Resource Gambit or Last Agent optimization) allows a single non-XA resource, such as a JMS server or a database, to participate in an XA transaction by carefully ordering the resource commit sequence.

    Critical Safety Warnings

    • Inconsistency Risk: There is a small chance of inconsistent results across participating resources if BTM crashes while a transaction is in-flight. This is a limitation of the LRC concept itself, not BTM.
    • Single Resource Limit: You can have at most one non-XA resource participating via LRC in a single transaction. Attempting to use a second emulating resource will cause BTM to throw an exception.
    • Safety Note: Using LRC is 100% safe if you are only running transactions against a single JMS server. It is not 100% safe in multi-resource scenarios.

    Implementation

    To enable LRC, you must use bitronix.tm.resource.jms.lrc.LrcXAConnectionFactory as the XAConnectionFactory implementation within your connection factory configuration.

    // Example of configuring an ActiveMQ datasource with LRC
    PoolingConnectionFactory myConnectionFactory = new PoolingConnectionFactory();
    myConnectionFactory.setClassName("bitronix.tm.resource.jms.lrc.LrcXAConnectionFactory");
    myConnectionFactory.setUniqueName("amq-lrc");
    myConnectionFactory.setMaxPoolSize(5);
    myConnectionFactory.getDriverProperties().setProperty("connectionFactoryClassName", "org.apache.activemq.ActiveMQConnectionFactory");
    myConnectionFactory.getDriverProperties().setProperty("properties.brokerUrl", "tcp://localhost:61616");
  9. Use Last Resource Commit (LRC) for non-XA JDBC resources

    master

    The Last Resource Commit (LRC) optimization (also known as Last Resource Gambit or Last Agent optimization) allows a single non-XA database to participate in an XA transaction by ordering the resource commit sequence.

    Critical Safety Warnings

    • Crash Risk: If BTM crashes while a transaction is in-flight, there is a small chance of inconsistent results across participating resources. This is a limitation of the LRC concept, not BTM.
    • Single Database Safety: If you are using LRC to run transactions against only a single database, the scenario is 100% safe.
    • Single Non-XA Limit: You can have at most one non-XA datasource emulating XA via LRC in a single transaction. Attempting to use a second emulating datasource will cause BTM to throw an exception.
  10. Retrieve connection factories created by the Resource Loader

    master

    If you use the Resource Loader, you can retrieve the created connection factories using one of these three methods:

    1. JNDI Binding (Preferred): Add bitronix.tm.resource.bind=true to your Resource Loader properties file. The connection factories will be bound to the default JNDI server using their uniqueName as the JNDI name.
    2. ResourceObjectFactory: In environments with read-only JNDI (like Tomcat), bind a bitronix.tm.resource.ResourceObjectFactory object. Pass a javax.naming.Reference containing a javax.naming.StringRefAddr where the addrType is the connection factory's uniqueName.
    3. ResourceRegistrar (Least Preferred): Call bitronix.tm.resource.ResourceRegistrar.get(String uniqueName). Note that this method ties your application code directly to BTM APIs.