CRUD using Java, Hibernate, maven and Log4j
This post
briefs about the very basics of Hibernate and how I integrated it with a simple
java project to perform CRUD operations. CRUD stands for Create, Read, Update
and Delete operations – which we end up doing in most of our day to day
programming. I forced myself to follow business object (BO) and Data Access
Object (DAO) patterns in this project so that I become habituated with both of
them. I agree that business object pattern does not make any sense at all for
this sample project but DAO pattern does make a lot of sense. As a matter of
fact, DAO makes a lot of sense in any project that deals with data.
Software Used
1)
Java 1.6
2)
Spring Tool suite (STS) 3.1.0
3)
Oracle 11g Express Edition
4)
Apache maven 3.0.4
5)
Hibernate 4.1.8 Final
6)
Log4j 1.2.16 and Slf4j 1.6.1
Pre-installation
and validation steps
The below
steps were done before the actual java project was created
1) Installed Java 1.6 and added JAVA_HOME in System
Path and System environment variables
2)
Installed Spring Tool Suite
3)
Installed Maven 3.0.4 and added M2_HOME in
System Path and System environment variables. Configured STS to use this installed
maven instead of its native one. This can be done in STS Window menu ->
Preferences -> Maven -> Installations.
4)
Installed Oracle 11g Express Edition, created a new
database user and ran the below script (as the new user) to create a table in
his schema. This script will also insert data into the table
CREATE TABLE EMPLOYEE( EMP_ID NUMBER(5) NOT NULL, FNAME VARCHAR2(20), LNAME VARCHAR2(20), DEPT_ID NUMBER(5) NOT NULL, MANAGER_EMP_ID NUMBER(5), SALARY NUMBER(5), HIRE_DATE DATE, JOB_ID NUMBER(3), ACTIVE CHAR(1) DEFAULT 'Y' NOT NULL, CONSTRAINT employee_pk PRIMARY KEY (EMP_ID) ); -- Insert Data into the tables. insert into employee (EMP_ID,FNAME,LNAME,DEPT_ID,MANAGER_EMP_ID,SALARY,HIRE_DATE,JOB_ID) select e.emp_id, e.fname, e.lname, e.dept_id, e.manager_emp_id, e.salary, e.hire_date, e.job_id from ( select 7369 emp_id, 'JOHN' fname, 'SMITH' lname, 20 dept_id, 7902 manager_emp_id, 800 salary, '17-DEC-80' hire_date, 667 job_id from dual union all select 7499 emp_id, 'KEVIN' fname, 'ALLEN' lname, 30 dept_id, 7698 manager_emp_id, 1600 salary, '20-FEB-81' hire_date, 670 job_id from dual union all select 7521 emp_id, 'CYNTHIA' fname, 'WARD' lname, 30 dept_id, 7698 manager_emp_id, 1250 salary, '22-FEB-81' hire_date, null job_id from dual union all select 7566 emp_id, 'TERRY' fname, 'JONES' lname, 20 dept_id, 7839 manager_emp_id, 2000 salary, '02-APR-81' hire_date, 671 job_id from dual union all select 7654 emp_id, 'KENNETH' fname, 'MARTIN' lname, 30 dept_id, 7698 manager_emp_id, 1250 salary, '28-SEP-81' hire_date, 670 job_id from dual union all select 7698 emp_id, 'MARION' fname, 'BLAKE' lname, 30 dept_id, 7839 manager_emp_id, 2850 salary, '01-MAY-80' hire_date, 671 job_id from dual union all select 7782 emp_id, 'CAROL' fname, 'CLARK' lname, 10 dept_id, 7839 manager_emp_id, 2450 salary, '09-JUN-81' hire_date, 671 job_id from dual union all select 7788 emp_id, 'DONALD' fname, 'SCOTT' lname, 20 dept_id, 7566 manager_emp_id, 3000 salary, '19-APR-87' hire_date, 669 job_id from dual union all select 7839 emp_id, 'FRANCIS' fname, 'KING' lname, 10 dept_id, null manager_emp_id, 5000 salary, '17-NOV-81' hire_date, 672 job_id from dual union all select 7844 emp_id, 'MARY' fname, 'TURNER' lname, 30 dept_id, 7698 manager_emp_id, 1500 salary, '08-SEP-81' hire_date, 670 job_id from dual union all select 7876 emp_id, 'DIANE' fname, 'ADAMS' lname, 20 dept_id, 7788 manager_emp_id, 1100 salary, '23-MAY-87' hire_date, null job_id from dual union all select 7900 emp_id, 'FRED' fname, 'JAMES' lname, 30 dept_id, 7698 manager_emp_id, 950 salary, '03-DEC-81' hire_date, 667 job_id from dual union all select 7902 emp_id, 'JENNIFER' fname, 'FORD' lname, 20 dept_id, 7566 manager_emp_id, 3000 salary, '03-DEC-81' hire_date, 669 job_id from dual union all select 7934 emp_id, 'BARBARA' fname, 'MILLER' lname, 10 dept_id, 7782 manager_emp_id, 1300 salary, '23-JAN-82' hire_date, 667 job_id from dual ) e; commit;
Create maven
project
The first
and foremost task is to create a maven project in STS which generates a default
maven project structure that includes the pom.xml file. Use the below pom.xml
file instead of the default one that STS provides.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>com.samples</groupId> <artifactId>hibernateCrud</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>hibernateCrud</name> <url>http://maven.apache.org</url> <repositories> <repository> <id>JBoss repository</id> <url>http://repository.jboss.org/nexus/content/groups/public/</url> </repository> </repositories> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <hibernate.version>4.1.8.Final</hibernate.version> <oracle.version>11.2.0</oracle.version> <junit.version>4.11</junit.version> <commons-logging.version>1.1.1</commons-logging.version> <log4j.version>1.2.16</log4j.version> <slf4j.version>1.6.1</slf4j.version> </properties> <dependencies> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency> <dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>${oracle.version}</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>${junit.version}</version> <scope>test</scope> </dependency> </dependencies> </project>
In this
pom.xml file –<groupid>, <artifactid>, <version>,
<packaging> and <name> elements describe about the type and name of
the artifact that this project would generate after building with maven.
Usually it’s a good practice to match the groupId value with the base package
name of java class. <repositories> tells about the nexus repository where
the dependent artifact jars (like hibernate, log4J etc) can be found. <properties> is a place where you can centralize the configuration of
version numbers of all the artifacts and then can be referred elsewhere int the
pom.xml file with ${property-name} representation. <dependencies> lists
the various artifacts that this project is dependent on. Once pom.xml is
configured, navigate to the project location in command line and type mvn clean install to clean and build
the project. This automatically downloads the needed artifacts that were
configured in pom.xml too. The downloaded artifacts as well as the jar or war
artifact that you build out of this project are placed in
/.m2 folder.
Log4j
configuration
SLF4J
(Simple Logging Facade for Java) is a simple façade or abstraction framework
over other logging frameworks like java.util.Logging and Log4J. The desired
logging framework is decided during the deployment time.
<dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <version>${slf4j.version}</version> </dependency>
This
downloads slf4j-log4j12-<version>.jar, slf4j-api-<version>.jar and
log4j-<log4j-version>.jar to your local .m2 repository folder. Between, <version>
and <logj-version> are the versions that you have mentioned under the
properties tag of pom.xml
Log4j
Properties
This
property file is used to configure the root Logger and how the output is
formatted when you use a log statement. Below is the configuration I have used
to send the logs to console using the specified pattern
log4j.rootLogger=INFO,out log4j.appender.out=org.apache.log4j.ConsoleAppender log4j.appender.out.layout=org.apache.log4j.PatternLayout log4j.appender.out.layout.ConversionPattern=[%t] [class: %-c{1}] %-5p - %m%n
Database and Hibernate configuration in pom.xml
To configure database (oracle), the pom needs an oracle driver (ojdbc) and to configure Hibernate ORM, the pom needs hibernate-core jar file and so the below configuration
<dependency> <groupId>com.oracle</groupId> <artifactId>ojdbc6</artifactId> <version>${oracle.version}</version> </dependency> <dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-core</artifactId> <version>${hibernate.version}</version> </dependency>HibernateUtil.java contains code to instantiate a session. Create a new configuration object which will hold all properties from the hibernate xml config file. If a different file name is used then you have to mention the filename to the configuration object so that it can read all the properties. These properties are used to create a service registry using service registry builder. Using the resulting service registry, the immutable session factory object is created. The way we create session factory object has changed from Hibernate version 4. A snippet from HibernateUtil’s buildSessionFactory() method
Configuration configuration = new Configuration(); //If you ignore the below configure filename, then it searches hibernate.cfg.xml by default configuration.configure("hib.cfg.xml"); ServiceRegistry serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry(); return configuration.buildSessionFactory(serviceRegistry);
The only
hibernate entity that we have used is the “Employee” class that is mapped to
EMPLOYEE table which we already created using the above script. An important
point to note is that this entity is referred as value for the
element in hibernate xml config file.
<mapping class="com.samples.domain.Employee"></mapping>
BO, DAO and other layers
As I said,
this project is all about doing CRUD operations using hibernate. Totally there
are four different packages or layers in this project.
Application Layer (com.samples)
Contains
application code in HibernateCRUD.java and code for creating session factory
object in HibernateUtil.java
Business object layer (com.samples.BO)
This layer contains
code for business validations to check whether the in or out data conforms to
the business rules. As we know, it interfaces
with DAO layer and so it converts every business object or the individual java
properties to its equivalent domain object.
Data access object layer (com.samples.DAO)
This layer encapsulates the code for all the database operations, session and transaction management. This layer interacts with the
underlying Hibernate ORM or Database. Any data related operation cannot by pass
this layer.
Domain layer (com.samples.domain)
This holds all
the domain or entity objects of the application. These are simple POJOs that
map to the underlying database database tables.
Following a
layered approach makes us to write uncluttered code and making us to think - to
which layer does a new piece of code will fit in. The above approach helps us
to use business object pattern and data access object pattern. Every read/write
operation from the application code passes through the BO layer then to the DAO
layer and then finally transforms as an action on the database. Similarly when
the action is complete, the data passes through the DAO layer and to BO layer
and then finally to the application layer. Having this in mind, if you navigate
the code, it could be easily understood. But as a whole, this project depicts
how to perform – add, get, list (get all), update and delete operations using
hibernate.
Before
bringing this post to an end, let me talk about the domain or hibernate entity
mapping of the “Employee” POJO. The mapping is pretty straight forward but the
one thing to note is the ID property mapped to EMP_ID column of table.
@Column(name="EMP_ID") @Id @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "emp_id_seq") @SequenceGenerator(name="emp_id_seq", sequenceName="emp_id_sequence", allocationSize=1) private Integer empId;
Here we are
asking to use an Oracle sequence generated value for the column “EMP_ID”. By
default hibernate uses HILO algorithm to generate the sequence numbers and
bumps the numbers by 50 for every fetch. To override this we have used an
allocation size of 1. By doing this way there won’t be big gap in two
successive rows of this table.
All this is possible by having a database sequence called “emp_id_sequence” which can be created with the below BEFORE trigger
CREATE OR REPLACE TRIGGER "METALLICATONY"."EMP_ID_TRIGGER" BEFORE INSERT ON EMPLOYEE REFERENCING NEW AS NEW FOR EACH row BEGIN IF :NEW.emp_id IS NULL THEN SELECT emp_id_sequence.nextval INTO :NEW.emp_id FROM dual; END IF; ALTER TRIGGER "METALLICATONY"."EMP_ID_TRIGGER" ENABLE;Having a CHAR(1) column ACTIVE in database, we can map it to a Boolean type in Hibernate entity using the @Type annotation. The ACTIVE column can take Y or N which actually maps to true or false in the domain object
@Column(name="ACTIVE") @org.hibernate.annotations.Type(type="yes_no") private Boolean active;
This project is pretty straight forward and it helped me to get easy with maven, hibernate and Log4J. Hope it would help you too. Feel free to browse through or download the source from my git repository CRUD with Hibernate @ GitHub and import it as a maven project into your favorite IDE.
Labels: Programming, Techie Talk
0 Comments:
Post a Comment
<< Home