Implementation of object-relational mapping (O/R mapping) is a general need for many projects in software development. Usually, work with the automation process of data storage is very boring, and at manual implementation there is a danger of mistakes and bugs. Also, to add constantly varying requirements, it is necessary for the developer to take into account the complex process of synchronization of all initial code and data storage structures. More than that, taking into account the necessity of portability of application between platforms, it all becomes even more complex and confusing.
Hibernate sounds like the best solution. It allows us to store the data in constant storehouse without serious consequences, thus a choice of such as storehouse, installation, and configuration do not make big difficulties. Hibernate allows us to store objects of any kind; therefore, it is not necessary for an application to know that its data will be kept with Hibernate. Clearly, with help of Hibernate we can not only keep the data in a storehouse, but also update and delete the data.
Preparing the Workspace
To begin, we will need to download the Hibernate distribution from http://www.hibernate.org. We will use version 2.1.4. As a database, we will use MySQL version 4.0.16, which also can be downloaded from http://www.mysql.com. I need to mention that Hibernate also supports not only MySQL but different other open-source and commercial databases; for example, Hypersonic SQL, PostgreSQL, Oracle, DB2, and others.
After you download all necessary packages, you must adjust your environment to include, generally, everything that we need to make it include all downloaded JAR files into our CLASSPATH. It should consist of at least two files: hibernate2.jar from a directory in which you have unpacked Hibernate, and mysql-connector-java-3.0.9-stable-bin.jar (which is JDBC Connector/J to MySQL database server; it could be downloaded from the MySQL Web site). Hibernate requires few more additional libraries that are in a directory, called <hibernate-dir>/lib /, where <hibernate-dir> is a directory with the unpacked Hibernate package. From this directory, we do not need all JAR files, but it is better to use them all now. Before we start work with Hibernate, we shall formulate a problem all over again and we try to solve it with the help of Hibernate.
Formulate a Problem
Certainly, every developer has faced the problem of creating a client servicing system. The general circuit can look as follows: We create an object for Order, we set into it Product objects, which by then becomes Order Items, and then we save Order.
To build a database structure, we will use the following SQL script (or you can just simply type these commands in the MySQL console client):
DROP DATABASE HIBERNATE; CREATE DATABASE HIBERNATE; USE HIBERNATE; CREATE TABLE PRODUCTS (ID VARCHAR(32) NOT NULL PRIMARY KEY, NAME VARCHAR(32) NOT NULL, PRICE DOUBLE NOT NULL, AMOUNT INTEGER NOT NULL);
Apparently, this model of the data is very simple. In the case of a data model for real projects, we first will need to add all tables of other classes, and also to define FOREIGN KEY fields, indexes, additional fields, and other items. However, for our example, such a model will be quite good.
Now, we will result a Java code that will be the Product class. For brevity, we will not give the results for the full getter/setter methods. You can add them easily.
public class Product { private String id; private String name; private double price; private int amount; public String getId() { return this.id; } public void setId(String s) { this.id = s; } // default constructor // and usual getter/setter methods ... ... ... ... ... ... }
Note: Hibernate works with any kind of Java objects if they support the JavaBeans specification.
At last, we will start using Hibernate. To keep object in a database, it is necessary to execute the following steps (actions):
- Create an object of the Product class
- Receive net.sf.hibernate.SessionFactory with the use of net.sf.hibernate.cfg.Configuration, right at the beginning of the application.
- Open a net.sf.hibernate.Session session by calling the SessionFactory.openSession() method.
- Keep an object of the Product class and close the session.
However, before you start these steps, you should define some configuration files with which Hibernate will “know” where it is necessary to keep your objects and how your objects will be displayed in the chosen storehouse (the database table).
The first configuration file is a hibernate.properties file. This file defines which database we want to us, a name of the user and the password, and a set of other options. In our case, the database will be MySQL, and the hibernate.properties file will contain the next lines:
hibernate.connection.username=green hibernate.connection.password= hibernate.connection.url=jdbc:mysql://localhost/hibernate hibernate.connection.driver_class=com.mysql.jdbc.Driver hibernate.dialect=net.sf.hibernate.dialect.MySQLDialect
The next necessary file is Product.hbm.xml. It is an XML file that defines how Java objects are kept in a database. In this file, we determine the data in what table of our database and how it will be written down, what field in which column of the table, and so forth. Here is the code for our Product.hbm.xml file:
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd"> <hibernate-mapping> <class name="Product" table="products"> <id name="id" type="string" unsaved-value="null"> <column name="id" sql-type="char(32)" not-null="true"/> <generator class="uuid.hex"/> </id> <property name="name"> <column name="name" sql-type="char(255)" not-null="true"/> </property> <property name="price"> <column name="price" sql-type="double" not-null="true"/> </property> <property name="amount"> <column name="amount" sql-type="integer" not-null="true"/> </property> </class> </hibernate-mapping>
The line <class name = "Product" table = "products"> means that we are going to display a class with the name Product in the table products.
The <id> element and its affiliated elements set the communication between our Java class and a database.
The <property> elements define in what columns each of fields will be kept, and also its type, a name, etc.
The <generator class = "uuid.hex"/> element, at first glance, is not understandable. Knowing that is one of the affiliated elements of an <id> element, its purpose becomes clearer: Because our application does not know how the data will be kept in a database, the substitute key is necessary for us. This key will not have any value in the business logic of the application. It only helps Hibernate manipulate objects. Again, a created object of the Product class has no certain ID—Hibernate will create it for us. In our case, we have chosen UUID lines; however, there are many various predetermined ID generators. Besides, you also can write you own. For more detailed information, I suggest you to take a look at the documentation delivered with Hibernate.
Storing New Products
Now that we have these two files, we can create an algorithm for storing the Product class in a database with the help of the following code:
import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.Transaction; import net.sf.hibernate.cfg.Configuration; // Usage: // java InsertProduct <title> <amount> <price> public class InsertProduct { public static void main(String[] args) throws Exception { Product p = new Product(); p.setName(args[0]); p.setAmount(Integer.parseInt(args[1])); p.setPrice(Double.parseDouble(args[2])); Configuration cfg = new Configuration().addClass(Product.class); SessionFactory sf = cfg.buildSessionFactory(); Session sess = sf.openSession(); Transaction t = sess.beginTransaction(); sess.save(p); t.commit(); sess.close(); } }
To run our program and store a new object, use this:
java InsertProduct Book 100 600
With the help of the MySQL console client (mysql.exe), you can take a look at the products table’s contents. Use the following commands:
USE hibernate; SELECT * FROM products;
Then you supposed to see table with the only one record:
ID | NAME | PRICE | AMOUNT | 3f138041f947f4320ff90764f8340f01 | Book | 600 | 100 |
Now you are convinced that the information on the object of the Product class has been successfully stored in our database, and thus we have not written any SQL expression.
Finding and Loading Product Objects
Searching for and loading existing objects is a very simple task for Hibernate. With the use of its query language, we very easily can take an object (or set of objects) by its ID, a name, or other properties. We also can take either the whole object or its certain properties separately. Let’s consider the FindProductByName class:
import java.util.List; import net.sf.hibernate.Hibernate; import net.sf.hibernate.Session; import net.sf.hibernate.SessionFactory; import net.sf.hibernate.cfg.Configuration; import Product; // Usage: // java FindProductByName <title> public class FindProductByName { public static void main(String[] args) throws Exception { String query = "SELECT product " + "FROM product IN CLASS test.hibernate.Product " + "WHERE product.name=:name"; String name = args[0]; Configuration cfg = new Configuration().addClass(Product.class); SessionFactory sf = cfg.buildSessionFactory(); Session sess = sf.openSession(); List list = sess.find(query, name, Hibernate.STRING); if (list.size() == 0) { System.out.println("Product [" + name + "] not found!"); System.exit(0); } Product p = (Product) list.get(0); sess.close(); System.out.println("Found product: " + p); } }
Let’s consider the most interesting places of the above-mentioned code:
In the code, there is a query with a WHERE expression. All is very similar to the usual SQL format.
Initialize Hibernate as we did in the first example. This time, we already have created files of a configuration and mapping (XML file). The sess.find() method carries out the query and establishes the name of a product given to it, as an argument for the search with the Hibernate.STRING type.
As a result, we will get an object of the java.util.List class, filled with Product objects from a database that satisfies the search conditions.
With the Product p = (Product) list.get (0); expression, we take the first found object.
Updating and Removing Products
By now, you already should have a decent understanding of how Hibernate works. Therefore, now we will make our examples hardly less in size, having cleaned out all repeating and unimportant items.
Following is the example of how to increase all Products’ prices by 10% in one transaction. We should write the following:
... double percentage = Double.parseDouble(args[0])/100; sess = sf.openSession(); Transaction t = sess.beginTransaction(); Iterator iter = list.iterator(); while (iter.hasNext()) { Product p = (Product) iter.next(); p.setPrice(p.getPrice() * (1 + percentage)); sess.saveOrUpdate(p); } t.commit(); sess.close(); ...
And, at last, for removal of a Product, we should cause a method sess.delete(product). Please, do not overlook also carrying out commit() at the end of transaction to confirm changes if only certainly the option autocommit in your database is turned on.
Afterword
This article shows what kind of tool is Hibernate, and also shows a few advantages. From it you have learned how simple is to keep any kind of Java objects, and then to manipulate them. Opportunities for Hibernate are incomparably wider. I also just need to mention that Hibernate arms the developer with very a powerful object-oriented query language, HQL, which has a set of various useful features.