OpenJPA caching with WebSphere eXtreme Scale, Informix, and DB2, Part 1: Caching POJOs with hellojpa

Using IBM WebSphere eXtreme Scale, Informix, and DB2

OpenJPA™ is an Apache persistence project. One elegant feature of OpenJPA lets you speed up your lookups and reduce the load on back-end databases with a Java™ Cache. This article will show you how to install, configure, and experiment with IBM® WebSphere® eXtreme Scale product in conjunction with OpenJPA. You can experiment with this without spending any cash, as the cache comes in a free evaluation. With NO code changes and a few lines in a configuration file, OpenJPA performance will improve dramatically.

Marty Lurie (lurie@us.ibm.com), Systems Engineer, IBM

photo of Marty LurieMarty Lurie started his computer career generating chads while attempting to write Fortran on an IBM 1130. His day job is in Systems Engineering for IBM's Informix organization, but if pressed he will admit he mostly plays with computers. His favorite program is the one he wrote to connect his Nordic Track to his laptop (the laptop lost two pounds, and lowered its cholesterol by 20%). Marty is an IBM-certified DB2 DBA, IBM-certified Business Intelligence Solutions Professional, and an Informix-certified Professional.


developerWorks Contributing author
        level

10 March 2011

Also available in Chinese

Overview

Want dramatic performance improvement without changing code? That is the promise of cache. But can it deliver? OpenJPA is an Apache persistence project. An elegant feature of OpenJPA is you can speed up your lookups and reduce the load on back-end databases with a Java Cache and NO code changes. This article will show you how to install, configure, and experiment with IBM WebSphere eXtreme Scale product in conjunction with OpenJPA. You can experiment with this without spending any cash, as the cache comes in a free evaluation. The links below will guide you to the download.

You can use WebSphere eXtreme Scale (WXS) instead of caching in OpenJPA to take advantage of embedded, embedded-partitioned, and remote caching.

This is the first of two articles. This one will address using OpenJPA and eXtreme Scale without an application server. The focus is Plain Old Java Objects (POJOs) and the JDK. Part 2 will take an example with an application server and explore similar testing.

You can explore the installation, configuration, and testing of OpenJPA, IBM WebSphere eXtreme Scale, Informix, and DB2 in the following steps:

  1. Download, install, and configure the following:
    • OpenJPA
    • WebSphere Extreme Scale Cache
    • Informix Innovator C Edition or DB2 Express C
  2. Test OpenJPA, with no cache.
  3. Modify the configuration to use the WebSphere eXtreme Scale cache.
  4. Test OpenJPA, with cache.
  5. Modify the OpenJPA sample to act as a simple test harness.
  6. Modify the OpenJPA configuration to connect to Informix or DB2.
  7. Analysis of results.

Enjoy your new-found performance improvements!

To avoid any confusion: OpenJPA is an Apache project. WebSphere eXtreme Scale, Informix, and DB2 are IBM products. Whereas Informix and DB2 have downloads with free license charges, WebSphere eXtreme Scale only has a free trial download. At the end of the trial period you must get a license to continue using XS. With that out of the way, let's get back to the technologies!

Download and install

The download and install shouldn't present much of a challenge. You will need to register on the IBM web site. There is no charge for getting an ID for the downloads used in this article. Here are the links you need:

If you only want to experiment with OpenJPA and XS caching, then you don't have to download a database. When doing the performance testing, it becomes much more interesting to see users, SQL, buffer pool hit rates, etc. The examples will be from Informix and DB2. You are encouraged to pick one and work with it. If you choose, you can skip ahead and use the Derby database bundled with OpenJPA.

Since there are a lot of resources describing how to install this software, they won't be covered here. As you download the binaries, look for the links for install guides and other documentation if you want more information.

After completing the downloads, your directory listing on Linux may look similar to Listing 1, but please use the md5sum to confirm you got what you really wanted.

Listing 1. Directory listing of downloads for Linux
-rw-r--r-- 1 lurie lurie  29418160 2010-12-31 16:47 apache-openjpa-2.0.1-binary.zip
-rw-r--r-- 1 lurie lurie 427579388 2010-12-31 17:35 db2exc_972_LNX_x86.tar.gz
-rw-r--r-- 1 lurie lurie  69655311 2010-12-31 17:08 extremescaletrial710.zip
-rw-r--r-- 1 lurie lurie 356157440 2010-12-31 17:34 iif.11.70.UC1IE.Linux-RHEL5.tar

Unzip/untar the files into staging directories. Table 1 shows the software and installation commands to start each install.

Table 1. Installation quickstart, the .sh commands are UNIX/Linux, .bat for Windows
SoftwareInstallation or execution command
OpenJPAapache-openjpa-2.0.1/examples/hellojpa/ant
WebSphere eXtreme ScaleObjectGrid/gettingstarted/env.sh, runcat.sh, runcontainer.sh c1, runclient.sh i hello world
Informix Dynamic Serversudo informix/ids_install
DB2expc/db2setup

Follow the defaults for Informix and DB2. Let the script create a sample database instance for you. The graphical entry point for DB2 is shown in Figure 1.

Figure 1. Install entry point for DB2
Screen shot showing the DB2 setup launchpad

Test OpenJPA with no cache

Listing 2 shows the output of running the ant script provided with OpenJPA. Even though caching hasn't been introduced yet, it took 115 milliseconds to create a table. Inserting a row, based on persisting a Java object, took 12 milliseconds. Reading the object back took 1 millisecond. Perhaps it would be a mild overstatement to say this is exciting stuff, but it will get more interesting as we go.

Listing 2. OpenJPA output from baseline test
lurie@merlin:/work/dwOpenJPA/work/openjpa/apache-openjpa-2.0.1/examples/hellojpa$ ant
Buildfile: build.xml

pre-compile:

compile:
    [javac] Compiling 2 source files

run:
     [java] 4232  hellojpa  TRACE  [main] openjpa.jdbc.SQL - t 8204368, conn 15666395 
executing stmnt 22424679 CREATE TABLE Message (id BIGINT NOT NULL, created TIMESTAMP, 
message VARCHAR(255), PRIMARY KEY (id))

     [java] 4347  hellojpa  TRACE  [main] openjpa.jdbc.SQL - t 8204368, conn 15666395 
[115 ms] spent

     [java] 4683  hellojpa  TRACE  [main] openjpa.jdbc.SQL - t 8204368, conn 15975876 
executing prepstmnt 29412736 INSERT INTO Message 
(id, created, message) VALUES (?, ?, ?) [params=?, ?, ?]

     [java] 4695  hellojpa  TRACE  [main] openjpa.jdbc.SQL - t 8204368, conn 15975876 
[12 ms] spent

     [java] 4969  hellojpa  TRACE  [main] openjpa.jdbc.SQL - t 8204368, conn 20336357 
executing prepstmnt 32685187 SELECT t0.id, t0.created, t0.message FROM Message t0

     [java] 4970  hellojpa  TRACE  [main] openjpa.jdbc.SQL - t 8204368, conn 20336357 
[1 ms] spent

     [java] Hello Persistence! (created on: Mon Jan 03 13:18:48 EST 2011)

BUILD SUCCESSFUL
Total time: 10 seconds

Modify the configuration to use the WebSphere eXtreme Scale cache

The next step is to activate the WebSphere eXtreme Scale cache without making any changes to the Java code! You can do this by modifying the OpenJPA persistence.xml file, and by adding the XS jar to the classpath in the example build.xml, as shown in Listing 3 and Listing 4. Notice that the hellojpa build file uses the build file in the parent directory.

Be sure to use the IBM JDK when using the eXtreme Scale cache.

Listing 3. Modifications to apache-openjpa-2.0.1/examples/META-INF/persistence.xml
        <property name="openjpa.ConnectionPassword" 
                value="secret"/>


		<property name="openjpa.DataCache"
	          value="com.ibm.websphere.objectgrid.openjpa.ObjectGridDataCache(
       		   ObjectGridName=BasicTestObjectGrid,ObjectGridType=EMBEDDED,
       		   maxNumberOfReplicas=4)"/>
		<property name="openjpa.QueryCache"
          	value="com.ibm.websphere.objectgrid.openjpa.ObjectGridQueryCache()"/>
		<property name="openjpa.RemoteCommitProvider" value="sjvm"/>



        <properties>
    <persistence-unit>
Listing 4. Modifications to apache-openjpa-2.0.1/examples/build.xml
 <fileset dir="${root}">
            <include name="openjpa-all-*.jar"/>
            <include name="lib/derby*.jar"/>
        <fileset>
        <!-- add path to the eXtreme Scale jar file -->
         <pathelement path="xs"/>
        <fileset dir="/home/lurie/tmp/xs71/ObjectGrid/lib">
            <include name="objectgrid.jar"/>
        <fileset>
        <!-- end of mods to find  eXtreme Scale jar file -->

    </path>

You've now enabled the cache, and made no changes to the Java program, yet the cache is now ready to go.

Run hellojpa with caching enabled

That's it! Time to run the sample. If you haven't already done so, configure the path to use the IBM JVM, and re-run the sample at the command line by typing ant, as shown in Listing 5.

Listing 5. Running OpenJPA sample program with eXtreme Scale Cache enabled
/work/dwOpenJPA/work/openjpa/apache-openjpa-2.0.1/examples/hellojpa$ ant
[java]  ReplicatedPar I CWOBJ1511I: BasicTestObjectGrid:IBM_SYSTEM_ENTITYMANAGER_MAPSET:0
		 (primary) is open for business.
     [java]  ReplicatedPar I CWOBJ1511I: BasicTestObjectGrid:MAPSET_BasicTestObjectGrid:0
		 (primary) is open for business.
     [java]  ObjectGridRes I CWOBJ3134I: The ObjectGrid type is embedded and the default 
		maximum number of replicas is 47.  The maximum number of replicas must be 
		greater than or equal to the number of JVMs in the system.
     [java] hellojpa  TRACE  [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176, 
		conn 362616221> executing prepstmnt 652224224 INSERT INTO Message 
		(id, created, message) VALUES (?, ?, ?) [params=?, ?, ?]
     [java] hellojpa  TRACE  [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176, 
		conn 362616221> [212 ms] spent
... lines deleted ...
     [java] hellojpa  TRACE  [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176, 
		conn 696330625> executing prepstmnt 856306442 SELECT t0.id, t0.created, 
		t0.message FROM Message t0
     [java] hellojpa  TRACE  [P=324170:O=0:CT] openjpa.jdbc.SQL - <t 1720215176, 
		conn 696330625> [1 ms] spent

The results don't really differ from the first case. Why? If there is only one row in the database, then a cache isn't going to make too much difference. Sorry if this is demonstrating a grasp of the obvious. To make this more interesting, we need a better test that will include a few thousand rows.

You are probably tired of having all the SQL TRACE messages scrolling across your screen. To switch to only warning messages, edit the build.xml file to read as follows: value="DefaultLevel=WARN,SQL=WARN".

Modify the OpenJPA sample to act as a simple test harness: Adding looping to Main.java

For production applications, it is critical to study the expected workload and develop a test harness that mirrors reality as much as possible. Full scale testing of transaction systems with significant simulated historical data, like a year, is basic common sense unless you like production system emergencies.

In this case, you can simply create a loop to insert a lot of objects, and then read them back. While it will demonstrate the effectiveness of the cache, it doesn't represent a proper test harness unless you're running helloJPA in production.

Listing 6 shows the changes to the Main.java program, and how to insert 100 rows. This is not a grand challenge. Since this test is about performance, you will be adding Informix to the configuration in the next section. Derby is fine for development, but when it comes to heavy lifting, Informix is a far better choice. The sample files also include the configuration for running on DB2. When testing with Informix, the loop will insert a lot more rows which will make it interesting.

Listing 6. Modify openjpa Main.java to put in 100 rows
        EntityManager em = factory.createEntityManager();

        // *** loop here to put a bunch of rows in the database
            for ( int i=0; i<100;i++)
        {
        
        // *** don't forget to put a closing } below

        // Begin a new local transaction so that we can persist a new entity
        em.getTransaction().begin();

        // Create and persist a new Message entity
        em.persist(new Message("Hello Persistence!"));

        // Commit the transaction, which will cause the entity to
        // be stored in the database
        em.getTransaction().commit();

        // *** end of loop
        }

Cache doesn't really help if you only read items once. Modify Main.java as shown in Listing 7 to read and report timings for two passes at what you have persisted to disk.

Listing 7. Main.java does two reads of the persisted objects
 // Create a fresh, new EntityManager
        EntityManager em2 = factory.createEntityManager();

        // **** set up a timer of how long the queries take
        long starttm = System.currentTimeMillis();


        // Perform a simple query for all the Message entities
        Query q = em2.createQuery("select m from Message m");

        // Go through each of the entities and print out each of their
        // messages, as well as the date on which it was created
        for (Message m : (List<Message> q.getResultList()) {

        // *** better comment this out or 20,000 prints are coming back!
        //  System.out.println(m.getMessage()
        //      + " (created on: " + m.getCreated() + ")");

        }
        // *** report on the first run
       long end1sttm = System.currentTimeMillis();
       System.out.println("\n\nfirst run took: " + (end1sttm-starttm) +
		"  millisec\n\n\n");

        
        // **** second run should be in local cache
        // Perform a simple query for all the Message entities
        Query q2 = em2.createQuery("select m from Message m");

        // Go through each of the entities and print out each of their
        // messages, as well as the date on which it was created
        for (Message m : (List<Message> q2.getResultList()) {
         //System.out.println(m.getMessage() 
		//+ " (created on: " + m.getCreated() + ")");
        }
        long end2ndtm = System.currentTimeMillis();
        System.out.println("\n\nsecond run, from cache took: " 
		+ (end2ndtm-end1sttm) + "  millisec\n\n\n");


        // Again, it is always good to clean up after ourselves
        em2.close();

The results, as shown in listing 8, show a dramatic speed-up for using WebSphere eXtreme Scale Cache. And remember, this is with no application code changes! I know you will grant me a pass on no code changes for adding the loop to generate the heavier workload.

Listing 8. Output from test run: Dramatic speed-up using WebSphere eXtreme Scale with Derby database
 [java] [1/26/11 11:00:11:776 EST] 3a883a88 SystemOut     O 
     [java] 
     [java] first run took: 3761  millisec
     [java] 
     [java] 
     [java] 
     [java] [1/26/11 11:00:11:865 EST] 3a883a88 SystemOut     O 
     [java] 
     [java] second run, from cache took: 89  millisec
     [java] 
     [java]

The performance improvement is over 40 times better, 3761 milliseconds to 89 milliseconds. This is hardware dependent so your mileage will vary. There are a number of environmental factors that can also impact performance. For example, if you are paging/swapping any relevant performance, then data is off the table.

Modify the OpenJPA configuration to connect to Informix or DB2

A more realistic test is to use OpenJPA with an industrial strength database. The good news is changing the database from Derby to Informix only requires some simple modifications in the build.xml file, as shown in Listing 9. The database specification is changed, and the path to the jdbc jar is required.

Listing 9. Modifications to build.xml to use Informix Dynamic Server
build.xml

<project default="usagewarning">>

    <property name="parent" value="${basedir}/.."/>
    <property name="root" value="${parent}/.."/>

    <!-- database connection properties
    <property name="dbdriver" value="org.apache.derby.jdbc.EmbeddedDriver"/>
    <property name="dburl"
        value="jdbc:derby:${basedir}/${example}-database;create=true"/>
    <property name="dbuser" value=""/>
    <property name="dbpass" value=""/>

-->
<!-- database connection properties -->
<!-- informix instead of derby -->

    <property name="dbdriver" value="com.informix.jdbc.IfxDriver"/>
    <property name="dburl"
        value="jdbc:informix-sqli://merlin:54321/idsopenjpa:informixserver=ids115"/>
    <property name="dbuser" value="informix"/>
    <property name="dbpass" value="idsr0cks"/>

    <target name="usagewarning">


PATH CHANGES

<path id="classpath"
        description="The classpath to use for compiling and running">
        <pathelement path="${parent}"/>
        <fileset dir="${root}">
            <include name="**/*.jar"/>
        </fileset>
        <pathelement path="xs"/>
        <fileset dir="/home/lurie/tmp/xs71/ObjectGrid/lib">
            <include name="objectgrid.jar"/>
        </fileset>
        <pathelement path="ifx"/>
        <fileset dir="/opt/IBM/informix/jdbc/lib">
            <include name="ifxjdbc.jar"/>
        </fileset>
    </path>

Informix Configuration

Don't create any tables, just a database.  It seems almost too easy.

informix@merlin:~$ dbaccess - - 
> create database idsopenjpa with buffered log;

Database created.

Analysis of Results

So was it fast? Reading this would be a waste of time if it wasn't fast! As shown in Listing 10, the Main.java program was modified to insert 10,000 rows. Informix can crank out 10,000 rows in 1 second because of its advanced buffer pool management and industrial strength architecture. There is still a significant performance improvement by having the data stored in cache in the same address space with the Java application. Beating 49 milliseconds for cache access while traversing a TCP/IP round trip is a significant challenge for any database.

Listing 10. Output from test run: Dramatic speedup using WebSphere eXtreme Scale with Informix database
  [java] [1/26/11 17:28:38:751 EST] 72887288 SystemOut     O 
     [java] 
     [java] first run took: 1096  millisec rows processed= 10000
     [java] 
     [java] 
     [java] 
     [java] [1/26/11 17:28:38:800 EST] 72887288 SystemOut     O 
     [java] 
     [java] second run, from cache took: 49  millisec
     [java]

If you are curious about what is happening at the database level, look at listing 11 to see the schema.

Listing 11. Informix database schema
create table "informix".message 
  (
    id decimal(32,0) not null ,
    created datetime year to fraction(3),
    message varchar(255),
    primary key (id) 
  );

Conclusion: Enjoy your new-found performance improvements!

You have covered a lot of ground here with a rapid introduction to OpenJPA, WebSphere eXtreme Scale, and the use of a Java cache with the Informix Dynamic Server database. The sample files provided include all of the previously shown code, and of course include how to do this with DB2.

Please experiment with this yourself!

If you'd like to hear more on this topic, don't miss the Informix International Users Group (see Resources for more details), where Marty be presenting on this topic.


Download

DescriptionNameSize
Sample files for this articlesampleFiles.tar50B

Resources

Learn

Get products and technologies

  • Build your next development project with IBM trial software, available for download directly from developerWorks.
  • Download a free copy of Informix Innovator-C, a version of Informix designed for small workloads.
  • Download an evaluation copy of WebSphere eXtreme Scale.
  • Download DB2 Express-C, a free edition of DB2 for Linux, Windows, and Mac that is easy to use and provides a solid base to build and deploy applications.

Discuss

Comments

developerWorks: Sign in

Required fields are indicated with an asterisk (*).


Need an IBM ID?
Forgot your IBM ID?


Forgot your password?
Change your password

By clicking Submit, you agree to the developerWorks terms of use.

 


The first time you sign into developerWorks, a profile is created for you. Information in your profile (your name, country/region, and company name) is displayed to the public and will accompany any content you post, unless you opt to hide your company name. You may update your IBM account at any time.

All information submitted is secure.

Choose your display name



The first time you sign in to developerWorks, a profile is created for you, so you need to choose a display name. Your display name accompanies the content you post on developerWorks.

Please choose a display name between 3-31 characters. Your display name must be unique in the developerWorks community and should not be your email address for privacy reasons.

Required fields are indicated with an asterisk (*).

(Must be between 3 – 31 characters.)

By clicking Submit, you agree to the developerWorks terms of use.

 


All information submitted is secure.

Dig deeper into Information management on developerWorks


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=1
Zone=Information Management, WebSphere, Java technology, Open source
ArticleID=631390
ArticleTitle=OpenJPA caching with WebSphere eXtreme Scale, Informix, and DB2, Part 1: Caching POJOs with hellojpa
publish-date=03102011