15 - Hibernate Cascade and Fetching Strategy: Page 2 of 2

15.2.1 Cascade (save-update)

We can use cascade= save-update to enable the save or update cascade effect.  With this we can avoid the extra call of save or update. Please note that when we say “avoid extra call to save or update does not mean that additional query will not be fired. It is just that we need not to call save() function in java code”.

Let's enable cascade effect in association-mapping.hbm.xml

We added cascade=”save-update” in set which means now when stadium entity will persist, it will automatically save the cricket matches.. Since we added it on set (vice-versa is not true , saving matches will not save stadium).

<?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.tutorial.hibernate.CricketMatch" table="Cricket_Match">
        <id name="id" type="int" column="match_id">
            <generator class="native" />
        </id>

        <property name="team1" column="team1" type="string" />
        <property name="team2" column="team2" type="string" />
        <property name="type" column="type" type="string" />    
        <property name="umpire" column="umpire" type="string" />

    </class>

    <class name="com.tutorial.hibernate.Stadium" table="Stadium">
        <id name="id" type="int" column="stadium_id">
            <generator class="native" />
        </id>
        <property name="name" type="string" column="stadium_name" />
        <property name="capacity" type="int" column="capacity" />
        <property name="country" type="string" column="country" />

        <set name="matches" cascade="save-update" >
           <key column="stadium_id"></key>
           <one-to-many class="com.tutorial.hibernate.CricketMatch" />
        </set>
     </class>

</hibernate-mapping>

Test Program – This program will only makes a call to save for Stadium and two matches get persisted automatically. Also updating Stadium details Or matches details gets persisted.

import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;

import com.tutorial.hibernate.CricketMatch;
import com.tutorial.hibernate.Stadium;

public class Test {

      private static SessionFactory factory;       
      public static void main(String args[])
      {        
        Configuration cfg = new Configuration().configure();
        factory = cfg.buildSessionFactory();        
        Session session = factory.openSession();
        Transaction tx = session.beginTransaction();

        Stadium stadium = new Stadium();        
        stadium.setCapacity(2300);
        stadium.setCountry("Australia");
        stadium.setName("Sydney");

        CricketMatch match1 = new CricketMatch();

        match1.setTeam1("India");
        match1.setTeam2("Australia");
        match1.setType("Test Match");
        match1.setUmpire("Billy Bowden");

        CricketMatch match2 = new CricketMatch();

        match2.setTeam1("West Indies");
        match2.setTeam2("South Africa");
        match2.setType("T 20");
        match2.setUmpire("Stuart Willy");

        Set<CricketMatch> matches = new HashSet<CricketMatch>();

        matches.add(match1);
        matches.add(match2);

        stadium.setMatches(matches);
        int stadiumId= (Integer)session.save(stadium);

        tx.commit();
        session.close();

        updateStadiumDetails(stadiumId);

        factory.close();        
    }
    private static void updateStadiumDetails(int id)
    {
        Session session = factory.openSession();        
        Transaction tx = session.beginTransaction();
        Stadium stadium = (Stadium)session.get(Stadium.class,id);

        Set<CricketMatch> matches  = stadium.getMatches();

        Iterator it= matches.iterator();
        while(it.hasNext())
        {
            CricketMatch match= (CricketMatch)it.next();
            match.setType("One Day");
        }
            stadium.setCapacity(5400);

            tx.commit();        
    }
}

Result

 

 

15.2.2 Cascade (delete)

We can use cascade=delete which will delete all the matches if stadium is deleted. To see it in action change the set definition as below 

<set name="matches" cascade="delete">
        <key column="stadium_id"></key>
        <one-to-many class="com.tutorial.hibernate.CricketMatch" />        
</set> 

Deleting stadium will delete both matches like below.

Session session = factory.openSession();
Transaction tx = session.beginTransaction();
Stadium stadium = (Stadium)session.get(Stadium.class,id);
session.delete(stadium);
tx.commit();

15.3 Fetching Strategies

Hibernate offers several fetching strategies for the associated objects. By default , Hibernate uses lazy fetching which means only the object we queried will be fetched.

Hibernate supports following strategies

  1. Select Fetching – This is default strategy and is a lazy load of the associations. Till we do not call the associations, associations will not be loaded.
  2. Sub Select Fetchingassociations will be fetched in a second select statement when requested. The second select statement will fetch all the related associations in sub-select query.
  3. Join Fetching –  This fetching loads all the associations using a joins while loading the parent entity. Since this loads the association with parent, it disables the lazy loading.
  4. Batch Fetching used to fetch collections up to the batch size.

Let’s play with the same example we discussed in Section 19.2 and insert some associations in tables using below program. Run this program twice so that we will have 2 stadiums and 4 matches.

Configuration cfg = new Configuration().configure();
factory = cfg.buildSessionFactory();
        
Session session = factory.openSession();
Transaction tx = session.beginTransaction();

Stadium stadium = new Stadium();

stadium.setCapacity(2300);
stadium.setCountry("Australia");
stadium.setName("Sydney");

CricketMatch match1 = new CricketMatch();

match1.setTeam1("India");
match1.setTeam2("Australia");
match1.setType("Test Match");
match1.setUmpire("Billy Bowden");

CricketMatch match2 = new CricketMatch();

match2.setTeam1("West Indies");
match2.setTeam2("South Africa");
match2.setType("T 20");
match2.setUmpire("Stuart Willy");

Set<CricketMatch> matches = new HashSet<CricketMatch>();
matches.add(match1);
matches.add(match2);

stadium.setMatches(matches);

session.save(stadium);

tx.commit();
session.close();

Stadium Table 

Cricket_Match Table

15.3.1 Difference between Select and Sub Select Strategy           

Select Fetching-

Collections will always be fetched using second select. If  set has lazy=false then collections will be fetched with separate select immediately else will be fetched with separate select when requested.

To use the join fetching, add fetch=”select”  in the set definition in association-mapping.hbm.xml lilke below.  

<set name="matches" cascade="save-update,delete" fetch="select">
        <key column="stadium_id"></key>
        <one-to-many class="com.tutorial.hibernate.CricketMatch" />
</set>

Fetch Stadium and Matches details like below will fire two select statements (refer console output)

Session session = factory.openSession();
Query query = session.createQuery("from Stadium ");
List  stadiums = query.list();
for(int i=0;i<stadiums.size();i++)
{
    Stadium stadium = (Stadium)stadiums.get(i);
    Set<CricketMatch> matches  = stadium.getMatches();

    Iterator it= matches.iterator();
    while(it.hasNext())
    {
        CricketMatch match= (CricketMatch)it.next();
    }            
}

Console OutPut –As you can see , three queries are fired. One for Stadium and since there are two stadium, one  separate  queries to fetch matches details for each stadium.            

Sub Select Fetching

To use the join fetching, add fetch=”subselect”  in the set definition in association-mapping.hbm.xml lilke below. 

<set name="matches" cascade="save-update,delete" fetch="subselect">
        <key column="stadium_id"></key>
        <one-to-many class="com.tutorial.hibernate.CricketMatch" />
</set>

Fetch Stadium and Matches details like below will fire two select statements (refer console output)

Session session = factory.openSession();
Query query = session.createQuery("from Stadium ");
List  stadiums = query.list();

for(int i=0;i<stadiums.size();i++)
{
    Stadium stadium = (Stadium)stadiums.get(i);
    Set<CricketMatch> matches  = stadium.getMatches();

    Iterator it= matches.iterator();
    while(it.hasNext())
    {
        CricketMatch match= (CricketMatch)it.next();
    }            
}

Console OutPut – Two queries are fired. One for stadium details and another is sub select to fetch match details of all stadiums in a one go.        

Like us on Facebook