Chapter 2 Programming Information
This section describes how to use advanced jConnect features and contains the following topics:
You can use the jConnect event notification feature to have your application notified when an Open Server procedure is executed.
To use this feature, you must use the SybConnection class, which extends the Connection interface. SybConnection contains a regWatch( ) method for turning event notification on and a regNoWatch( ) method for turning event notification off.
Your application must also implement the SybEventHandler interface. This interface contains one public method, void event(String proc_name, ResultSet params), which is called when the specified event occurs. The parameters of the event are passed to event( ) and it tells the application how to respond.
To use event notification in your application, call SybConnection.regWatch( ) to register your application in the notification list of a registered procedure. Use this syntax:
SybConnection.regWatch(proc_name,eventHdlr,option)
Whenever an event with the designated proc_name occurs on the Open Server, jConnect calls eventHdlr.event( ) from a separate thread. The event parameters are passed to eventHdlr.event( ) when it is executed. Because it is a separate thread, event notification does not block execution of the application.
If proc_name is not a registered procedure, or if Open Server cannot add the client to the notification list, the call to regWatch( ) throws a SQL exception.
To turn off event notification, use this call:
SybConnection.regNoWatch(proc_name)
When you use Sybase event notification extensions, the
application needs to call the close( ) method
on the connection to remove a child thread created by the first
call to regWatch( ). Failing to do so may cause
the Virtual Machine to hang when exiting the application.
The following example shows how to implement an event handler and then register an event with an instance of your event handler, once you have a connection:
public class MyEventHandler implements SybEventHandler { // Declare fields and constructors, as needed. ... public MyEventHandler(String eventname) { ... } // Implement SybEventHandler.event. public void event(String eventName, ResultSet params) { try { // Check for error messages received prior to event // notification. SQLWarning sqlw = params.getWarnings(); if sqlw != null { // process errors, if any ... } // process params as you would any result set with // one row. ResultSetMetaData rsmd = params.getMetaData(); int numColumns = rsmd.getColumnCount(); while (params.next()) // optional { for (int i = 1; i <= numColumns; i++) { System.out.println(rsmd.getColumnName(i) + " = " + params.getString(i)); } // Take appropriate action on the event. For example, // perhaps notify application thread. ... } } catch (SQLException sqe) { // process errors, if any ... } } } public class MyProgram { ... // Get a connection and register an event with an instance // of MyEventHandler. Connection conn = DriverManager.getConnection(...); MyEventHandler myHdlr = new MyEventHandler("MY_EVENT"); // Register your event handler. ((SybConnection)conn).regWatch("MY_EVENT", myHdlr, SybEventHandler.NOTIFY_ALWAYS); ... conn.regNoWatch("MY_EVENT"); conn.close();
}
jConnect provides two classes for returning Sybase-specific error information, SybSQLException and SybSQLWarning, as well as a SybMessageHandler interface that allows you to customize the way jConnect handles error messages received from the server.
jConnect provides an EedInfo interface that specifies methods for obtaining Sybase-specific error information. The EedInfo interface is implemented in SybSQLException and SybSQLWarning, which extend the SQLException and SQLWarning classes.
SybSQLException and SybSQLWarning contain the following methods:
Some error messages may be SQLException or SQLWarning messages, without being SybSQLException or SybSQLWarning messages. Your application should check the type of exception it is handling before it downcasts to SybSQLException or SybSQLWarning.
You can use the SybMessageHandler interface to customize the way jConnect handles error messages generated by the server. Implementing SybMessageHandler in your own class for handling error messages can provide the following benefits:
Error-message handlers implementing the SybMessageHandler interface only
receive server-generated messages. They do not handle messages generated
by jConnect.
When jConnect receives an error message, it checks to see if a SybMessageHandler class has been registered for handling the message. If so, jConnect invokes the messageHandler( ) method. The messageHandler( ) method accepts a SQL exception as its argument, and jConnect processes the message based on what value is returned from messageHandler( ). The error-message handler can:
You can install an error-message handler implementing SybMessageHandler by calling the setMessageHandler( ) method from SybDriver, SybConnection, or SybStatement. If you install an error-message handler from SybDriver, all subsequent SybConnection objects inherit it. If you install an error-message handler from a SybConnection object, it is inherited by all SybStatement objects created by that SybConnection.
This hierarchy only applies from the time the error-message handler object is installed. For example, if you create a SybConnection object, myConnection, and then call SybDriver.setMessageHandler( ) to install an error-message handler object, myConnection cannot use that object.
To return the current error-message handler object, use
getMessageHandler(
).
The following example uses jConnect version 4.1.
import java.io.*; import java.sql.*; import com.sybase.jdbcx.SybMessageHandler; import com.sybase.jdbcx.SybConnection; import com.sybase.jdbcx.SybStatement; import java.util.*; public class MyApp { static SybConnection conn = null; static SybStatement stmt = null static ResultSet rs = null; static String user = "guest"; static String password = "sybase"; static String server = "jdbc:sybase:Tds:192.138.151.39:4444"; static final int AVOID_SQLE = 20001; public MyApp() { try { Class.forName("com.sybase.jdbc.SybDriver").newInstance; Properties props = new Properties(); props.put("user", user); props.put("password", password); conn = (SybConnection) DriverManager.getConnection(server, props); conn.setMessageHandler(new NoResultSetHandler()); stmt =(SybStatement) conn.createStatement(); stmt.executeUpdate("raiserror 20001 'your error'"); for (SQLWarning sqw = _stmt.getWarnings(); sqw != null; sqw = sqw.getNextWarning()); { if (sqw.getErrorCode() == AVOID_SQLE); { System.out.println("Error" + sqw.getErrorCode()+ " was found in the Statement's warning list."); break; } } stmt.close(); conn.close(); } catch(Exception e) { System.out.println(e.getMessage()); e.printStackTrace(); } } class NoResultSetHandler implements SybMessageHandler { public SQLException messageHandler(SQLException sqe) { int code = sqe.getErrorCode(); if (code == AVOID_SQLE) { System.out.println("User " + _user + " downgrading " + AVOID_SQLE + " to a warning"); sqe = new SQLWarning(sqe.getMessage(), sqe.getSQLState(),sqe.getErrorCode()); } return sqe; } } public static void main(String args[]) { new MyApp(); }
Some database products enable you to directly store Java objects as column data in a database. In such databases, Java classes are treated as datatypes, and you can declare a column with a Java class as its datatype.
jConnect supports storing Java objects in a database by implementing the setObject( ) methods defined in the PreparedStatement interface and the getObject( ) methods defined in the CallableStatement and ResultSet interfaces. This allows you to use jConnect with an application that uses native JDBC classes and methods to directly store and retrieve Java objects as column data.
To use getObject( ) and setObject(
), set the jConnect version to VERSION_4 or later.
See "Setting the jConnect version".
The following sections describe the requirements and procedures for storing objects in a table and retrieving them using JDBC with jConnect:
Adaptive Server Enterprise version 12.0 and later and
Adaptive Server Anywhere version 6.0.x and later can store Java
objects in a table, with some limitations. See the jConnect
for JDBC Release Bulletin for more information.
To store Java objects belonging to a user-defined Java class in a column, three requirements must be met:
To send an instance of a user-defined class as column data, use one of the following setObject( ) methods, as specified in the PreparedStatement interface:
void setObject(int parameterIndex, Object x, int targetSqlType, int scale) throws SQLException;
void setObject(int parameterIndex, Object x, int targetSqlType) throws SQLException;
void setObject(int parameterIndex, Object x) throws SQLException;
In jConnect 4.5, you can also use PreparedStatement.setObject (int parameterIndex
, Object
x
, Types.OTHER) method to
pass a Java object to the database. The object must still implement
the java.io.Serializable interface.In jConnect
5.5, you can use the Types.OTHER target sqlType
to
send a Java object, or you can use Types.JAVA_OBJECT (available only
in jConnect 5.x).
The following example defines an Address class, shows the definition of a Friends table that has an Address column whose datatype is the Address class, and inserts a row into the table.
public class Address implements Serializable
{
public String streetNumber; public String street; public String apartmentNumber; public String city; public int zipCode;
//Methods
...
}
/* This code assumes a table with the following structure ** Create table Friends:
** (firstname varchar(30) , ** lastname varchar(30), ** address Address, ** phone varchar(15))
*/
// Connect to the database containing the Friends table. Connection conn = DriverManager.getConnection("jdbc:sybase:Tds:localhost:5000", "username", "password"); // Create a Prepared Statement object with an insert statement //for updating the Friends table. PreparedStatement ps = conn.prepareStatement("INSERT INTO Friends values (?,?,?,?)"); // Now, set the values in the prepared statement object, ps. // set firstname to "Joan." ps.setString(1, "Joan"); // Set last name to "Smith." ps.setString(2, "Smith"); // Assuming that we already have "Joan_address" as an instance // of Address, use setObject(int parameterIndex, Object x) to // set the address column to "Joan_address." ps.setObject(3, Joan_address); // Set the phone column to Joan's phone number. ps.setString(4, "123-456-7890"); // Perform the insert. ps.executeUpdate();
A client JDBC application can receive a Java object from the database in a result set or as the value of an output parameter returned from a stored procedure. If a result set contains a Java object as column data, use one of the following getObject( ) methods in the ResultSet interface to retrieve the object:
Object getObject(int columnIndex) throws SQLException;
Object getObject(String columnName) throws SQLException;If an output parameter from a stored procedure contains a Java object, use the following getObject( ) method in the CallableStatement interface to retrieve the object:
Object getObject(int parameterIndex) throws SQLException;
The following example illustrates the use of
ResultSet.getObject(int
parameterIndex) to assign an object received in a result set
to a class variable. The example uses the Address class
and Friends table used in the previous section
and presents a simple application that prints a name and address
on an envelope.
/* ** This application takes a first and last name, gets the ** specified person's address from the Friends table in the ** database, and addresses an envelope using the name and ** retrieved address. */ public class Envelope { Connection conn = null; String firstName = null; String lastName = null; String street = null; String city = null; String zip = null; public static void main(String[] args) { if (args.length < 2) { System.out.println("Usage: Envelope <firstName> <lastName>"); System.exit(1); } // create a 4" x 10" envelope Envelope e = new Envelope(4, 10); try { // connect to the database with the Friends table. conn = DriverManager.getConnection( "jdbc:sybase:Tds:localhost:5000", "username", "password"); // look up the address of the specified person firstName = args[0]; lastName = args[1]; PreparedStatement ps = conn.prepareStatement( "SELECT address FROM friends WHERE " + "firstname = ? AND lastname = ?"); ps.setString(1, firstName); ps.setString(2, lastName); ResultSet rs = ps.executeQuery(); if (rs.next()) { Address a = (Address) rs.getObject(1); // set the destination address on the envelope e.setAddress(firstName, lastName, a); } conn.close(); } catch (SQLException sqe) { sqe.printStackTrace(); System.exit(2); } // if everything was successful, print the envelope e.print(); } private void setAddress(String fname, String lname, Address a) { street = a.streetNumber + " " + a.street + " " + a.apartmentNumber; city = a.city; zip = "" + a.zipCode; } private void print() { // Print the name and address on the envelope. ... } }
You can find a more detailed example of HandleObject.java in the sample (jConnect 4.x) and sample2 (jConnect 5.x) subdirectories under your jConnect directory.
Adaptive Server Anywhere version 6.0 and Adaptive Server Enterprise version 12.0 and later allow you to specify Java classes as:
In earlier versions, only classes that appeared in jConnect's CLASSPATH were accessible; that is, if a jConnect application attempted to access an instance of a class that was not in the local CLASSPATH, a java.lang.ClassNotFound exception would result.
jConnect version 5.2 implements DynamicClassLoader (DCL) to load a class directly from an Adaptive Server Anywhere or Adaptive Server Enterprise server and use it as if it was present in the local CLASSPATH.
All security features present in the superclass are inherited. The loader delegation model implemented in Java 2 is followed--first jConnect attempts to load a requested class from the CLASSPATH; if that fails, jConnect tries the DynamicClassLoader.
See Java in Adaptive Server Enterprise for more detailed information about use Java and Adaptive Server.
To use DCL functionality:
Properties props = new Properties();// URL of the server where the classes live. String classesUrl = "jdbc:sybase:Tds:myase:1200"; // Connection properties for connecting to above server. props.put("user", "grinch"); props.put("password", "meanone"); ... // Ask the SybDriver for a new class loader. DynamicClassLoader loader = driver.getClassLoader(classesUrl, props);
// Stash the class loader so that other connection(s) // can know about it. props.put("CLASS_LOADER", loader);// Additional connection properties props.put("user", "joeuser"); props.put("password", "joespassword");// URL of the server we now want to connect to. String url = "jdbc:sybase:Tds:jdbc.sybase.com:4446";// Make a connection and go. Connection conn = DriverManager.getConnection(url, props);Assuming the following Java class definition:
class Addr { String street; String city; String state; }
create table employee (char(100) name, int empid, Addr address)
Statement stmnt = conn.createStatement();
// Retrieve some rows from the table that has a Java class
// as one of its fields.
ResultSet rs = stmnt.executeQuery(
"select * from employee where empid = '19'");
if (rs.next() {
// Even though the class is not in our class path,
// we should be able to access its instance.
Object obj = rs.getObject("address");
// The class has been loaded from the server,
// so let's take a look.
Class c = obj.getClass();
// Some Java Reflection can be done here
// to access the fields of obj.
...
}
The CLASS_LOADER connection property provides a convenient mechanism for sharing one class loader among several connections.
You should ensure that sharing a class loader across connections does not result in class conflicts. For example, if two different, incompatible instances of class org.foo.Bar exist in two different databases, problems can arise if you use the same loader to access both classes. The first class is loaded when examining a result set from the first connection. When it is time to examine a result set from the second connection, the class is already loaded. The second class is never loaded, and there is no direct way for jConnect to detect this situation.
However, Java has a built-in mechanism for ensuring that the version of a class matches the version information in a deserialized object. The above situation is at least detected and reported by Java.
Classes and their instances do not need to reside in the same database or server, but there is no reason why both the loader and subsequent connections cannot refer to the same database/server.
The following example illustrates how to deserialize an object from a local file. The serialized object is an instance of a class that resides on a server and does not exist in the CLASSPATH.
SybResultSet.getObject( ) makes use of DynamicObjectInputStream, which is a subclass of ObjectInputStream that loads a class definition from DynamicClassLoader, rather than the default system ("boot") class loader.
// Make a stream on the file containing the
//serialized object.
FileInputStream fileStream = new FileInputStream("serFile");
// Make a "deserializer" on it. Notice that, apart
//from the additional parameter, this is the same
//as ObjectInputStreamDynamicObjectInputStream
stream = new DynamicObjectInputStream(fileStream, loader);
// As the object is deserialized, its class is
//retrieved via the loader from our server.
Object obj = stream.readObject();stream.close();
jConnect version 5.2 includes a new connection property called PRELOAD_JARS. When defined as a comma-delimited list of JAR file names, the JAR files are loaded in their entirety. In this context, "JAR" refers to the "retained JARname" used by the server. This is the JAR name specified in the install Java program, for example:
install java new jar 'myJarName' from file '/tmp/mystuff.jar'
If you set PRELOAD_JARS, the JAR files are associated with the class loader, so it is unnecessary to preload them with every connection. You should only specify PRELOAD_JARS for one connection. Subsequent attempts to preload the same JAR files may result in performance problems as the JAR data is retrieved from the server unnecessarily.
Adaptive Server Anywhere 6.x and later cannot return
an JAR file as one entity, so jConnect iteratively retrieves each
class in turn. However, Adaptive Server 12.x and later retrieves
the entire JAR and loads each class that it contains.
There are various public methods in DynamicClassLoader. For more information, see the javadocs information in JDBC_HOME/docs/en/javadocs.
Additional features include the ability to keep a loader's database connection "alive" when a series of class loads is expected, and to explicitly load a single class by name.Public methods inherited from java.lang.ClassLoader can also be used. Methods in java.lang.Class that deal with loading classes are also available; however, use these methods with caution since some of them make assumptions about which class loader gets used. In particular, you should use the 3-argument version of Class.forName(), otherwise the system ("boot") class loader will be used. See "Handling error messages".
The JDBC 2.0 Optional Package (formerly the JDBC 2.0 Standard Extension API) defines several new features that may be implemented by JDBC 2.0 drivers. jConnect version 5.2 has implemented the following optional package extension features:
The above features require classes and/or interfaces that are not found in standard Java 2 distributions. You must download javax.sql.* and javax.naming.* to implement
Databases and Connection Pooling, and you must download javax.transaction.xa.* to implement Distributed Transaction Management Support.
Sybase recommends that you use JNDI 1.2, which is compatible
with Java 1.1.6 and later.
The JDBC 2.0 Optional Package (formerly the JDBC 2.0 Standard Extension API), Chapter 5, "JNDI and the JDBC API."
This feature provides JDBC clients with an alternative to the standard approach for obtaining database connections. Instead of invoking Class.forName ("com.sybase.jdbc2.jdbc.SybDriver"), then passing a JDBC URL to the DriverManager's getConnection( ) method, clients can access a JNDI name server using a logical name to retrieve a javax.sql.DataSource object. This object is responsible for loading the driver and establishing the connection to the physical database it represents. The client code is simpler and reusable because the vendor-specific information has been placed within the DataSource object.
The Sybase implementation of the DataSource object is com.sybase.jdbcx.SybDataSource (see the javadocs for details). This implementation supports the following standard properties using the design pattern for JavaBean components:
roleName is not supported.
jConnect provides an implementation of the javax.naming.spi.ObjectFactory interface so the DataSource object can be constructed from the attributes of a name server entry. When given a javax.naming.Reference, or a javax.naming.Name and a javax.naming.DirContext, this factory can construct com.sybase.jdbcx.SybDataSource objects. To use this factory, set the java.naming.object.factory system property to include com.sybase.jdbc2.SybObjectFactory.
You can use DataSource in different ways, in different applications. All options are discussed below with some code examples to guide you through the process. For more information, see the JDBC 2.0 Optional Package (formerly the JDBC 2.0 Standard Extension API), and the JNDI documentation on Sun's Web site.
jConnect has supported LDAP connectivity since version 4.0. As a result, the recommended approach, which requires no custom software, is to configure DataSources as LDAP entries using the LDAP Data Interchange Format (LDIF). For example:
dn:servername:myASE, o=MyCompany, c=US
1.3.6.1.4.1.897.4.2.5:TCP#1# mymachine 4000
1.3.6.1.4.1.897.4.2.10:PACKETSIZE=1024&user=me&password=secret
1.3.6.1.4.1.897.4.2.11:userdb
This is the typical JDBC client application. The only difference is that you access the name server to obtain a reference to a DataSource object, instead of accessing the DriverManager and providing a JDBC URL. Once you obtain the connection, the client code is identical to any other JDBC client code. The code is very generic and references Sybase only when setting the object factory property, which can be set as part of the environment.
The jConnect installation contains the sample program sample2/SimpleDataSource.java to illustrate the use of DataSource. This sample is provided for reference only; that is, you cannot run the sample unless you configure your environment and edit the sample appropriately. SimpleDataSource.java contains the following critical code:
import javax.naming.*;
import javax.sql.*;
import java.sql.*;
// set necessary JNDI properties for your environment (same as above)
Properties jndiProps = new Properties();
// used by JNDI to build the SybDataSource
jndiProps.put(Context.OBJECT_FACTORIES,
"com.sybase.jdbc2.jdbc.SybObjectFactory");
// nameserver that JNDI should talk to
jndiProps.put(Context.PROVIDER_URL, "ldap:
//some_ldap_server:238/o=MyCompany,c=Us");
// used by JNDI to establish the naming context
jndiProps.put(Context.INITIAL_CONTEXT_FACTORY,
"com.sun.jndi.ldap.LdapCtxFactory");
// obtain a connection to your name server
Context ctx = new InitialContext(jndiProps);
DataSource ds = (DataSource) ctx.lookup("servername=myASE");
// obtains a connection to the server as configured earlier.
// in this case, the default username and password will be used
Connection conn = ds.getConnection();
// do standard JDBC methods
...
Explicitly passing the Properties to the InitialContext constructor is not required if the properties have already been defined within the virtual machine; that is, passed when Java was either set as part of the browser properties, or by using:
java -Djava.naming.object.factory=com.sybase.jdbc2.jdbc.SybObjectFactory
See your Java VM documentation for more information about setting environment properties.
This phase is typically done by the person who does database system administration or application integration for their company. The purpose is to define a data source, then deploy it under a logical name to a name server. If the server needs to be reconfigured (for example, moved to another machine, port, and so on), then the administrator runs this configuration utility (outlined below) and reassigns the logical name to the new data source configuration. As a result, the client code does not change, since it knows only the logical name.
import javax.sql.*;
import com.sybase.jdbcx.*;
.....
// create a SybDataSource, and configure it
SybDataSource ds = new com.sybase.jdbc2.jdbc.SybDataSource();
ds.setUser("my_username");
ds.setPassword("my_password");
ds.setDatabaseName("my_favorite_db");
ds.setServerName("db_machine");
ds.setPortNumber(4000);
ds.setDescription("This DataSource represents the Adaptive Server Enterprise server running on db_machine at port 2638. The default username and password have been set to 'me' and 'mine' respectively. Upon connection, the user will access the my_favorite_db database on this server."); Properties props = newProperties() props.put("REPEAT_READ","false"); props.put("REQUEST_HA_SESSION","true"); ds.setConnectionProperties(props);
// store the DataSource object. Typically this is // done by setting JNDI properties specific to the // type of JNDI service provider you are using. // Then, initialize the context and bind the object.
Context ctx = new InitialContext();
ctx.bind("jcbc/myASE", ds);
Once you set up your DataSource,
you decide where and how you want to store the information. To assist
you, SybDataSource is both java.io.Serializable and javax.naming.Referenceable,
but it is still up to the administrator to determine how the data
is stored depending on what service provider you are using for JNDI.
The client retrieves the DataSource object by setting its JNDI properties the same way the DataSource was deployed. The client needs to have an object factory available that can transform the object as it is stored (for example, serialized) into a Java object.
Context ctx = new InitialContext(); DataSource ds = (DataSource ctx.lookup("jcbc/myASE");
The JDBC 2.0 Optional Package (formerly the JDBC 2.0 Standard Extension API), Chapter 6, "Connection Pooling."
Traditional database applications create one connection to a database that you use for each session of an application. However, a Web-based database application may need to open and close a new connection several times during the application's use. An efficient way to handle Web-based database connections is to use connection pooling, which maintains open database connections and manages connection sharing across different user requests to maintain performance and to reduce the number of idle connections. On each connection request, the connection pool first determines if there is an idle connection in the pool. If there is, the connection pool returns that connection instead of making a new connection to the database.
Connection pooling capabilities are provided by ConnectionPoolDataSource. If you use this interface, you can pool connections. If you use the DataSource interface, you cannot pool connections.
When you use ConnectionPoolDataSource, pool implementations listen to the PooledConnection. The implementation is notified when a user closes the connection, or if the user has an error that destroys the connection. At this point, the pool implementation decides what to do with the PooledConnection.
Without connection pooling, a transaction:
With connection pooling, the sequence looks more like this:
It is less costly to reuse a connection than to create a new one every time a client needs to establish a connection to a database.
To enable a third party to implement the connection pool, the jConnect implementation has the ConnectionPoolDataSource interface produce PooledConnections, similar to how the DataSource interface produces Connections.The pool implementation creates "real" database connections, using the getPooledConnection( ) methods of ConnectionPoolDataSource. Then, the pool implementation registers itself as a listener to the PooledConnection. Currently, when a client requests a connection, the pool implementation invokes getConnection( ) on an available PooledConnection. When the client finishes with the connection and calls close(), the pool implementation is notified via the ConnectionEventListener interface that the connection is free and available for reuse.
The pool implementation is also notified via the ConnectionEventListener interface if the client somehow corrupts the database connection, so that the pool implementation can remove that connection from the pool.For more information, refer to Appendix B of the the JDBC 2.0 Optional Package (formerly the JDBC 2.0 Standard Extension API).
This approach is the same as 1a. Configuration by administrator: LDAP described in "JNDI for naming databases," except that you enter an additional line to your LDIF entry. In the following example, the added line of code is bolded for your reference.
dn:servername=myASE, o=MyCompany, c=US 1.3.6.1.4.1.897.4.2.5:TCP#1# mymachine 4000 1.3.6.1.4.1.897.4.2.10:PACKETSIZE=1024&user=me&password=secret 1.3.6.1.4.1.897.4.2.11:userdb 1.3.6.1.4.1.897.4.2.18:ConnectionPoolDataSource
This procedure initializes three properties (INITIAL_CONTEXT_FACTORY, PROVIDER_URL, and OBJECT_FACTORIES as shown on page 78), and retrieves a ConnectionPoolDataSource object. For a more complete code example, see sample2/SimpleConnectionPool.java. The fundamental difference is:
... ConnectionPoolDatabase cpds = (ConnectionPoolDataSource) ctx.lookup("servername=myASE"); PooledConnection pconn = cpds.getPooledConnection();
This feature provides a standard Java API for performing distributed transactions with either Adaptive Server Enterprise version 12.x or version 11.x with XA-Server.
This feature is designed for use in a large multitier
environment.
See Chapter 7, "Distributed Transactions," in the JDBC 2.0 Optional Package (formerly the JDBC 2.0 Standard Extension API).
jConnect also provides a standard Java API for performing distributed transactions with Adaptive Server Enterprise version 11.x as your database server.
This approach is the same as 1a. Configuration by administrator: LDAPdescribed in "JNDI for naming databases", except that you enter an additional line to the LDIF entry. In the following example, the added line of code is displayed in bold.
dn:servername:myASE, o=MyCompany, c=US 1.3.6.1.4.1.897.4.2.5:TCP#1# mymachine 4000 1.3.6.1.4.1.897.4.2.10:PACKETSIZE=1024&user=me&password=secret 1.3.6.1.4.1.897.4.2.11:userdb 1.3.6.1.4.1.897.4.2.18:XADataSource
This procedure initializes three properties (INITIAL_CONTEXT_FACTORY, PROVIDER_URL, and OBJECT_FACTORIES), and retrieves a XADataSource object. For example:
... XADataSource xads = (XADatasource) ctx.lookup("servername=myASE"); XAConnection xaconn = xads.getXAConnection();
or override the default settings for the user name and password:
... XADataSource xads = (XADatasource) ctx.lookup("servername=myASE"); XAConnection xaconn = xads.getXAConnection("my_username","my_password");
This approach is the same as 1a. Configuration by administrator: LDAPdescribed in "JNDI for naming databases", except that you enter an additional three lines to the LDIF entry.
In the following example, the additional code lines are displayed in bold .
dn:servername:myASE, o=MyCompany, c=US 1.3.6.1.4.1.897.4.2.5:TCP#1# mymachine 4000 1.3.6.1.4.1.897.4.2.10:PACKETSIZE=1024&user=me&password=secret 1.3.6.1.4.1.897.4.2.11:userdb 1.3.6.1.4.1.897.4.2.16:userconnection 1.3.6.1.4.1.897:4.2.17:1 1.3.6.1.4.1.897.4.2.18:XADataSource
where . . .4.2.17:1
indicates
that jConnect is going to connect to an XA-Server and userconnection
corresponds
to the Logical Resource Manager (LRM) to use. XA-Server has an xa_config file
that contains these entries:
[xa]
lrm=userconnection server=my_ase_11_server XAServer=my_xa_server
See the XA-Server documentation for details on how to write an xa_config file.
This procedure initializes three properties (INITIAL_CONTEXT_FACTORY, PROVIDER_URL, and OBJECT_FACTORIES), and retrieves a XADataSource object. For example:
... XADataSource xads = (XADatasource) ctx.lookup("servername=myASE"); XAConnection xaconn = xads.getXAConnection();
With Adaptive Server Enterprise 11.x, you cannot override the default user name and password[Unmapped Entity: shy ] ; that is, you cannot call:
xads.getXAConnection("my_username","my_password");
because the lrm is associated with a specific user name and password.
Copyright © 2001 Sybase, Inc. All rights reserved. |
![]() |