7.1 Overview
By this chapter, we all know that Hibernate requires database configurations and mapping files in order to understand the database details and the object to tables mapping. We have discussed the details of database configuration in earlier chapters and in this chapter, we will discuss mapping documents and Hibernate Types in detail.
7.2 Primary Key
In a relational database primary keys play an important role. Primary key has to be unique and cannot have a null value. The primary key is also used to establish a relationship between multiple tables. When we persist Java objects using Hibernate, primary key has to be generated. Hibernate supports several approaches to generate a primary and the Java property corresponding to primary key is known as an identifier.
We can specify the identifier in mapping documents using <id> tag. Id element supports below attributes
- name – is the name of the property of object which will be used for primary key.
- type – is the data type of field.
- column- column name in table to hold primary key.
- generator class – generator class implementation which will be used by hibernate to generate the primary key.
Sample definition of primary key in mapping file looks like below
<id name="userID" column="user_id" type="long"> <generator class="native"> </generator> </id>
For the above definition, there will be one property of type long with name “userID” in Java class. We can ignore the property from Java object and name attribute from < id> tag in case we do not need to use primary key in our application logic and hibernate will generate and store it in database but this is not recommended at all.
Hibernate has several identifier generator modules. Below are the details of the modules.
- assigned – this is the default identifier generation strategy (in case generator tag is not defined). With this approach, its application's responsibility to generate and assign the primary key in identifier property.
<id name="userID" column="user_id" type="long"> <generator class="assigned"> </generator> </id>
- identity – this approach is database dependent which forces us to make sure about the database with which application is interacting supports identity or not before using. In this case database generates the unique value and not by Hibernate.
<id name="userID" column="user_id" type="long"> <generator class="identity"> </generator> </id>
- sequence – this approach is database dependent because not all databases supports sequence. This forces us to make sure about the database with which application is interacting supports sequence or not before using. Hibernate gets the next value using the sequence.
If we did not define any sequence in the database, then, hibernate creates a one with name “HIBERNATE_SEQUENCE”. For auto creation of sequence , hbm2ddl.auto must be enabled. Alternatively, we can pass the name of sequence which has been created in database explicitly.
Below tag will create a sequence with name “HIBERNATE_SEQUENCE”
<id name="userID" column="user_id" type="long"> <generator class="sequence"> </generator> </id> To pass the sequence name we can use param tag <id name="userID" column="user_id" type="long"> <generator class="sequence"> <param name="sequence">user_id_seq</param> </generator> </id>
- increment – this approach is database independent and increments the maximum value by one and use as identifier .In case there is no row in database , then for the very first row ,value will be 1.
<id name="userID" column="user_id" type="long"> <generator class="increment"> </generator> </id>
NOTE: identity and sequence looks similar but there are some differences.
- With identity approach , database generates the value and not Hibernate where as in case increment , hibernate generates the value.
- With increment approach , hibernate fires a select query to get the max value and does increment on it where as in case of identity , there is no select query
- Increment approach is database independent where as identity is database dependent.
- hilo (high/low ) – this approach is database independent and a very efficient way of generating identifier. This approach requires a separate table and a column with default table name as “hibernate_unique_key” and column name as “next_hi” . We can pass custom table and column name as well.
<id name="userID" column="user_id" type="long"> <generator class="hilo"> </generator> </id>
To pass custom table and column name
<id name="userID" column="user_id" type="long"> <generator class="hilo"> <param name="table">custom table name</param> <param name="column">custom column name </param> </generator> </id>
- native – this approach uses other generator modules like identity , sequence or hilo depending on the database application is connecting to.
<id name="userID" column="user_id" type="long"> <generator class="native"> </generator> </id>
7.3 Database identity with Hibernate
Database identity is nothing but a primary key of a database and is very important. With Hibernate as a persistent framework, we can get hold of the primary key (database identity) with any one of the below two approaches.
- Using the value of Java object property used as identifier.
- Can get the value using Session API [ Session.getIdentifier(Object) ] if Java object does not expose identifier property.
Note: Database identifier must not be changed once generated and assigned so should we define the setter and getter method of identifier as public? We might need to know the value of primary key in application logic so ideally we can define the get method as public and set method as private. This approach is fine when the identifier is generated by hibernate and not by application, but we have to define set as public in case application is generating the identifier. [ we have to define a setter method even if it is private ]
7.4 Mapping Document Details
Lets take an example of Student POJO class to understand hibernate mapping file.
Student.java
package com.hibernate.tutotial public class Student { private int id; private String name; private String emailAddress; public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getEmailAddress() { return emailAddress; } public void setEmailAddress(String emailAddress) { this.emailAddress = emailAddress; } }
Corresponding to Student.java lets define STUDENT_INFO table
create table STUDENT_INFO (
id INT NOT NULL auto_increment,
name VARCHAR(20) default NULL,
email VARCHAR(20) default NULL,
PRIMARY KEY (id)
);
Mapping Document ( hbm.xml )
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="com.hibernate.tutorial.Student" table="STUDENT_INFO"> <id name="id" type="int" column="id"> <generator class="native"/> </id> <property name="name" column="name" type="string"/> <property name="emailAddress" column="email" type="string"/> </class> </hibernate-mapping>
Details
- First three lines of Mapping file are the DOC type
- <hibernate-mapping> is the root element of the file
- <class> tag is used to map one Java object. We can define multiple <class> tag in a single hbm file if we want to (one per Java object) . For example, we have student and book persistent objects and we want to define them in a single mapping document
- “name” attribute of <class> tag defines the qualified path of Java object
- “table” attribute defines the table name in which object needs to persist
- <id> tag is used for database identifier. (refer Section 7.2 for more details)
- For each property of an object , one <property> tag is defined.
- “Name” attribute defines the property name , “column” defines the column name to which it maps and “type” is the data type.
7.5 Data Type Mapping
As we know Java and database supports several data types and there should be some mapping required. In mapping document we use the attribute “type” to define the data type. Below is the complete list of data type mapping.
Mapping type | Java type | ANSI SQL Type | |
Integer | int or java.lang.Integer | INTEGER | |
Long | long or java.lang.Long | BIGINT | |
Short | short or java.lang.Short | SMALLINT | |
Float | float or java.lang.Float | FLOAT | |
Double | double or java.lang.Double | DOUBLE | |
big_decimal | java.math.BigDecimal | NUMERIC | |
character | java.lang.String | CHAR(1) | |
String | java.lang.String | VARCHAR | |
Byte | byte or java.lang.Byte | TINYINT | |
Boolean | boolean or java.lang.Boolean | BIT | |
yes/no | boolean or java.lang.Boolean | CHAR(1) ('Y' or 'N') | |
true/false | boolean or java.lang.Boolean | CHAR(1) ('T' or 'F') | |
Date | java.util.Date or java.sql.Date | DATE | |
Time | java.util.Date or java.sql.Time | TIME | |
timestamp | java.util.Date or java.sql.Timestamp | TIMESTAMP | |
calendar | java.util.Calendar | TIMESTAMP | |
calendar_date | java.util.Calendar | DATE | |
binary | byte[] | VARBINARY (or BLOB) | |
text | java.lang.String | CLOB | |
serializable | java.io.Serializable implementation | VARBINARY (or BLOB) | |
clob | java.sql.Clob | CLOB | |
blob | java.sql.Blob | BLOB | |
class | java.lang.Class | VARCHAR | |
locale | java.util.Locale | VARCHAR | |
timezone | java.util.TimeZone | VARCHAR | |
currency | java.util.Currency | VARCHAR |