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.
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, theMySQL 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.
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:
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.
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.
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
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.JBossTransactionManagerLookupworks for JBoss server and
net.sf.hibernate.transaction.WeblogicTransactionManagerLookupfor WebLogic server.
net.sf.hibernate.transaction.JTATransactionFactorydelegates 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 EJBHibernates 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.
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 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
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 fileejb-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
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 URLhttp://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 theejb-jar/com/prohorenko/example/ejb/TranhiberBean.java file and uncomment the following line:
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 donot 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.
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:
- Remove the ejb-jar/META-INF/hibernate.cfg.xml,ejb-jar/META-INF/jboss.xml, andejb-jar/META-INF/mysql-ds.xml files.
- Use the configuration files from the filetranhiber_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.
- General sample code for this article
- Configuration files for this article for WebLogic 8.1
- Enterprise JavaBeans technology
- The Java-based Apache Antbuild tool
- The object/relational persistence tool Hibernate
- The MySQL database server
- The MySQL Connector/Jdriver
- The BEA WebLogic 8.1 application server
- The JBossapplication server