SQL Zone is brought to you in partnership with:

I currently work in the capacity of Software Engineer at a reputed company in Sri Lanka. I'm most keen in J2EE Technologies and love working with open source libraries which fit my project needs. Very interested in the NoSQL concept and experimenting with various products to find a good blend for our projects within the company. Part time freelancer. Avid contributor in the stackoverflow arena. Android is another area which I am looking at with very keen interest as I believe mobile development is the way forward. Dinuka is a DZone MVB and is not an employee of DZone and has posted 24 posts at DZone. You can read more from them at their website. View Full User Profile

Hibernate by Example - Part 1 (Orphan removal)

09.23.2011
| 17610 views |
  • submit to reddit

So i thought to do a series of hibernate examples showing various features of hibernate. In the first part i wanted to show about the Delete Orphan feature and how it may be used with the use of a story line. So let us begin :)  

Prerequisites:
In order for you to try out the following example you will need the below mentioned JAR files:


  • org.springframework.aop-3.0.6.RELEASE.jar
  • org.springframework.asm-3.0.6.RELEASE.jar
  • org.springframework.aspects-3.0.6.RELEASE.jar
  • org.springframework.beans-3.0.6.RELEASE.jar
  • org.springframework.context.support-3.0.6.RELEASE.jar
  • org.springframework.context-3.0.6.RELEASE.jar
  • org.springframework.core-3.0.6.RELEASE.jar
  • org.springframework.jdbc-3.0.6.RELEASE.jar
  • org.springframework.orm-3.0.6.RELEASE.jar
  • org.springframework.transaction-3.0.6.RELEASE.jar.
  • org.springframework.expression-3.0.6.RELEASE.jar
  • commons-logging-1.0.4.jar
  • log4j.jar
  • aopalliance-1.0.jar
  • dom4j-1.1.jar
  • hibernate-commons-annotations-3.2.0.Final.jar
  • hibernate-core-3.6.4.Final.jar
  • hibernate-jpa-2.0-api-1.0.0.Final.jar
  • javax.persistence-2.0.0.jar
  • jta-1.1.jar
  • javassist-3.1.jar
  • slf4j-api-1.6.2.jar
  • mysql-connector-java-5.1.13-bin.jar
  • commons-collections-3.0.jar

For anyone who want the eclipse project to try this out, you can download it with the above mentioned JAR dependencies here.

Introduction:

Its year 2011. And The Justice League has grown out of proportion and are searching for a developer to help with creating a super hero registering system. A developer competent in Hibernate and ORM is ready to do the system and handle the persistence layer using Hibernate. For simplicity, He will be using a simple stand alone application to persist super heroes. This is how this example will layout:

  • Table design
  • Domain classes and Hibernate mappings
  • DAO & Service classes
  • Spring configuration for the application
  • A simple main class to show how it all works
Let the Journey Begin......................


Table Design:

The design consists of three simple tables as illustrated by the diagram below;





As you can see its a simple one-to-many relationship linked by a Join Table. The Join Table will be used by Hibernate to fill the Super hero list which is in the domain class which we will go on to see next.

Domain classes and Hibernate mappings:

There are mainly only two domain classes as the Join table in linked with the primary owning entity which is the Justice League entity. So let us go on to see how the domain classes are constructed with annotations;
package com.justice.league.domain;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;

import org.hibernate.annotations.Type;

@Entity
@Table(name = "SuperHero")
public class SuperHero implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = -6712720661371583351L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "super_hero_id")
	private Long superHeroId;

	@Column(name = "super_hero_name")
	private String name;

	@Column(name = "power_description")
	private String powerDescription;

	@Type(type = "yes_no")
	@Column(name = "isAwesome")
	private boolean isAwesome;

	public Long getSuperHeroId() {
		return superHeroId;
	}

	public void setSuperHeroId(Long superHeroId) {
		this.superHeroId = superHeroId;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public String getPowerDescription() {
		return powerDescription;
	}

	public void setPowerDescription(String powerDescription) {
		this.powerDescription = powerDescription;
	}

	public boolean isAwesome() {
		return isAwesome;
	}

	public void setAwesome(boolean isAwesome) {
		this.isAwesome = isAwesome;
	}

}

As i am using MySQL as the primary database, i have used the GeneratedValue strategy as GenerationType.AUTO which will do the auto incrementing whenever a new super hero is created. All other mappings are familiar to everyone with the exception of the last variable where we map a boolean to a Char field in the database.

We use Hibernate's @Type annotation to represent true & false as Y & N within the database field. Hibernate has many @Type implementations which you can read about here. In this instance we have used this type.

Ok now that we have our class to represent the Super Heroes, lets go on to see how our Justice League domain class looks like which keeps tab of all super heroes who have pledged allegiance to the League.

package com.justice.league.domain;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name = "JusticeLeague")
public class JusticeLeague implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 763500275393020111L;

	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	@Column(name = "justice_league_id")
	private Long justiceLeagueId;

	@Column(name = "justice_league_moto")
	private String justiceLeagueMoto;

	@Column(name = "number_of_members")
	private Integer numberOfMembers;

	@OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true)
	@JoinTable(name = "JUSTICE_LEAGUE_SUPER_HERO", joinColumns = { @JoinColumn(name = "justice_league_id") }, inverseJoinColumns = { @JoinColumn(name = "super_hero_id") })
	private List<SuperHero> superHeroList = new ArrayList<SuperHero>(0);

	public Long getJusticeLeagueId() {
		return justiceLeagueId;
	}

	public void setJusticeLeagueId(Long justiceLeagueId) {
		this.justiceLeagueId = justiceLeagueId;
	}

	public String getJusticeLeagueMoto() {
		return justiceLeagueMoto;
	}

	public void setJusticeLeagueMoto(String justiceLeagueMoto) {
		this.justiceLeagueMoto = justiceLeagueMoto;
	}

	public Integer getNumberOfMembers() {
		return numberOfMembers;
	}

	public void setNumberOfMembers(Integer numberOfMembers) {
		this.numberOfMembers = numberOfMembers;
	}

	public List<SuperHero> getSuperHeroList() {
		return superHeroList;
	}

	public void setSuperHeroList(List<SuperHero> superHeroList) {
		this.superHeroList = superHeroList;
	}

}


The important fact to note here is the annotation @OneToMany(cascade = { CascadeType.ALL }, fetch = FetchType.EAGER, orphanRemoval = true). Here we have set orphanRemoval = true.

So what does that do exactly? Ok so say that you have a group of Super Heroes in your League. And say one Super Hero goes haywire. So we need to remove Him/Her from the League. With JPA cascade this is not possible as it does not detect Orphan records and you will wind up with the database having the deleted Super Hero(s) whereas your collection still has a reference to it.

Prior to JPA 2.0 you did not have the orphanRemoval support and the only way to delete orphan records was to use the following Hibernate specific(or ORM specific) annotation which is now deprecated;

@org.hibernate.annotations.Cascade(org.hibernate.annotations.CascadeType.DELETE_ORPHAN)

But with the introduction of the attribute orphanRemoval, we are now able to handle the deletion of orphan records through JPA. Now that we have our Domain classes

DAO & Service classes:
To keep with good design standards i have separated the DAO(Data access object) layer and the service layer. So let us see the DAO interface and implementation. Note that i have used HibernateTemplate through HibernateDAOSupport so as to keep away any Hibernate specific detail out and access everything in a unified manner using Spring.

package com.justice.league.dao;

import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.justice.league.domain.JusticeLeague;

@Transactional(propagation = Propagation.REQUIRED, readOnly = false)  
public interface JusticeLeagueDAO {

	
	public void createOrUpdateJuticeLeagure(JusticeLeague league);
	
	public JusticeLeague retrieveJusticeLeagueById(Long id);
}


In the interface layer i have defined the Transaction handling as Required. This is done so that whenever you do not need a transaction you can define that at the method level of that specific method and in more situations you will need a transaction with the exception of data retrieval methods. 

According to the JPA spec you need a valid transaction for insert/delete/update functions.

So lets take a look at the DAO implementation;

package com.justice.league.dao.hibernate;

import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import com.justice.league.dao.JusticeLeagueDAO;
import com.justice.league.domain.JusticeLeague;

@Qualifier(value="justiceLeagueHibernateDAO")
public class JusticeLeagueHibernateDAOImpl extends HibernateDaoSupport
		implements JusticeLeagueDAO {

	@Override
	public void createOrUpdateJuticeLeagure(JusticeLeague league) {

		if (league.getJusticeLeagueId() == null) {
			getHibernateTemplate().persist(league);
		} else {
			getHibernateTemplate().update(league);
		}

	}
	
	@Transactional(propagation = Propagation.NOT_SUPPORTED, readOnly = false)  
	public JusticeLeague retrieveJusticeLeagueById(Long id){
		return getHibernateTemplate().get(JusticeLeague.class, id);
	}

}


Here i have defined an @Qualifier to let Spring know that this is the Hibernate implementation of the DAO class. Note the package name which ends with hibernate. This as i see is a good design concept to follow where you separate your implementation(s) into separate packages to keep the design clean.

Ok lets move on to the service layer implementation. The service layer in this instance is just acting as a mediation layer to call the DAO methods. But in a real world application you will probably have other validations, security related procedures etc handled within the service layer.

 

package com.justice.league.service;

import com.justice.league.domain.JusticeLeague;

public interface JusticeLeagureService {

	public void handleJusticeLeagureCreateUpdate(JusticeLeague justiceLeague);

	public JusticeLeague retrieveJusticeLeagueById(Long id);
}


 

package com.justice.league.service.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;

import com.justice.league.dao.JusticeLeagueDAO;
import com.justice.league.domain.JusticeLeague;
import com.justice.league.service.JusticeLeagureService;

@Component("justiceLeagueService")
public class JusticeLeagureServiceImpl implements JusticeLeagureService {

	@Autowired
	@Qualifier(value = "justiceLeagueHibernateDAO")
	private JusticeLeagueDAO justiceLeagueDAO;

	@Override
	public void handleJusticeLeagureCreateUpdate(JusticeLeague justiceLeague) {
		justiceLeagueDAO.createOrUpdateJuticeLeagure(justiceLeague);
	}

	public JusticeLeague retrieveJusticeLeagueById(Long id){
		return justiceLeagueDAO.retrieveJusticeLeagueById(id);
	}
}

Few things to note here. First of all the @Component binds this service implementation with the name justiceLeagueService within the spring context so that we can refer to the bean as a bean with an id of name justiceLeagueService.

And we have auto wired the JusticeLeagueDAO and defined an @Qualifier so that it will be bound to the Hibernate implementation.

The value of the Qualifier should be the same name we gave the class level Qualifier within the DAO Implementation class. And Lastly let us look at the Spring configuration which wires up all these together;


Spring configuration for the application:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="  
          http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
          http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd  
          http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd  
          http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">


	<context:component-scan base-package="com.justice.league" />
	<context:annotation-config />

	<tx:annotation-driven />

	<bean id="sessionFactory"
		class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
		<property name="packagesToScan">
			<list>
				<value>com.justice.league.**.*</value>
			</list>
		</property>
		<property name="hibernateProperties">
			<props>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				<prop key="hibernate.connection.driver_class">com.mysql.jdbc.Driver</prop>
				<prop key="hibernate.connection.url">jdbc:mysql://localhost:3306/my_test</prop>
				<prop key="hibernate.connection.username">root</prop>
				<prop key="hibernate.connection.password">password</prop>
				<prop key="hibernate.show_sql">true</prop>
				<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
				
			</props>
		</property>
	</bean>

	<bean id="justiceLeageDAO"
		class="com.justice.league.dao.hibernate.JusticeLeagueHibernateDAOImpl">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

	<bean id="transactionManager"
		class="org.springframework.orm.hibernate3.HibernateTransactionManager">
		<property name="sessionFactory" ref="sessionFactory" />
	</bean>

</beans>

Note that i have used the HibernateTransactionManager in this instance as i am running it stand alone. If you are running it within an application server you will almost always use a JTA Transaction manager.

I have also used auto creation of tables by hibernate for simplicity purposes. The packagesToScan property instructs to scan through all sub packages(including nested packaged within them) under the root package com.justice.league.**.* to be scanned for @Entity annotated classes.

We have also bounded the session factory to the justiceLeagueDAO so that we can work with the Hibernate Template. For testing purposes you can have the tag <prop key="hibernate.hbm2ddl.auto">create</prop> initially if you want, and let hibernate create the tables for you. Ok so now that we have seen the building blocks of the application, lets see how this all works by first creating some super heroes within the Justice League

A simple main class to show how it all works:

As the first example lets see how we are going to persist the Justice League with a couple of Super Heroes; 

package com.test;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.justice.league.domain.JusticeLeague;
import com.justice.league.domain.SuperHero;
import com.justice.league.service.JusticeLeagureService;

public class TestSpring {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		ApplicationContext ctx = new ClassPathXmlApplicationContext(
				"spring-context.xml");
		JusticeLeagureService service = (JusticeLeagureService) ctx
				.getBean("justiceLeagueService");

		JusticeLeague league = new JusticeLeague();
		List<SuperHero> superHeroList = getSuperHeroList();

		league.setSuperHeroList(superHeroList);
		league.setJusticeLeagueMoto("Guardians of the Galaxy");
		league.setNumberOfMembers(superHeroList.size());

		service.handleJusticeLeagureCreateUpdate(league);

	}

	private static List<SuperHero> getSuperHeroList() {

		List<SuperHero> superHeroList = new ArrayList<SuperHero>();

		SuperHero superMan = new SuperHero();
		superMan.setAwesome(true);
		superMan.setName("Clark Kent");
		superMan.setPowerDescription("Faster than a speeding bullet");

		superHeroList.add(superMan);

		SuperHero batMan = new SuperHero();
		batMan.setAwesome(true);
		batMan.setName("Bruce Wayne");
		batMan.setPowerDescription("I just have some cool gadgets");
		superHeroList.add(batMan);

		return superHeroList;
	}

}

And if we go to the database and check this we will see the following output; 

mysql> select * from superhero;
+---------------+-----------+-----------------+-------------------------------+
| super_hero_id | isAwesome | super_hero_name | power_description             |
+---------------+-----------+-----------------+-------------------------------+
|             1 | Y         | Clark Kent      | Faster than a speeding bullet |
|             2 | Y         | Bruce Wayne     | I just have some cool gadgets |
+---------------+-----------+-----------------+-------------------------------+

mysql> select * from justiceleague;
+-------------------+-------------------------+-------------------+
| justice_league_id | justice_league_moto     | number_of_members |
+-------------------+-------------------------+-------------------+
|                 1 | Guardians of the Galaxy |                 2 |
+-------------------+-------------------------+-------------------+

So as you can see we have persisted two super heroes and linked them up with the Justice League. Now let us see how that delete orphan works with the below example;

package com.test;

import java.util.ArrayList;
import java.util.List;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.justice.league.domain.JusticeLeague;
import com.justice.league.domain.SuperHero;
import com.justice.league.service.JusticeLeagureService;

public class TestSpring {

	/**
	 * @param args
	 */
	public static void main(String[] args) {

		ApplicationContext ctx = new ClassPathXmlApplicationContext(
				"spring-context.xml");
		JusticeLeagureService service = (JusticeLeagureService) ctx
				.getBean("justiceLeagueService");

		JusticeLeague league = service.retrieveJusticeLeagueById(1l);
		List<SuperHero> superHeroList = league.getSuperHeroList();
		/**
		 * Here we remove Batman(a.k.a Bruce Wayne) out of the Justice League
		 * cos he aint cool no more
		 */
		for (int i = 0; i < superHeroList.size(); i++) {
			SuperHero superHero = superHeroList.get(i);
			if (superHero.getName().equalsIgnoreCase("Bruce Wayne")) {
				superHeroList.remove(i);
				break;
			}

		}

		service.handleJusticeLeagureCreateUpdate(league);

	}

}

Here we first retrieve the Justice League record by its primary key. Then we loop through and remove Batman off the League and again call the createOrUpdate method. As we have the remove orphan defined, any Super Hero not in the list which is in the database will be deleted.
Again if we query the database we will see that batman has been removed now as per the following;

mysql> select * from superhero;
+---------------+-----------+-----------------+-------------------------------+
| super_hero_id | isAwesome | super_hero_name | power_description             |
+---------------+-----------+-----------------+-------------------------------+
|             1 | Y         | Clark Kent      | Faster than a speeding bullet |
+---------------+-----------+-----------------+-------------------------------+

So that's it. The story of how Justice League used Hibernate to remove Batman automatically without being bothered to do it themselves.

Next up look forward to how Captain America used Hibernate Criteria to build flexible queries in order to locate possible enemies. Watch out!!!!

Have a great day people and thank you for reading!!!!

If you have any suggestions or comments pls do leave them by.

From http://dinukaroshan.blogspot.com/2011/09/hibernate-by-example-part-1-orphan.html

Published at DZone with permission of Dinuka Arseculeratne, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Manuel Jordan replied on Mon, 2011/09/26 - 8:17am

Thanks for share this tutorial

Mike Dzone replied on Mon, 2011/09/26 - 8:32am

If you are reading this article, watch this webcast http://vimeo.com/28885655. What we should be taking from this article is how obsurd it is to have so many JAR dependencies, so much XML configuration and obscure annotations for a 3 table database structure.

Dinuka Arseculeratne replied on Mon, 2011/09/26 - 11:04pm in response to: Manuel Jordan

@Manuel - Thx alot for the comment. Hope you enjoyed reading it. Cheers

Dinuka Arseculeratne replied on Mon, 2011/09/26 - 11:05pm in response to: Mike Dzone

@Mike - Yes i agree on your point. Thx for sharing webcast. Cheers.

Alen Vrecko replied on Wed, 2011/09/28 - 10:45am

Isnt using eager loading on @OneToMany List considered bad practice? Iirc latest Hibernate doesnt allow you to use List, you need to use Set for eager OTM.

Dinuka Arseculeratne replied on Sat, 2011/10/01 - 12:06am in response to: Alen Vrecko

@Alen,

 Yes that is true. To not make the example more verbose i sticked with EAGER loading because i would need to do an initialized on hibernate template otherwise. But i agree with you 100% that it is not good practice. Are you sure about not allowing lists? im using Hibernate 3.6.4 here. What version are you refering to?

 

Thx for taking the time to leave by your thoughts.

 

Cheers

Alen Vrecko replied on Thu, 2011/10/06 - 12:39pm

@Dinuka Sorry for later reply I am super busy atm.

My mistake I didn't notice but I had 2 Eager Lists in an Entity and that fails miserably. Having only 1 Eager with other Lazy works.

If you make another article on Hibernate I'd be very interesting to know your opinion on List vs Set vs IdBag vs TreeSet vs ...

List is great as it doesn't force you to implement the hashCode and equals while Set is better for Hibernate. If only there'd be a Set that doesn't force you to use equals and hashCode or write the comparator or anything more than the List requires you to do.

The ideal data structure for me o) preserve the order of the elements (using primary key, if no PK then insertion order) o) don't allow for duplicates (same PK or if PK is null then same instance)

I must be missing something obvious. Cheers Alen

Dinuka Arseculeratne replied on Fri, 2011/10/07 - 1:29am in response to: Alen Vrecko

@Alen,

 

Thx again for taking the time off your busy schedule to drop by a comment. I believe your question about having two eager lists is anwered here.

I did not know that either. Thx for that info. That looks like a great idea. I will see what i can incorporate into my next post. Your feedback and comments are much appreciated and valued.

 

Have a great day

 

Cheers

 

Dinuka

Manuel Jordan replied on Sat, 2011/10/29 - 1:56pm in response to: Dinuka Arseculeratne

Yes, Interesting work, thanks again for share this valuable material. Best Regards from Peru!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.