In this chapter, we will cover the following recipes:
Getting the required libraries for hibernate
Creating a hibernate persistent class
Providing an XML-based hibernate mapping
Providing an annotation-based hibernate mapping
Providing a hibernate configuration using an XML file
Providing a hibernate configuration using a properties file
Configuring hibernate programmatically
In this chapter, we will take a look at how the hibernate and ORM (Object-relational Mapping) frameworks work, how to configure hibernate in different ways, and the libraries that are required for the hibernate application. An essential part of the application is the hibernate configuration. Through the configuration, we can provide database information to the hibernate engine, such as the database host, port, username, password, the database name, the drive class, and so on.
In the older era of Java development, developers used some methodologies to persist data. To persist data means to save or store data in some storage medium by maintaining it in a certain state. Once the data is successfully persisted, it can be used at any given time. A database is the more preferable storage medium for a transactional operation. Usually, we use JDBC (Java Database Connectivity) to perform such operation with the database.
If we use the JDBC operation, we need to work a bit harder and take care of the following processes:
Opening a database connection
Maintaining an open connection
Building a query
Executing a query
Getting a response to the query
Mapping the query response with the custom classes
Closing the database connection
To avoid this hectic process, we can use the ORM tools available in the market. ORM stands for Object Relation Mapping. It works as a bridge between the application and database by simplifying the communication between them.
The benefits of the ORM framework are as follows:
It reduces the development time/cost.
It speeds up the development.
It provides us with portability. Hibernate supports multiple databases, so there is no need to write a database-specific code.
This is a useful feature of hibernate. Generally, all databases have their own syntax made up of Data Definition Language (DDL) or Data Manipulation Language (DML) statements. If we used JDBC, we would need to write a database-specific code as our database is changed. However, hibernate gets rid of the developer's headache by handling this issue.
The syntax of a query may be different for different database parameters; still, hibernate works in the same way for all types of databases. Hibernate's term dialect
helps achieve this type of functionality. The implementation of the dialect
class is provided by the database provider to inform hibernate about the syntax of this particular database.
Some useful features of hibernate are as follows:
Code reusability
Transaction management
Efficient collection/custom classes mapping
The caching mechanism supported by hibernate
To work with hibernate, we need a JAR (Java Archive) file provided by hibernate. Here, we will see how to download the hibernate core distribution. There are multiple ways to get the required libraries; here, we will consider two of them:
Manually downloading
Using Maven
The first and most basic JAR file needed is a JDBC driver. The JDBC driver is a bridge or an API between Java and the database. The JDBC driver provides us with the generic classes that will help us communicate with the database. Generally, the driver is either provided by the database provider or developed by communities; however, you have to get it yourself. This also depends on the type of the database you are using. As we will use the MySQL database for this book, we will use the Mysql-Connector.jar
file.
Let's come back to the library section. Apart from JDBC, you will need the JAR files for hibernate. Perform the following steps:
Download the hibernate core distribution from http://hibernate.org/orm/.
Now, place all the files in your classpath if you plan to run a standalone program and put them in the lib
folder if it's a J2EE project.
If you use the Maven project, it would get rid of your headache of finding all the JAR files for hibernate and the dependent libraries. You can use the following Maven configuration for hibernate.
Enter the following code into the pom.xml
source file to show the dependency mapping of hibernate and MySQL in pom.xml
:
… <dependencies> <!-- MySQL connector --> <dependency> <groupId>MySQL</groupId> <artifactId>MySQL-connector-Java</artifactId> <version>MySQL-connector-version</version> </dependency> <!-- Hibernate framework --> <dependency> <groupId>hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>hibernate-version</version> </dependency> <dependencies>
Using this method, Maven will download all the required JAR files related to hibernate and the dependent libraries required for hibernate.
As discussed in the Preface, the developer will be dealing with objects at every step of development. Also, when we use hibernate, we don't need to work on a core SQL query. Here, we will create a POJO (Plain Old Java Object) in Java, which represents a table in the database.
By POJO, we mean that we will create a Java class that satisfies the following requirements:
It needs to have a default constructor that is persistent.
It should contain the id
attribute. ID is used to identify the object and is mapped with the primary column of a table.
All attributes should have Getter
and Setter
methods, such as getXXX
and setXXX
where xxx
is a field name.
We will now create a persistent class and name it Employee
. The following table shows a representation of the Employee
class:
Employee |
---|
|
|
|
Create the
Employee.java
class and place the following code in the class:
public class Employee{ private long id; private String firstName; private double salary; // other fields // default constructor public Employee() { } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } // // Getter and setter for other fields... // }
Now the preceding class satisfies all the requirements listed before to be a persistent class.
The preceding class now contains the following:
The default Employee()
constructor
The id
attribute, which is the primary column of the table and can be used to uniquely identify an entry
The individual getters and setters in all the attributes (id
, firstName
, and salary
)
Now, let's see how to design a POJO for tables having references between the Department
and Employee
tables:
The following code is the definition for the Department
class in Department.java
:
public class Department{ private long id; private String deptName; //default constructor public void Department(){ } //getters and setters public long getId() { return id; } public void setId(long id) { this.id = id; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } }
The following code is the definition for the Employee
class in Employee.java
:
public class Employee{
private long id;
private String firstName;
private double salary;
private Department department; // reference to Department.
//default constructor
public void Employee(){
}
//getters and setters
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Department getDepartment(){
return department;
}
public setDepartment(Department department){
this.department = department;
}
}
Downloading the example code
You can download the example code files for all Packt books you have purchased from your account at http://www.packtpub.com. If you purchased this book elsewhere, you can visit http://www.packtpub.com/support and register to have the files e-mailed directly to you.
In the preceding recipe, you learned how to create a POJO. Now we will consider how to create the configuration for hibernate. There are multiple ways of mapping, and this is one of them.
Generally, the configuration provides the following information:
The mapping between the POJO and the database table
The mapping between the POJO property and the database table column
The definition of the primary key column
The definitions of the foreign key column and relationships such as one-to-one, one-to-many, many-to-one, many-to-many with another table, and so on
Constraints such as not-null, formula, lazy, cascade, and so on
The definitions of the length, the data type of the column, the formula, and so on
To provide hibernate mapping based on XML, perform the following steps:
Ensure that the basic structure of the configuration file is as follows:
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD X.X//EN" "http://hibernate.sourceforge.net/hibernate-mapping-X.X.dtd"> <hibernate-mapping> ... </hibernate-mapping>
Create a XML file and name it Employee.hbm.xml
. Then, add the configuration, as shown in the following code:
<hibernate-mapping> <class="Employee" table="employee"> <id name="id" type="long" column="id"> <generator class="increment" /> </id> <property column="firstName" name="firstName" /> <property column="salary" name="salary" /> <!-- other properties mapping--> </class> </hibernate-mapping>
Here, we named the mapping file Employee.hbm.xml
. However, while developing, there is no strict rule regarding the naming convention. Here, we will create a new hbm file for each POJO; for example, we created an Employee.hbm.xml
file for the Employee.java
class. Another common practice we will use here is to create one hbm file for the module, map all the classes of this module in the same mapping file, and name this file modulename.hbm.xml
.
Here, <hibernate-mapping>
is a root element that contains all the <class>
elements. The <class>
tag contains the following attributes:
name
: This specifies the FQN (Fully Qualified Name) of the Java class.
table:
This denotes the database table used for the class defined in the name
attribute.
The <generator>
tag in the <id>
tag is used to generate the value of the primary key. There are many types of built-in generators provided by hibernate, such as identity
, sequence
, hilo
, and so on.
The <id>
tag defines the primary key column for the database table. It contains the following attributes:
name
: This specifies the Java class attribute name
column
: This denotes the database table's column name
type
: This specifies the data type of the column that will help hibernate during the creation and retrieval of the automatic table
size
: This denotes the size attribute that defines the length of the table's column
The type
attribute in the <id>
and <property>
tags helps hibernate to create a table structure automatically for us using the hbm mapping.
Usually, we create a mapping file called hbm (hibernate mapping). It is a normal XML schema file that contains custom hibernate XML tags. This helps the hibernate engine to map the class to the table and the class
field to the table
column, along with the given attributes.
All the mapping definitions for hibernate are bundled under the <hibernate-mapping> ... </hibernate-mapping>
tag. In <hibernate-mapping> ... </hibernate-mapping>
, we can add any number of class-to-table mapping definitions.
Now, let's create the XML mapping for the POJO having a reference with another POJO. Here, we will create two different mapping files. To achieve this using an XML-based mapping, we have to create different class mappings for each POJO that has a dependency.
The following is a code that represents the mapping for the Department
class. The mapping is in the Department.hbm.xml
file:
… <hibernate-mapping> <class name="Department" table="department"> <id name="id" type="long" column="id"> <generator class="auto" /> </id> <property column="deptName" name="deptName" /> <!-- other properties mapping --> </class> </hibernate-mapping> …
Next, we will create a mapping for the Employee
class. Its definition is present in the Employee.hbm.xml
file:
… <hibernate-mapping> <class="Employee" table="employee"> <id name="id" type="long" column="id"> <generator class="auto" /> </id> <property column="firstName" name="firstName" /> <property column="salary" name="salary" /> <many-to-one name="department" class="Department" > <column name="department"/> </many-to-one> <!-- other properties mapping--> </class> </hibernate-mapping> …
In the preceding example, we mapped the Department
entity with the Employee
entity. This will refer to the department
column in the employee table. This means that it will create a foreign key that is referenced to the department table.
Here, we will use the <many-to-one>
relationship, which means that either many employees are connected with one department, or one department is used by many employees.
The properties are as follows:
not-null="true
": This property prevents the user from inserting the NULL value in the column
lazy="true
": This feature helps us while retrieving data using hibernate
The two possible options for lazy
are true
and false
. In our example, Employee
is a parent class, whereas Department
is a child of the Employee
class. Now, while fetching, if we set lazy
as true
, it means that it will only fetch employee records. No child records will be fetched with Employee
, and hibernate will use a separate query if we try to access a child record, which is employee.getDepartment()
. If we set lazy
as false
, hibernate will fetch the child records with the parent, which means that the department information will also be fetched, along with that of the employee. Hibernate will use a join query to fetch the child records.
When we choose the annotation-based way to provide a configuration, we don't need to create any hibernate mapping (usually *.hbm. xml
) file. Hibernate provides the annotations that we can directly write to the POJO, and we can provide all the mappings via the classes, which we can do using the previous XML file.
Now, let's create the class that contains the annotation-based mapping. As we used the Employee
class to provide XML-based mapping here, we will use the same class with annotations:
Represent the annotation-based mapping for the Employee
class in Employee.java
, as shown in the following code:
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table(name="employee") public class Employee{ @Id @Column(name="id") @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(name="firstname") private String firstName; @Column(name = "salary") private double salary; // default constructor public Employee() { } public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } }
Now, compare the annotations with the XML mapping to gain a better understanding of the difference between the two methods.
In the annotations, we will write the following code:
@Entity @Table(name="employee") public class Employee{...}
Now, check the XML mapping for the same here:
<class name="Employee" table="employee">
The keywords used in the preceding class are described below:
@Entity
: This annotation declares the class as an entity bean.
@Table
: We can set this annotation at the class level only. You can provide the name
attribute, which is considered as a database table name. You can also just write @Table
without any attribute; in this case, the class name is considered as a table name by hibernate.
In the annotations, we will write the following code:
@Id @Column(name="id") @GeneratedValue(strategy = GenerationType.AUTO) private long id;
Now, check the XML mapping for the same in the following code:
<id name="id" type="long" column="id"> <generator class="auto" /> </id>
The annotations used in the preceding code are described below:
@Id
: This annotation declares the property to be an identifier property, and this is used as a primary key for the table.
@Column
: This annotation is used to define the column
for the table. Here, we used name="id"
, meaning that hibernate considers the column name to be "id"
. You can also write @Column
without any attributes; in this case, the property name is considered to be a column name for the table.
@GeneratedValue
: Using this annotation, we can provide information to hibernate on how to generate a value for the primary key column. Here, we will use strategy = GenerationType.AUTO
, which means that hibernate uses the autoincrement value for the id
column. If not provided, hibernate uses the most appropriate generation strategy.
In the annotations, we will write the following code:
@JoinColumn(name="department") @ManyToOne private Department department;
Now check the XML mapping for the same in the following code:
<many-to-one name="department" class="Department"> <column name="department"/> </many-to-one>
The annotations used in the preceding code are described below:
@JoinColumn
: This annotation notifies hibernate that this is a reference column.
@ManyToOne
: This annotation defines the relation between the referenced tables. Here, we have used many-to-one, meaning that one department can be mapped with multiple employees.
In the previous section you learned how to reference a class using hibernate. In this section, we will take a look at how to provide the reference of one class in another class in detail.
Do not get confused when writing Employee.java
again to show the reference object annotation.
The following code represents the annotation-based mapping for the Employee
class that has the reference field in Employee.java
:
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.ManyToOne; import javax.persistence.Table; @Entity @Table(name="employee") public class Employee{ @Id @Column(name="id") @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column(name="firstname") private String firstName; @Column(name = "salary") private double salary; @JoinColumn(name="department") @ManyToOne private Department department; // default constructor public Employee() { } // getters & setters public long getId() { return id; } public void setId(long id) { this.id = id; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public double getSalary() { return salary; } public void setSalary(double salary) { this.salary = salary; } public Department getDepartment(){ return department; } public setDepartment(Department department){ this.department = department; } }
The following code represents the annotation-based mapping for the Department
class in Department.java
:
import javax.persistence.Column; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Table; @Entity @Table //If name is not supplied hibernate will use class name as table name public class Department{ @Id @Column //If name is not supplied hibernate will use field name as column name @GeneratedValue(strategy = GenerationType.AUTO) private long id; @Column private String deptName; public long getId() { return id; } public void setId(long id) { this.id = id; } public String getDeptName() { return deptName; } public void setDeptName(String deptName) { this.deptName = deptName; } }
In the preceding discussion, you learned how to create a class and provide a mapping to hibernate. These mappings show the relationship between the Java class and the database table.
Still, hibernate requires some information about the database, host, and port, on which the application is running. It also requires information about the username and password to access the database. Hibernate uses this set of configurations to connect to the database.
This is a traditional way to provide the hibernate configuration; however here, we need to create an XML file, generally called hibernate.cfg.xml
, in the classpath. There is no strict rule to name it hibernate.cfg.xml
; we can give it a custom name instead of hibernate.cfg.xml
, in which case, we need to instruct hibernate to load the configuration from the particular file. Otherwise, hibernate looks for the file named hibernate.cfg.xml
in the classpath.
Now, we will create the XML file that shows the configuration for MySQL:
Enter the following code in hibernate.cfg.xml
to show the configuration for the applications:
... <hibernate-configuration> <session-factory> <property name="hibernate.dialect"> org.hibernate.dialect.MySQLDialect </property> <property name="hibernate.connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="hibernate.connection.url"> jdbc:mysql://localhost:3306/kode12 </property> <property name="hibernate.connection.username"> root </property> <property name="hibernate.connection.password"> root </property> <property name="show_sql">true</property> <property name="hbm2ddl.auto">update</property> <!-- List of XML mapping files --> <mapping resource="Employee.hbm.xml"/> <mapping resource="Department.hbm.xml"/> </session-factory> </hibernate-configuration>
Here, we will take a look at only the basic configuration parameters. Let's understand the meaning of each property:
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
: This property helps hibernate to generate database-specific SQL statements. This is an optional property. According to hibernate documentation, hibernate will be able to choose the correct implementation of dialect
automatically using the JDBC metadata returned by the JDBC driver.
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
: Using this property, we can provide the Fully Qualified Name (FQN) of the java driver
name for a particular database. The driver
class is implemented using Java and resides in the JAR file and contains the driver that should be placed in our classpath.
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/kode12</property>
: Using this property, we can provide the physical location of the database; however, the connection URL may vary from database to database. Here, we will use the MySQL database, so the URL shows jdbc:MySQL://<host/computer-name/ip>:<port>/<database name to connect>
.
<property name="hibernate.connection.username">root</property>
: Using this property, we can provide the username to access a particular database.
<property name="hibernate.connection.password">root</property>
: Using this property, we can provide the password to access a particular database.
<property name="show_sql">true</property>
: The possible value for this property is either true
or false
. This is an optional property. Hibernate logs all the generated queries that reach the database to the console if the value of show_sql
is set to true
. This is useful during basic troubleshooting. Hibernate will use the prepared statement so that it does not display the parameter in the output window. If you want to see this parameter as well, you will have to enable the detailed log. Log4j is preferred for the detailed log.
<property name="hbm2ddl.auto">create</property>
: The possible values are validate
, update
, create
or create-drop
. This is also an optional property. Here, we will set value=create
so that it will remove all the schemas and create a new one using the hibernate mapping on each build of sessionfactory
. For value=update
, hibernate will update the new changes in the database.
<mapping resource="Employee.hbm.xml"/>
: All of the mapping file is declared in the mapping
tag, and the mapping file is always named xx.hbm.xml
. We can use multiple mapping tags for multiple mapping files.
Here is an example:
<mapping resource="Employee.hbm.xml"/> <mapping resource="Department.hbm.xml"/>
Here are some useful properties used in hibernate:
hibernate.format_sql
:
hibernate.connection.pool_size
:
The possible value is always greater than 1
(value >= 1)
It limits the maximum number of pooled connections
hibernate.connection.autocommit
:
The possible values are true
and false
It sets the autocommit
mode for JDBC
This is another way to configure hibernate; here, we will create a file with the .properties
extension. Usually called hibernate.properties
, this file is a replacement for hibernate.cfg.xml
. You can use any approach (either cfg.xml
or the properties file). However, the properties file is better for startup, and it is the easiest approach to get started quickly.
This is a simpler representation of an XML file. Hibernate searches for the XML file or the properties file at startup to find the configuration in your classpath. We can use any one of these options. You can use both of them at the same time, but this is uncommon because hibernate gives priority to the XML file over properties; the properties file is simply ignored in such cases.
The properties file looks similar to a normal text file, but the content should be in a key/value pair, which is Key=Value
.
Here is an example: hibernate.connection.driver_class=com.mysql.jdbc.Driver
.
Now, we will create a file called hibernate.properties
in our classpath and write the following properties in the file. The following code represents hibernate.cfg.xml
in the hibernate.properties
file:
… hibernate.dialect=org.hibernate.dialect.MySQLDialect hibernate.connection.driver_class=com.mysql.jdbc.Driver hibernate.connection.url=jdbc:mysql://localhost:3306/kode12 hibernate.connection.username=root hibernate.connection.password=root show_sql=true hbm2ddl.auto=update …
When we create an instance of the Configuration
class, it will look for hibernate.cfg.xml
or hibernate.properties
in our classpath. If we use a .properties
file, it'll get all of the property defined in the file, rather than create a Configuration
object.
In the preceding section, we understood XML and the properties-based configuration. Hibernate also supports the programmatic configuration. To configure hibernate using this method, we have to work on a Java code and create an instance of the org.hibernate.cfg.Configuration
class. There are multiple ways to configure hibernate.
First, write the following code:
Configuration configuration = new Configuration();
This will create an instance of the Configuration
class using hibernate.cfg.xml
or hibernate.properties
, whichever is found in the classpath.
Provide the following mapping files to the configuration:
configuration = configuration.addResource("Employee.hbm.xml"); configuration = configuration.addResource("Department.hbm.xml");
You can use an alternate way, as shown in the following code:
Configuration configuration = new Configuration().addResource("Employee.hbm.xml").addResource("Department.hbm.xml");
We can also provide a direct mapping using the class, as shown in the following code:
configuration = configuration.addClass("Department.class");
This will also look for Department.hbm.xml
.
We can also set a custom property. To set up the custom property, use the following method:
configuration.setProperty(propertyName, value);
For example, consider the following code:
configuration.setProperty("show_sql", true);
To set up multiple properties using the properties object, execute the following code:
configuration.setProperties(java.util.Properties properties);
Here is an example:
Properties properties = new Properties(); properties.put("hibernate.dialect", "org.hibernate.dialect.MySQLDialect"); properties.put("hibernate.connection.driver_class", "com.mysql.jdbc.Driver"); properties.put("hibernate.connection.url", "jdbc:mysql://localhost:3306/kode12"); properties.put("hibernate.connection.username", "root"); properties.put("hibernate.connection.password", "root"); properties.put("show_sql", "true"); properties.put("hbm2ddl.auto", "update"); configuration.setProperties(properties);
To read the mapping from the URL, you can use the following code:
configuration = configuration.addURL(java.net.URL url);
To read the mapping from the XML file, you can use the following code:
configuration = configuration.addXML(String xml);
When we select the programmatic configuration option, the Configuration
class is very important. Using the instance of the Configuration
class, we will build a SessionFactory
object, as shown in the following code:
SessionFactory sessionFactory = new Configuration().buildSessionFactory();
When the preceding code is executed, it creates a SessionFactory
object using a .properties
or .cfg
file or whichever source is provided to create the configuration.
Where there is an eBook version of a title available, you can buy it from the book details for that title. Add either the standalone eBook or the eBook and print book bundle to your shopping cart. Your eBook will show in your cart as a product on its own. After completing checkout and payment in the normal way, you will receive your receipt on the screen containing a link to a personalised PDF download file. This link will remain active for 30 days. You can download backup copies of the file by logging in to your account at any time.
If you already have Adobe reader installed, then clicking on the link will download and open the PDF file directly. If you don't, then save the PDF file on your machine and download the Reader to view it.
Please Note: Packt eBooks are non-returnable and non-refundable.
Packt eBook and Licensing When you buy an eBook from Packt Publishing, completing your purchase means you accept the terms of our licence agreement. Please read the full text of the agreement. In it we have tried to balance the need for the ebook to be usable for you the reader with our needs to protect the rights of us as Publishers and of our authors. In summary, the agreement says:
If you want to purchase a video course, eBook or Bundle (Print+eBook) please follow below steps:
Our eBooks are currently available in a variety of formats such as PDF and ePubs. In the future, this may well change with trends and development in technology, but please note that our PDFs are not Adobe eBook Reader format, which has greater restrictions on security.
You will need to use Adobe Reader v9 or later in order to read Packt's PDF eBooks.
Packt eBooks are a complete electronic version of the print edition, available in PDF and ePub formats. Every piece of content down to the page numbering is the same. Because we save the costs of printing and shipping the book to you, we are able to offer eBooks at a lower cost than print editions.
When you have purchased an eBook, simply login to your account and click on the link in Your Download Area. We recommend you saving the file to your hard drive before opening it.
For optimal viewing of our eBooks, we recommend you download and install the free Adobe Reader version 9.