In regards to the its structure in the previous trails, the banking application
described here has been slightly simplified. In this version creating local
JTA transactions, accounts managed by a bank object are in fact instances or
tuples within a SQL relational table named "accounts". When the Bank
object is requested for instance to create an account or to get information
on an account, the Bank object performs SQL statement such SQL INSERT or SQL
SELECT.
Deploy the application
Executing the demonstration consists to launch the folowing program
java com.arjuna.demo.jta.jdbcbank.BankClient -host <hostName>
-port portNumber -username <userName> -dbName <DBName>
-password <password> -clean|-create
Where:
- hostName - the name of the machine where is located the database
- userName - the user name used to access the database
- password - the password used to access to database
- DBName - the database name
- clean - the existing relational table will be deleted then created
- create - a new relational table will be created
Note Due to an issue with Oracle, it is possible that an XA exception is thrown when attempting to perform this test (see Release Notes).
If an xa error is returned you can use the following property property com.arjuna.ats.jdbc.isolationLevel set to TRANSACTION_READ_COMMITTED.
This property can be added in previous command as follow:
java -Dcom.arjuna.ats.jdbc.isolationLevel=TRANSACTION_READ_COMMITTED
com.arjuna.demo.jta.jdbcbank.BankClient -host <hostName>
-port portNumber -userName <userName>
-password <password> -clean|-create
How JDBC is used
The following Banking application illustrates some methods that use the JDBC API. In this application, the way
to create a jdbc connection is made via an XADataSource obtained with JNDI operations, es explained in the previous
trail jdbc introduction
The BankClient class instantiates an XADataSource and bind it to a jndi naming in order to be retrieved to create
transactional connections.
This portion of code illustrates how this made against oracle (tested on version 9i). A similar code could tested
against an other database by providng the appropriate XADataSource implementation. Details of the BankClient class
can be found in the file BankClient.java
package com.arjuna.demo.jta.jdbcbank;
import javax.naming.*;
import java.util.Hashtable;
import oracle.jdbc.xa.client.OracleXADataSource;
import com.arjuna.ats.jdbc.common.jdbcPropertyManager;
public class BankClient
{
.....
public static void main(String[] args)
{
//Provide the apporopriate information to access the database
for (int i = 0; i < args.length; i++)
{
if (args[i].compareTo("-host") == 0)
host = args[i + 1]
if (args[i].compareTo("-port") == 0)
port = args[i + 1];
if (args[i].compareTo("-username") == 0)
user = args[i + 1];
if (args[i].compareTo("-password") == 0)
password = args[i + 1];
if (args[i].compareTo("-dbName") == 0)
dbName = args[i + 1];
....
}
try
{
// create DataSource
OracleXADataSource ds = new OracleXADataSource();
ds.setURL("jdbc:oracle:thin:@"+host+":"+port+":"+dbName);
// now stick it into JNDI
Hashtable env = new Hashtable();
env.put (Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.fscontext.RefFSContextFactory");
env.put (Context.PROVIDER_URL, "file:/tmp/JNDI");
InitialContext ctx = new InitialContext(env);
ctx.rebind("jdbc/DB", ds);
}
catch (Exception ex)
{ }
//Set the jndi information to be user by the Arjuna JDBC Property Manager
jdbcPropertyManager.propertyManager.setProperty("Context.INITIAL_CONTEXT_FACTORY",
"com.sun.jndi.fscontext.RefFSContextFactory");
jdbcPropertyManager.propertyManager.setProperty("Context.PROVIDER_URL",
"file:/tmp/JNDI");
Bank bank = new Bank();
BankClient client = new BankClient(bank);
}
While the BankClient class is responsible to obtain information to access the database, tocreate the XADataSource
and bind it to jndi, and also to get order from a user (create_account, debit, transfer, ..), the Bank class is resposnible
to create jdbc connections to perform user's requests. The Bank class is illustarted below where. All
methods are not illusrated here but have a similar behavior; they could be found in
details in the Bank.java
program. Note that for simplicity, much error checking code has been removed.
public Bank()
{
try
{
DriverManager.registerDriver(new TransactionalDriver());
dbProperties = new Properties();
dbProperties.put(TransactionalDriver.userName, user);
dbProperties.put(TransactionalDriver.password, password);
arjunaJDBC2Driver = new TransactionalDriver(); //
create_table();
}
catch (Exception e)
{
e.printStackTrace();
System.exit(0);
}
_accounts = new java.util.Hashtable();
reuseConnection = true;
}
public void create_account( String _name, float _value )
{
try
{
Connection conne = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/DB", dbProperties);
Statement stmtx = conne.createStatement(); // tx statement
stmtx.executeUpdate
("INSERT INTO accounts (name, value)
VALUES ('"+_name+"',"+_value+")");
}
catch (SQLException e)
{
e.printStackTrace();
}
}
public float get_balance(String _name)
throws NotExistingAccount
{
float theBalance = 0;
try
{
Connection conne = arjunaJDBC2Driver.connect("jdbc:arjuna:jdbc/DB", dbProperties);
Statement stmtx = conne.createStatement(); // tx statement
ResultSet rs = stmtx.executeQuery
("SELECT value from accounts
WHERE name = '"+_name+"'");
while (rs.next()) {
theBalance = rs.getFloat("value");
}
}
catch (SQLException e)
{
e.printStackTrace();
throw new NotExistingAccount("The Account requested does not exist");
}
return theBalance;
}
...
}
Note
Although, this version of the banking application creates JTA local transactions,
the way to manipulate JDBC API and the associated JBossTS mechanisms in the
case of distributed transactions is the same.