More Books
Hibernate: A J2EE Developer's Guide
Hibernate: A J2EE™ Developer's Guide
Table of Contents
Copyright
Acknowledgments
About the Author
Preface
Required Skills
Roadmap
Chapter 1. Overview
Why Object/Relational Mapping?
What Is Hibernate?
Comparing JDBC to Hibernate
Hibernate's Mapping System
Other Java/Database Integration Solutions
How to Obtain and Install
Supported Databases
Chapter 2. Getting Oriented
Application Architecture
Mapping Files
Generating Java Source
Application Configuration
Web Application
JSP Interface
Chapter 3. Starting from Java
Java Object Model
Generated Mapping Files
Generated Schema
Working with Artifacts and Owners
Chapter 4. Starting from an Existing Schema
Initial Schema
Using Middlegen
Generated Mapping Files
Generated Java
Working with the Database
Chapter 5. Mapping Files
Basic Structure
Mapping File Reference
Chapter 6. Persistent Objects
Sessions
Objects and Identity
Life-Cycle Methods
Chapter 7. Relationships
Database Relationships
Java Collection Relationships
Java Class Relationships
Any-Based Relationships
Bi-directional Relationships
Chapter 8. Queries
HQL
HQL Reference
Select
From
Where
Group By
Having
Order By
Criteria Queries
Native SQL Queries
Chapter 9. Transactions
Introduction to Transactions
Optimistic and Pessimistic Locking
Chapter 10. Performance
Finding and Solving Problems
Queries
Inserts
Connection Pooling
Caching
Chapter 11. Schema Management
Updating an Existing Schema
Generating Update and Drop Scripts
Chapter 12. Best Practices, Style Guide, Tips and Tricks
Reducing Code with Inversion of Control
Reducing Session Creation Impact with ThreadLocal
Using Hibernate as an EJB BMP Solution
Integrating with Other Technologies
Applications That Use Hibernate
Strategies for Getting Started
Chapter 13. Future Directions
Hibernate 3.0
EJB 3.0
Here and Now
Index
SYMBOL
A
B
C
D
E
F
G
H
I
J
K
L
M
N
O
P
Q
R
S
T
U
V
W
X

Working with the Database

The application now has both *.hbm.xml files and corresponding Java source files. Given these files, it's a simple matter to use Hibernate to perform database operations. The sample code shown in the remainder of this chapter will use the generated files to populate the database with some data and then produce a report based on that data.

From the perspective of the classes manipulating the database via Hibernate, these are just additional examples of manipulating data with Hibernate, independent of the build system that generated the Java and mapping files.

Two classes, as shown in Figure 4.4, are used to manipulate the data. The first, GenerateData, populates the database with some test data. The second, GenerateReports, generates a tab-delimited text file, suitable for use with a spreadsheet.

Figure 4.4. Data Generation and Reporting Classes


Listing 4.13 demonstrates the insertion of data. Note the use of java.util.HashSet as a concrete implementation of java.util.Set. The latter is only an interface, whereas the former is a concrete implementation. For more information on sets and relationships, see Chapter 7.

Listing 4.13. Generating Data
package com.cascadetg.ch04;

import java.util.HashSet;

/** Various Hibernate-related imports */
import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;

public class GenerateData
{
    /** We use this session factory to create our sessions */
    public static SessionFactory sessionFactory;

    static String[] students =
        {
            "Smith",
            "Bob",
            "123-45-6789",
            "Stevens",
            "John",
            "456-78-9012",
            "Almara",
            "Betty",
            "098-76-5432" };

    static Student[] createdStudents = new Student[3];
    static Exam midterm;
    static Exam coursefinal;

    /** Loads the Hibernate configuration information,
     * sets up the database and the Hibernate session factory.
     */
    public static void initialization()
    {
        //System.setErr(System.out);
        System.out.println("initialization");
        try
        {
            Configuration myConfiguration = new
                 Configuration();

            myConfiguration.addClass(Course.class);
            myConfiguration.addClass(Exam.class);
            myConfiguration.addClass(Examresult.class);
            myConfiguration.addClass(Student.class);

            // Sets up the session factory (used in the rest
            // of the application).
            sessionFactory =
                 myConfiguration.buildSessionFactory();

        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        initialization();
        createClass();
        createExamResults();
    }

    static void createClass()
    {
        System.out.println();
        System.out.println("createClass");

        Session hibernateSession = null;
        Transaction myTransaction = null;
        try
        {
            hibernateSession = sessionFactory.openSession();
            myTransaction =
                 hibernateSession.beginTransaction();

            Course myCourse = new Course();
            myCourse.setQuarter("Q12005");
            myCourse.setTitle("Introduction To Hibernate");
            hibernateSession.save(myCourse);

            midterm = new Exam();
            midterm.setComment("First midterm");
            midterm.setCourse(myCourse);
            hibernateSession.save(midterm);

            coursefinal = new Exam();
            coursefinal.setComment("Course final");
            coursefinal.setCourse(myCourse);
            hibernateSession.save(coursefinal);

            HashSet myExams = new HashSet();
            myExams.add(midterm);
            myExams.add(coursefinal);
            myCourse.setExams(myExams);
            hibernateSession.save(myCourse);

            for (int i = 0; i < students.length; i = i + 3)
            {
                Student newStudent = new Student();
                newStudent.setLastName(students[i]);
                newStudent.setFirstName(students[i + 1]);
                newStudent.setIdString(students[i + 2]);
                hibernateSession.save(newStudent);

                createdStudents[i / 3] = newStudent;
            }

            hibernateSession.flush();
            myTransaction.commit();

        } catch (Exception e)
        {
            e.printStackTrace();
            try
            {
                myTransaction.rollback();
            } catch (Exception e2)
            {
                // Silent failure of transaction rollback
            }
        } finally
        {
            try
            {
                hibernateSession.close();
            } catch (Exception e2)
            {
                // Silent failure of session close
            }
        }

    }

    static void createExamResults()
    {
        System.out.println();
        System.out.println("createExamResults");

        Session hibernateSession = null;
        Transaction myTransaction = null;
        try
        {
            hibernateSession = sessionFactory.openSession();
            myTransaction =
                 hibernateSession.beginTransaction();

            for (int i = 0; i < createdStudents.length; i++)
            {
                Student myStudent = createdStudents[i];
                Examresult myExamResult = new Examresult();
                myExamResult.setScore(85 + i * 4);
                myExamResult.setStudent(myStudent);
                myExamResult.setExam(midterm);
                hibernateSession.save(myExamResult);
            }

            for (int i = 0; i < createdStudents.length; i++)
            {
                Student myStudent = createdStudents[i];

                Examresult myExamResult = new Examresult();
                myExamResult.setScore(75 + i * 8);
                myExamResult.setStudent(myStudent);
                myExamResult.setExam(coursefinal);
                hibernateSession.save(myExamResult);
            }

            hibernateSession.flush();
            myTransaction.commit();

        } catch (Exception e)
        {
            e.printStackTrace();
            try
            {
                myTransaction.rollback();
            } catch (Exception e2)
            {
                // Silent failure of transaction rollback
            }
        } finally
        {
            try
            {
                hibernateSession.close();
            } catch (Exception e2)
            {
                // Silent failure of session close
            }
        }
    }
}

Once data is loaded into the database, generating a report is only a matter of retrieving data from the database. Listing 4.14 shows how the report is generated, including the use of HQL to obtain statistical information. For more information on HQL, see Chapter 8.

COMMITTING AND BOOKKEEPING

You may have noticed that the uses of Hibernate in the examples in this book all explicitly commit the transactions (for example, mytransaction .commit()). This explicit call to commit a transaction isn't strictly necessary, but it's best to get into the habit of using it. On the other hand, you may eventually get tired of doing the bookkeeping associated with opening a session, committing a transaction, handling exceptions, and closing sessions. For a discussion of one strategy to deal with this, check out inversion-of- control as described in Chapter 12.


Listing 4.14. Generating the Report
package com.cascadetg.ch04;

/** Various Hibernate-related imports */
import java.io.FileOutputStream;
import java.util.Iterator;

import net.sf.hibernate.*;
import net.sf.hibernate.cfg.*;
import net.sf.hibernate.expression.*;

public class GenerateReports
{
    /** This is used to store the resulting report */
    static StringBuffer report = new StringBuffer();

    // System constants for the new line and directory tokens
    static String newLine =
         System.getProperty("line.separator");
    static String fileSep =
         System.getProperty("file.separator");

    /** We use this session factory to create our sessions */
    static SessionFactory sessionFactory;

    static public String highScore(Exam inExam)
    {
        String hql =
            "select max(result.score) from Examresult "
                + "as result where result.exam=?";
        return getExamStats(hql, inExam);
    }

    static public String lowScore(Exam inExam)
    {
        String hql =
            "select min(result.score) from Examresult "
                + "as result where result.exam=?";
        return getExamStats(hql, inExam);
    }

    static public String averageScore(Exam inExam)
    {
        String hql =
            "select avg(result.score) from Examresult "
                + "as result where result.exam=?";
        return getExamStats(hql, inExam);
    }

    static public String getExamStats(String hql, Exam inExam)
    {

        Session hibernateSession = null;
        Transaction myTransaction = null;

        String returnVal = "0";
        try
        {
            hibernateSession = sessionFactory.openSession();
            myTransaction =
                 hibernateSession.beginTransaction();

            Query myQuery = hibernateSession.createQuery(hql);
            myQuery.setLong(0, inExam.getId().longValue());

            returnVal = myQuery.iterate().next().toString();

            myTransaction.commit();

        } catch (Exception e)
        {

            e.printStackTrace();
            try
            {
                myTransaction.rollback();
            } catch (Exception e2)
            {
                // Silent failure of transaction rollback
            }
        } finally
        {
            try
            {
                if (hibernateSession != null)
                    hibernateSession.close();
            } catch (Exception e)
            {
                // Silent failure of session close
            }
        }
        return returnVal;
    }

    static public String getExamReport(Exam inExam)
    {

        Session hibernateSession = null;
        Transaction myTransaction = null;

        java.util.Iterator result = null;
        String returnVal = "0";
        try
        {
            hibernateSession = sessionFactory.openSession();
            myTransaction =
                 hibernateSession.beginTransaction();

            // In this example, we use the Criteria API.  We
            // could also have used the HQL, but the
            // Criteria API allows us to express this query
            // more easily.

            Criteria query =
            hibernateSession.createCriteria(Examresult.class);
            query.add(Expression.like("exam", inExam));
            // Now, specify sorting by the score
            query.addOrder(Order.desc("score"));

            // Indicate that we want to grab all of the
            // associated student IDs as well.  This
            // lets us pull all of the data in a single
            // SQL statement!
            query.setFetchMode("student.idString",
                 FetchMode.EAGER);

            // This actually performs the database request,
            // based on the query we've built.
            result = query.list().iterator();

            while (result.hasNext())
            {
                Examresult myExamResult =
                     (Examresult)result.next();
                report.append(myExamResult.
                     getStudent().getIdString());
                report.append("\t");
                report.append(myExamResult.getScore());
                report.append(newLine);
            }

            myTransaction.commit();

        } catch (Exception e)
        {
            e.printStackTrace();
            try
            {
                myTransaction.rollback();
            } catch (Exception e2)
            {
                // Silent failure of transaction rollback
            }
        } finally
        {
            try
            {
                if (hibernateSession != null)
                    hibernateSession.close();

            } catch (Exception e)
            {
                // Silent failure of session close
            }
        }
        return returnVal;
    }

    static public void generateReport()
    {
        Session hibernateSession = null;
        Transaction myTransaction = null;

        java.util.Iterator result = null;
        try
        {
            hibernateSession = sessionFactory.openSession();
            myTransaction =
                 hibernateSession.beginTransaction();

            // In this example, we use the Criteria API.  We
            // could also have used the HQL, but the
            // Criteria API allows us to express this query
            // more easily.

            Criteria myQuery =
                hibernateSession.createCriteria(Course.class);

            result = myQuery.list().iterator();

            while (result.hasNext())
            {
                Course myCourse = (Course)result.next();
                Iterator exams =
                     myCourse.getExams().iterator();

                report.append(myCourse.getTitle());
                report.append(newLine);
                report.append(myCourse.getQuarter());
                report.append(newLine);
                report.append(newLine);

                while (exams.hasNext())
                {
                    Exam myExam = (Exam)exams.next();
                    report.append(myExam.getComment());
                    report.append(newLine);

                    report.append("High Score: \t");
                    report.append(highScore(myExam));
                    report.append(newLine);

                    report.append("Low Score: \t");
                    report.append(lowScore(myExam));
                    report.append(newLine);

                    report.append("Average Score: \t");
                    report.append(averageScore(myExam));
                    report.append(newLine);
                    report.append(newLine);

                    getExamReport(myExam);
                    report.append(newLine);
                }

            }

            myTransaction.commit();

        } catch (Exception e)
        {
            e.printStackTrace();
            try
            {
                myTransaction.rollback();
            } catch (Exception e2)
            {
                // Silent failure of transaction rollback
            }
        } finally
        {
            try
            {
                if (hibernateSession != null)
                    hibernateSession.close();
            } catch (Exception e)
            {
                // Silent failure of session close
            }
        }
    }

    static public void initialization()
    {
        try
        {
            Configuration myConfiguration = new
                 Configuration();

            myConfiguration.addClass(Course.class);
            myConfiguration.addClass(Exam.class);
            myConfiguration.addClass(Examresult.class);
            myConfiguration.addClass(Student.class);

            // Sets up the session factory (used in the rest
            // of the application).
            sessionFactory =
                 myConfiguration.buildSessionFactory();

        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args)
    {
        // Places the generated report in the same directory
        // as this Java source file.
        java.io.File reportFile =
            new java.io.File(
                "com"
                    + fileSep
                    + "cascadetg"
                    + fileSep
                    + "ch04"
                    + fileSep
                    + "report.txt");

        // If the report file doesn't exist, generate the
        // default data set.
        if (!reportFile.exists())
        {
            GenerateData.main(null);
        }

        // Set up our session factory
        initialization();

        // Do all of the report generation
        generateReport();

        // Echo the results to the console
        System.out.println(report.toString());

        // Try to write the results to the report file
        try
        {
            FileOutputStream myOutputStream =
                new FileOutputStream(reportFile);
            myOutputStream.write(report.toString().getBytes());
        } catch (Exception e)
        {
            e.printStackTrace();
        }
    }
}

When this application runs, it will generate the report file. Before looking at the report, Listing 4.15 shows the SQL generated by Hibernate during the course of the run. While the SQL shown may seem complex, it's a lot easier to look at this generated SQL than to write the SQL by hand. Several statements are much more complex than what one might easily writein particular, the single lengthy statement which fetches both the Examresults and the associated Student records with a single query. Compare that SQL statement with the generating code, as shown in the GenerateReports.getExamReport().

Listing 4.15. SQL Generated by Hibernate
Hibernate: select this.ID as ID0_, this.title as title0_, this.quarter as quarter0_ from
 course this where 1=1
Hibernate: select exams0_.ID as ID__, exams0_.courseID as courseID__, exams0_.ID as ID0_,
 exams0_.date as date0_, exams0_.comment as comment0_, exams0_.courseID as courseID0_ from
 exam exams0_ where exams0_.courseID=?
Hibernate: select max(examresult0_.score) as x0_0_ from examresult examresult0_ where 
(examresult0_.examID=? )
Hibernate: select min(examresult0_.score) as x0_0_ from examresult examresult0_ where 
(examresult0_.examID=? )
Hibernate: select avg(examresult0_.score) as x0_0_ from examresult examresult0_ where 
(examresult0_.examID=? )
Hibernate: select this.ID as ID3_, this.score as score3_, this.studentID as studentID3_,
 this.examID as examID3_, student1_.ID as ID0_, student1_.firstName as firstName0_,
 student1_.lastName as lastName0_, student1_.idString as idString0_, exam2_.ID as ID1_,
 exam2_.date as date1_, exam2_.comment as comment1_, exam2_.courseID as courseID1_,
 course3_.ID as ID2_, course3_.title as title2_, course3_.quarter as quarter2_ from
 examresult this left outer
outer join exam exam2_ on this.examID=exam2_.ID left outer join join student student1_ on
 this.studentID=student1_.ID left
course course3_ on exam2_.courseID=course3_.ID where this.examID like ? order by this
.score desc
Hibernate: select max(examresult0_.score) as x0_0_ from examresult examresult0_ where 
(examresult0_.examID=? )
Hibernate: select min(examresult0_.score) as x0_0_ from examresult examresult0_ where 
(examresult0_.examID=? )
Hibernate: select avg(examresult0_.score) as x0_0_ from examresult examresult0_ where 
(examresult0_.examID=? )
Hibernate: select this.ID as ID3_, this.score as score3_, this.studentID as studentID3_,
 this.examID as examID3_, student1_.ID as ID0_, student1_.firstName as firstName0_,
 student1_.lastName as lastName0_, student1_.idString as idString0_, exam2_.ID as ID1_,
 exam2_.date as date1_, exam2_.comment as comment1_, exam2_.courseID as courseID1_,
 course3_.ID as ID2_, course3_.title as title2_, course3_.quarter as quarter2_ from
 examresult this left outer join student student1_ on this.studentID=student1_.ID left
 outer join exam exam2_ on this.examID=exam2_.ID left outer join course course3_ on exam2_
.courseID=course3_.ID where this.examID like ? order by this.score desc

Finally, the generated report, a tab-delimited text file, can easily be opened in any popular spreadsheet software and formatted and edited as needed, as shown in Figure 4.5.

Figure 4.5. Generated Report