Skip to main content

Your Hibernate-Powered Application is Ready for CMT

January 20, 2005

{cs.r.title}









Contents
Statement of the Problem
Software Requirements
High-Level View of our Application
Examine the Code
Configuring MySQL
Compiling Your Code
Testing Ready Application
Afterword
Resources

Statement of the Problem

I am simply struck by seeing so many questions on numerous forums and
newsgroups, concerning problems with using Hibernate in a JBoss application server
environment and using container-managed transactions (CMT)! This happens even in a
FAQ on Hibernate's site: the question
"How do I use Hibernate with CMT?"
gets the very simple answer, "Just do it."

Isn't that strange? Why are people having such problems if everything is supposed to
be extremely simple? I have tried to find the solution myself, and to tell the truth, I
haven't found it. Hopefully the Hibernate community will note that this problem has come up
because of the lack of documentation. More accurately, the documentation
exists, but I have not been able to find a beginner-oriented description how to make it work from
square one. This, in my opinion, is the reason why people all over the world are trying
many different things, and can hardly understand that the only thing required is to just follow some elementary steps.

In this article, I intend to create my own simple Hibernate-powered application that will be
able to "understand" CMT. As mentioned above, I failed on my first attempt, but the second
came together easily. I hope that the stages described in this article
will help to those who are stuck on this problem.

Software Requirements

Before I begin, let me lay out what software I used, so you will be able
to duplicate my results. I was using the JBoss 3.2.3
application server, the MySQL 4.0.16 database server, and
Hibernate 2.1.6. You will also need to use
MySQL Connector/J 3.0.11 as the JDBC driver, and
Apache Ant 1.6.2 to compile, assemble, and deploy our source code, which is
available in the Resources section below. Apart from that, I have used
Together Designer Community
Edition to create simple UML diagrams; you do not really need it.

In this article, I'm not spelling out what
I expect from the reader. If you are interested in this problem, you probably are already familiar
with the relevant technologies.

High-Level View of our Application

We will start with understanding what our application will looks like, and what we will really need to store in the database (i.e., our persistence data). Figure 1 shows what our classes look like.

Figure 1
Figure 1. Diagram of Person and Pet classes

I suspect you can pick up everything from a single glance at the diagram. Thanks to the
popularity of the famous "one-to-many
Person-Pet" structure, you'll probably be very comfortable with this
arrangement, leaving you free to concentrate on understanding other important concepts later.

Examine the Code

Of course, the the entire application will be more complex than just two classes. We will also have
one EJB stateless session bean with a local client view:

Figure 2
Figure 2. The TranhiberEJB (short for "TRANsaction HIBERnate") Enterprise JavaBean

In the above diagram you can see that there are only three business methods in our EJB.
There's doFindPerson(...) with two arguments: first name and last name.
doAndPersonAndPet(...) and doAddPetToPerson(...) use three arguments:
first name, last name, and pet's name.

We will work with Hibernate in each of our business methods. Hibernate-related code is almost the same in all cases:

	SessionFactory sF = new Configuration()
.configure("/META-INF/hibernate.cfg.xml")
.buildSessionFactory();
Session session = sF.openSession();

The above code fragment shows how we will create a new session, and below is how
we will close it.

	session.flush();
session.close();

Even if this looks similar to many Hibernate tutorials, you may notice one
very important difference: there is no Transaction tx = session.beginTransaction();
and no tx.commit() operations.

The explanation is simple: CMT helps us eliminate explicit transaction demarcation calls in our code.
Instead, transaction demarcation is controlled by a deployment-specific descriptor.
We set transaction attributes for each of our business methods in /META-INF/ejb-jar.xml,
requiring each method to run with a new container-managed transaction. If the method is called with an
existing transaction context, the caller's transaction is suspended until this method completes.

	...
<container-transaction>
...
<trans-attribute>RequiresNew</trans-attribute>
</container-transaction>
...

Additionally, we force Hibernate to use pool resources such as database connections and specify this in the
/META-INF/hibernate.cfg.xml file:

	...
<property name="connection.datasource">
java:/myDS
</property>
<property name="transaction.manager_lookup_class">
net.sf.hibernate.transaction.JBossTransactionManagerLookup
</property>
<property name="transaction.factory.class">
org.hibernate.transaction.JTATransactionFactory
</property>
...

Also, this way we enable Hibernate integration with JTA, allowing the server's TransactionManager to
integrate fully with the container-managed transactions. Hibernate supports this by itself.
net.sf.hibernate.transaction.JBossTransactionManagerLookup works for JBoss server and
net.sf.hibernate.transaction.WeblogicTransactionManagerLookup for WebLogic server.
net.sf.hibernate.transaction.JTATransactionFactory delegates the use of JTA, and this is
exactly the thing we need for CMT.

We specify the low-level details of the datasource pool (myDS) in the /META-INF/mysql-ds.xml
file for our JBoss server, or create it manually via its administration console for WebLogic.

Our application will also have a web part. It will consists of two JSP pages. On the first one,
index.jsp, the user enters the first and last name of a person, and the name of his or her two pets, and then clicks on Submit. We are not limited to only adding exactly two pets; it's just that our JSP page was created to ask you only for two pets. But it's a simple page to make, and you
can easily modify it to ask you for as many pets as you like.

Next, the user is taken to the
the second page (create.jsp), which just responds that everything is done. To make
our application as simple as possible, I do not do any web output. This is appropriate, since our
business logic methods do not return any values; they just do their own business. I want to keep
the source clean, tiny, and understandable. You will be able to see a lot of debugging message
and detailed informtion in your JBoss logs, and you should see changes in your database tables.

The sequence of steps in our application is as follows: the user fills out the form and
submits it, the JSP page invokes business methods on the EJB stateless session bean, and this EJB
Hibernates the data. As you probably already figured out, we have beautifully
replaced container-managed persistence (CMP) EJB entity beans with Hibernate. Deviating
from our article's topic, I should note that there are a lot of disputes in the J2EE community on the question
of which is better Hibernate or CMP EB EJBs. Personally I have a neutral opinion. Certainly,
Hibernate is an extremely good O/R mapping tool: it's simple and fast. Nowadays, unfortunately and as
implausible as it might sound,
Hibernate is also much more portable between different containers than EJB is.
Still, it's important to remember that Hibernate is not an analogue of EJB technology. EJB is
supported by all application servers (by definition, they must support EJBs). I hope that EJB3s will have the full power of Hibernate and still remain a standard for all application servers. In this
case, that will be a powerful union!

Let's get back to our application. The code is easy to understand, and I think that the most
important parts of it have already been mentioned. You can unzip tranhiber_src.zip into
any directory you want and learn how it's organized.

Configuring MySQL

Now let's start preparing our MySQL database
with tables for our application. Run C:\mysql\bin\mysql mysql (any password or important settings
will also need to be entered on this command line) and type the following:

CREATE DATABASE jbossdb;
INSERT INTO db VALUES ('localhost','jbossdb',
    'userjboss',
    'Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y');
INSERT INTO user VALUES ('localhost','userjboss',
    password('zzz'),
    'N','N','N','N','N','N','N','N','N','N','N','N','N',
    'N','N','N','N','N','N','N','N','','','','',0,0,0);

Editor's note: Some of these lines have been split and indented to accommodate the layout
of the Java.net page. There are three commands here, and those that are too wide have been
wrapped and indented.

To have your changes take effect, use the C:\mysql\bin\mysqladmin reload command; on OSes other
than Windows, use the equivalent MySQL reload command for your platform.
This creates the database, and a configured user who will be able to access it. Now, let's create tables.
Run C:\mysql\bin\mysql jbossdb (or the equivalent for your OS) and type the following
SQL commands:

USE jbossdb;
DROP TABLE IF EXISTS example_person;
CREATE TABLE example_person (
id         int(11) NOT NULL auto_increment,
first_name text NOT NULL default '',
last_name text NOT NULL default '',
PRIMARY KEY (id)
) TYPE=InnoDB;

DROP TABLE IF EXISTS example_pet;
CREATE TABLE example_pet (
id          int(11) NOT NULL auto_increment,
name        text NOT NULL default '',
person_id   int(11) NOT NULL default 0,
PRIMARY KEY (id)
) TYPE=InnoDB;

As you can see, we are creating tables of the InnoDB type. That's important. MySQL's default type is
MyISAM. MyISAM is an improved replacement for ISAM, but it's a non-transactional storage
engine and it follows a different paradigm for data integrity, which MySQL calls
"atomicoperations." Again, it's non-transactional, meaning that it does not support transactions.
Obviously, we need a transactional table type, and in MySQL that means InnoDB.

At any rate, the database configuration-creation steps are finished.
In case if you've changed the database name, table
names, or user access info, you will have to modify JBoss' datasource configuration file, located in
the file ejb-jar/META-INF/mysql-ds.xml.

Compiling Your Code

Please, check the Ant build file build.xml. Depending on your software installation
paths, you may need to change the jboss.home, hibernate.home, and
connector.home properties. They are on the top of the file. If you will use a significantly
different Hibernate version, you may also have to change the .jar library names, which would
require more extensive changes in the ant Build file. In common cases, you will only have to
change the three properties mentioned above, and nothing more.

With all of these steps completed, you can compile, assemble, and deploy your application. To do this,
just type ant all in your source directory. To deploy into the JBoss default configuration, you
can type ant deploy. Very easy, isn't it? In both cases, you will get our application
packaged into the file tranhiber.ear.

Testing Ready Application

Good. Well, you can point your favorite browser to the URL http://localhost:8080/web/, and
work with our application. Add a few persons with pets (by submitting HTML forms), and then you can open
C:\mysql\bin\mysql jbossdb and execute the following SQL query:

USE jbossdb;
SELECT example_person.first_name,
example_person.last_name,
example_pet.name
FROM example_person
LEFT JOIN example_pet
ON example_pet.person_id=example_person.id;

This will bring up a list of the just-added persons and their pets. You did that! And that's
everything you need. Our application is working in CMT! Isn't that nice? Now I bet I can
anticipate your next question: "How can we check that CMT is working?"
Very, very easily. Just edit the ejb-jar/com/prohorenko/example/ejb/TranhiberBean.java file
and uncomment the following line:

ctx.setRollbackOnly();

This will cause transactions be rolled back, in any case. Test it: compile, assemble, and deploy
the application once again, restart JBoss server (I had troubles when I didn't restart the server; I'm not sure why) and go to the URL again and fill in a few forms. This time, the people and pets you have
added do not appear in the database.

As you see, everything is simple. Dig deeper into the code, and I am sure that you will
be able to add numerous features of your own.

It took virtually nothing to get Hibernate, out of the box, working in CMT. I didn't add a single
line of code. All we needed to do was to properly configure our application environment.

Afterword

In conclusion, I would like to mention that if you are using the BEA WebLogic 8.1 application
server, you can still work with the example described in this article. You just will need to
configure a Connection Pool and Data Source with the help of your
server's BEA WebLogic Administration Console. When you're done, just do the following:

  1. Remove the ejb-jar/META-INF/hibernate.cfg.xml, ejb-jar/META-INF/jboss.xml,
    and ejb-jar/META-INF/mysql-ds.xml files.
  2. Use the configuration files from the file tranhiber_srcwl81.zip (see
    Resources below) instead of the ones you just removed.

This was tested and seems to work correctly on my BEA WebLogic Server 8.1 on the Windows platform.

Resources

width="1" height="1" border="0" alt=" " />
Olexiy Prohorenko is a Sun Certified Enterprise Architect whose areas of interests include Web software architecture and development of software with frequently changing requirements.
Related Topics >> Databases   |   EJB   |