JBoss logo


print this page
email this page

JBossTS JTS supports the construction of both local and distributed transactional applications which access databases using the JDBC APIs. JDBC supports two-phase commit of transactions, and is similar to the XA X/Open standard. The JDBC support is found in the com.arjuna.ats.jdbc package.

Transactional Driver

The JBossTS JTS approach to incorporating JDBC connections within transactions is to provide transactional JDBC drivers through which all interactions occur. These drivers intercept all invocations and ensure that they are registered with, and driven by, appropriate transactions. There is a single type of transactional driver through which any JDBC driver can be driven; obviously if the database is not transactional then ACID properties cannot be guaranteed. This driver is com.arjuna.ats.jdbc.TransactionalDriver, which implements the java.sql.Driver interface.

The driver may be directly instantiated and used within an application. For example:

 TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver(); 

It can be registered with the JDBC driver manager (java.sql.DriverManager) by adding them to the Java system properties. The jdbc.drivers property contains a list of driver class names, separated by colons, that are loaded by the JDBC driver manager when it is initialised, for instance:

jdbc.drivers=foo.bar.Driver:mydata.sql.Driver:bar.test.myDriver

On running an application, it is the DriverManager's responsibility to load all the drivers found in the system property jdbc.drivers. For example, this is where the driver for the Oracle database may be defined. When opening a connection to a database it is the DriverManager' s role to choose the most appropriate driver from the previously loaded drivers.

A program can also explicitly load JDBC drivers at any time. For example, the my.sql.Driver is loaded with the following statement:

Class.forName("my.sql.Driver"); 

Calling Class.forName() will automatically register the driver with the JDBC driver manager. It is also possible to explicitly create an instance of the JDBC driver using the registerDriver method of the DriverManager. This is the case for instance for the TransactionalDriver that can be registered as follow:

TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver();
DriverManager.registerDriver(arjunaJDBC2Driver);

When you have loaded a driver, it is available for making a connection with a DBMS.

Making Connections

Once a driver is loaded and ready for a connection to be made, instances of a Connection class can be created using the getConnection method on the DriverManager, as follow:

Connection con = DriverManager.getConnection(url, username, password);

From its version 2.0, the JDBC API has introduced a new way to obtain instances of the Connection class. This is the case of the interfaces DataSource and XADataSource that creates transactional connections. When using a JDBC 2.0 driver, JBossTS will use the appropriate DataSource whenever a connection to the database is made. It will then obtain XAResources and register them with the transaction via the JTA interfaces. It is these XAResources which the transaction service will use when the transaction terminates in order to drive the database to either commit or rollback the changes made via the JDBC connection.

There are two ways in which the JBossTS JDBC 2.0 support can obtain XADataSources. These will be explained in the following sections. Note, for simplicity we shall assume that the JDBC 2.0 driver is instantiated directly by the application.

  1. Java Naming and Directory Interface (JNDI)

    To get the ArjunaJDBC2Driver class to use a JNDI registered XADataSource it is first necessary to create the XADataSource instance and store it in an appropriate JNDI implementation. Details of how to do this can be found in the JDBC 2.0 tutorial available at JavaSoft. An example is show below:

    XADataSource ds = MyXADataSource();
    Hashtable env = new Hashtable();
    String initialCtx = PropertyManager.
      getProperty("Context.INITIAL_CONTEXT_FACTORY");
    env.put(Context.INITIAL_CONTEXT_FACTORY, initialCtx);
    initialContext ctx = new InitialContext(env);
    ctx.bind("jdbc/foo", ds);

    Where the Context.INITIAL_CONTEXT_FACTORY property is the JNDI way of specifying the type of JNDI implementation to use.
    Then the application must pass an appropriate connection URL to the JDBC 2.0 driver:

    Properties dbProps = new Properties();
    dbProps.setProperty(TransactionalDriver.userName, "user");
    dbProps.setProperty(TransactionalDriver.password, "password");
    TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver();
    Connection connection = arjunaJDBC2Driver.
      connect("jdbc:arjuna:jdbc/foo", dbProps);

    The JNDI URL must be pre-pended with jdbc:arjuna: in order for the ArjunaJDBC2Driver to recognise that the DataSource must participate within transactions and be driven accordingly.

  2. Dynamic class instantiation

    Many JDBC implementations provide proprietary implementations of XADataSources that provide non-standard extensions to the specification. In order to allow the application to remain isolated from the actual JDBC 2.0 implementation it is using and yet continue to be able to use these extensions, JBossTS hides the details of these proprietary implementations using dynamic class instantiation. In addition, the use of JNDI is not required when using this mechanism because the actual implementation of the XADataSource will be directly instantiated, albeit in a manner which will not tie an application or driver to a specific implementation. JBossTS therefore has several classes which are for specific JDBC implementations, and these can be selected at runtime by the application setting the dynamicClass property appropriately:

Database Type Property Name
Cloudscape 3.6 com.arjuna.ats.internal.jdbc.drivers.cloudscape_3_6
Sequelink 5.1 com.arjuna.ats.internal.jdbc.drivers.sequelink_5_1
Oracle 8.1.6 com.arjuna.ats.internal.jdbc.drivers.oracle_8_1_6
SQL Server 2000 com.arjuna.ats.internal.jdbc.drivers.sqlserver_2_2

The application code must specify which dynamic class the TransactionalDriver should instantiate when setting up the connection:

    Properties dbProps = new Properties();
    dbProps.setProperty(TransactionalDriver.userName, "user");
    dbProps.setProperty(TransactionalDriver.password, "password");
    dbProps.setProperty(TransactionalDriver.dynamicClass,
        "com.arjuna.ats.internal.jdbc.drivers.sequelink_5_0");
    TransactionalDriver arjunaJDBC2Driver = new TransactionalDriver();
    Connection connection = arjunaJDBC2Driver.connect("jdbc:arjuna:
        sequelink://host:port;databaseName=foo",dbProperties);
    

Note on properties used by the com.arjuna.ats.jdbc.TransactionalDriver class

  • userName: the user name to use when attempting to connect to the database.
  • password: the password to use when attempting to connect to the database.
  • createDb: if set to true, the driver will attempt to create the database when it connects. This may not be supported by all JDBC 2.0 implementations.
  • dynamicClass: this specifies a class to instantiate to connect to the database, rather than using JNDI.

Using the Connection

Once the connection has been established (for example, using the java.sql.DriverManager.getConnection method), all operations on the connection will be monitored by JBossTS. Once created, the driver and any connection can be used in the same way as any other JDBC driver or connection.

JBossTS connections can be used within multiple different transactions simultaneously, i.e., different threads, with different notions of the current transaction, may use the same JDBC connection. JBossTS does connection pooling for each transaction within the JDBC connection. So, although multiple threads may use the same instance of the JDBC connection, internally this may be using a different connection instance per transaction. With the exception of close, all operations performed on the connection at the application level will only be performed on this transaction-specific connection.

JBossTS will automatically register the JDBC driver connection with the transaction via an appropriate resource . When the transaction terminates, this resource will be responsible for either committing or rolling back any changes made to the underlying database via appropriate calls on the JDBC driver.

Further reading

More details on the way to manage applications using the JDBC API can be found in the JBossTS Programming Guide.

Copyright 2002-2005 Arjuna Technologies. Copyright 2008 JBoss, a division of Red Hat. All Rights Reserved.