Accessing Databases from J2EE Applications

J2EE applications interact with databases in a variety of different ways. For example, a typical e-commerce application may need to create and update product records, search for products that match certain criteria, and update a separate inventory database when an order is placed. In each of these cases, the application does the following:

  • Obtains a JDBC connection object (an instance of java.sql.Connection ).

  • Executes one or more SQL queries or commands.

  • Closes the connection.

This is easy to accomplish directly through the JDBC APIs. Unfortunately, the simplest approach isn't very scalable or maintainable . The following two examples show the differences between traditional JDBC access and the more complex but powerful J2EE approach.

Simple Database Access in Non-J2EE Environment

In a basic Java application, you might write the following code to remove products that have passed their expiration date:

 // Load your JDBC driver class so that it can register itself with DriverManager Class.forName("oracle.jdbc.driver.OracleDriver"); // Declare your connection var outside the try block so that we can clean it up later Connection c = null; try {     // Get connection from DriverManager with a JDBC URL, username, password     c = DriverManager.getConnection("jdbc:oracle:thin:@myserver:1521:mydb",                                                          "scott", "tiger");     // Execute some SQL command     Statement s = c.createStatement();     s.execute("UPDATE product SET active=0 WHERE expiration_date < sysdate");     s.close(); } finally {     // close your connection     c.close(); } 

This code is very clean and straightforward. You load a driver, get a connection, execute the update, and then close the connection.

Note 

In this example and others throughout this chapter, exception catching and null checks have been omitted to improve readability.

Of course, life gets a lot more complex once you start thinking about where to store data-base usernames and passwords, how to throttle the number of simultaneous connections, how to ensure that two updates don't clash , and how to roll back changes to a product database if updates to an inventory database are unsuccessful .

In a J2SE application, you could try to solve each of these problems yourself with special driver implementations , configuration files, and direct manipulation of JDBC transactions. However, in the world of J2EE, these problems have already been solved for you with data sources, the Java Transaction API (JTA), and JNDI.

Database Access in a J2EE Environment

With a J2EE application, you'll spend some extra time up front configuring a data source for your server, but then you'll be able to use it over and over again, from many different classes and applications, without worrying about drivers, usernames, passwords, or server locations.

By default, OC4J data sources are configured in a file called data-sources.xml , which is located in the main server configuration directory ( OC4J_HOME/j2ee/home ). A typical data source declaration might look like this:

 <data-source         class="com.evermind.sql.DriverManagerDataSource"         name="ProductCatalogDataSource"         location="jdbc/ProductCatalogDS"         xa-location="jdbc/xa/ProductCatalogXADS"         ejb-location="jdbc/ProductCatalogDS"         connection-driver="oracle.jdbc.driver.OracleDriver"         username="scott"         password="tiger"         url="jdbc:oracle:thin:@localhost:1521:productdb"         inactivity-timeout="30" /> 

You'll revisit all of these properties later in this chapter, but for now, notice that you've specified the name of a driver class ( connection-driver ), a JDBC URL, a username, and a password. You've also chosen a data-source implementation class and set up a few JNDI locations that control where your new data source will live in the global JNDI directory.

When OC4J starts, it will initialize this data source and make it available in JNDI at those locations. Then your applications can access it with code like this:

 // First, create a JNDI InitialContext so that we can look things up in JNDI InitialContext context = new InitialContext(); // Next, look the data source at the JNDI location we configured in data-sources.xml DataSource ds = (DataSource) context.lookUp("jdbc/ProductCatalogDS"); // Declare our connection var outside the try block so that we can clean it up later Connection c = null; try {     // Get connection from the data source     c = ds.getConnection();     // Execute some SQL command     Statement s = c.createStatement();     s.execute("UPDATE product SET active=0 WHERE expiration_date < sysdate");     s.close(); } finally {     // Close connection so the database can use those resources for another request     c.close(); } 

Though the code doesn't look much different, this second approach makes it much easier to take advantage of enterprise features available in OC4J and other J2EE servers. In particular, you can use the following:

  • Connection pooling. Lets you set upper and lower limits on the number of open connections. This cuts down on expensive initialization costs by reusing connections, and helps throttle access to the database so that it cannot be overwhelmed by a surge in requests .

  • Container-managed persistence (CMP). This built-in J2EE persistence framework can automatically save and retrieve entity-bean contents using a specified data source. This means that instead of hand-coding SQL to insert, update, or delete products, you can work with product EJBs and count on OC4J to save any changes to the database.

  • Java Transaction API (JTA). Lets you coordinate the success or failure across many different connections without needing to explicitly track, commit, or roll back each. You can mark the start and end of your transactions either programmatically (with UserTransaction ) or declaratively (in your EJB deployment descriptors).

  • Distributed transactions. OC4J provides support for Open Group's XA standard, which allows for the coordination of transactions across multiple databases or applications. In practice, this means that you can use more than one (XA-capable) data source in a single transaction. For example, you can configure your application so that any associated updates to the product database will also roll back if updates to the inventory database fail. This is accomplished by a protocol called two-phase commit , which first asks each database whether it's capable of committing, and then commits or rolls back all of them together based on the results. Note that OC4J only supports two-phase commit for Oracle data sources.

  • Improved monitoring and tuning. In addition to connection pool sizes, you can also configure transaction timeouts and many other properties that can improve your applications' performance and stability. You can also easily monitor transactions and connection usage through the server console.

  • Portability. Since your code never references a specific driver or JDBC URL, you can easily change database or application servers without rebuilding the application. Instead, you just need to change a few server configuration files.



Oracle Application Server 10g. J2EE Deployment and Administration
Oracle Application Server 10g: J2EE Deployment and Administration
ISBN: 1590592352
EAN: 2147483647
Year: 2004
Pages: 150

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net