This first tutorial gives you an opportunity to work with:
setting up a persistent unit,
creating in-memory entities and
persisting those entities to a database.
You’ll write the code such that the environment creates the database schema based on meta-information (annotations) in your entity classes.
Good luck!
JPA Tutorial 1: Background
title: JPA_Tutorial_1_Background
—
In this first tutorial we are going to perform some basic inserts, removes and queries against a database.
JPA allows us to work with entity classes, which are denoted as such using the annotation @Entity or configured in an XML file (we’ll call this persistence meta information). When we acquire the Entity Manager Factory using the Persistence class, the Entity Manager Factory finds and processes the persistence meta information.
To work with a database using JPA, we need an Entity Manager. Before we can do that, we need to create an Entity Manager Factory.
To acquire an Entity Manager Factory, we use the class javax.persistence.Persistence. It reads a file called persistence.xml in the META-INF directory. It then creates the named Entity Manager Factory, which processes persistence meta information stored in XML files or annotations (we only use annotations).
Creating an Entity Manager once we have the Entity Manager Factory is simple:
Once we have an Entity Manager, we can ask it to perform several operations such as persisting or removing an entity from the database or creating a query.
Term
Description
javax.persistence.Persistence
This is a class used as an entry point for using JPA. The primary method you’ll use on this class is createEntityManagerFactory(“someName”) to retrieve an entity manager factory with the name “someName”. This class requires a file called persistence.xml to be in the class path under a directory called META-INF.
EntityManagerFactory
An instance of this class provides a way to create entity managers. Entity Managers are not multi-thread safe so we need a way to create one per thread. This class provides that functionality. The Entity Manager Factory is the in-memory representation of a Persistence Unit.
EntityManager
An Entity Manager is the interface in your underlying storage mechanism. It provides methods for persisting, merging, removing, retrieving and querying objects. It is not multi-thread safe so we need one per thread. The Entity Manager also serves as a first level cache. It maintains changes and then attempts to optimize changes to the database by batching them up when the transaction completes.
persistence.xml
A required file that describes one or more persistence units. When you use the javax.persistence.Persistence class to look up an named Entity Manager Factory, the Persistence class looks for this file under the META-INF directory.
Persistence Unit
A Persistence Unit has a name and it describes database connection information either directly (if working in a JSE environment) or indirectly by referencing a JNDI-defined data source (if working in a managed/JEE environment). A Persistence Unit can also specify the classes(entities) it should or should not manage .
Persistence Meta Information
Information describing the configuration of entities and the database and the association between entity classes and the persistence units to which they relate. This is either through annotations added to classes or though XML files. Note that XML files take precedence over annotations.
JPA Initial Setup
title: JPA_Tutorial_1_Initial_Setup
—
This example requires Java 5 (JDK 1.5) or later and Eclipse 3.2 or later. This page gives you a link to all of the downloads you’ll need to get to get started. While I might mention specific version numbers, it’s a good bet that newer versions should work as well… of course that’s not always the case.
Note: We need the jar file that contains javax.persistence and the various annotations associated with JPA. You can either download JEE or get it from somewhere else. For this series of tutorials, we eventually use the JBoss EJB3 Embeddable container, so we’ll use that to avoid an extra 150+ meg download for one jar file.
Download Everything
First the basic stuff:
Download JSE 5 (choose just JDK 5.0 (there will be an update after it))
Extract the eclipse download somewhere. For all examples I use C:/eclipse.
Extract Jar Files
Extract each of the libraries to some location. In my case I extracted everything to C:/libs, so I have the following directories
Eclipse Project Setup
title: JPA_Tutorial_1_Eclipse_Project_Setup
—
Next we need to start eclipse and create a workspace.
Create Initial Project
Start eclipse.
When prompted, enter a directory for your workspace. I used C:\workspaces\JpaAndEjb3. To understand why I recommend not using a space in the name, read this sidebar.
Close the Welcome window
User Library
We are going to define a user library, which is just a collection of jar files with a name.
Once we create this, we can add it to our classpath with one command. This also makes setting
up new projects in the same workspace a snap. We can also export workspace settings and import them into a new workspace.
Pull down Window:Preferences
Navigate to Java:Build Path:User Libraries
Click on New
Enter JPA_JSE for the name and click on OK
Now we need to add several jars to this list. For each of the following jars, do the following:
Select JPA_JSE (after you add the first one, you’ll have to go back and click the library, which seems to be a poor UI design)
Click on Add JARs…
Navigate to the jar file
Select the jar file
Click on Open
Repeat at step one.
Here is a list of all the jar files you’ll need to add (note the path’s listed assume you extracted your jar files to C:/libs):
Create Java Project
Next we need to create a Java project. We’ll keep the source separate from the bin directory:
Pull down the File menu and select New:Project
Select Java Project and click Next
Enter a project name: JpaTutorial1, again read this sidebar to know why I did not use a space in the project name.
Make sure “Create new project in workspace” is selected.
Make sure the JRE selected is 1.5.x. If a 1.5 JRE does not show in the list, you can add it through Window->Preferences->JAVA->Installed JRE’s.
Select “Create separate source and output folders”
Click “finish”
Create folders and packages
Expand your project JpaTutorial1
Select the src folder
Right-click, select new:Folder
Enter the name META-INF
Click Finish
Select the src folder again
Right-click, select new:Package
Enter the name entity
Click on Finish
Select the Tutoria1 project again
Right-click, select new:Source Folder
Enter the name test
Click Finish
Select the test folder
Right-click, select new:Package
Enter the name entity
Add Required Libraries
We now need to add two libraries. One will be the user-defined library we created above. The second will be JUnit 4.x.
Edit the project properties. Select your project (e.g. JpaTutorial1) and either press alt-enter or right-click and select properties.
Select Java Build Path
Click on the Libraries tab
Click on Add Library
Select User Libraries and click Next
Select JPA_JSE by clicking on the checkbox
Click OK
Click on Add Library again
Click on JUnit
Click Next
In the pull-down list, select JUnit 4
Click Finish
Click OK
Persistence Unit Configuration
title: JPA_Tutorial_1_Persistence_Unit
—
We now need to create the Persistent Unit definition. Create a file called persistence.xml in the src/META-INF directory with the following contents:
persistence.xml
The Steps
Expand your project (JpaTutorial1)
Select the src/META-INF directory
Right click and select new:File
Enter persistence.xml for the name and press Finish (Note: all lowercase. It won’t make a difference on Windows XP but it will on Unix.)
Copy the contents (above) into the file and save it.
Verify This Works
Select the test
Right-click on entity and select new:Class
Enter PersonTest and click Finish
Enter the example code below:
When you’re finished and it all compiles, right-click within the source pane, select Run As:JUnit Test
You should see all green
If you do not, comment out the following line and review the console output
Create Your First Entity
title: JPA_Tutorial_1_First_Entity
—
For this example we’ll use a “top-down” approach. This means we’ll create a Plain Old Java Object (POJO) with some annotations to indicate how we want JPA to persist it. We’re letting the EntityManager take care of creating the tables in the database for us.
Create a Simple Class
The following class contains everything you need to begin persisting it to a database:
Person.java
Update persistence.xml
Note, for our configuration this step is optional.
If you use libraries provided exclusively by JBoss and Company, then you do not need to update your persistence.xml. If you are using another vendor or you want to make sure that your solution will work regardless of your persistence provider, add the following line to your persistence.xml:
Your updated persistence.xml is now:
Inserting and Querying
Now we need to update our unit test class, Person.java. We will have it insert two people, query and verify that the people we created are in the database:
PersonTest.java
Re-run this test (the short-cut for this is Ctrl-Fll). Verify that everything is green.
Add an Embedded Entity
title: JPA_Tutorial_1_Embedded_Entity
—
When we created Person we directly included address information into them. This is alright, but what if we want to use Address in another class? Let’s introduce a new entity, Address, and make it embedded. This means its fields will end up as columns in the table of the entity that contains it.
First, we’ll create Address:
Address.java
Next, we need to update Person (doing so will cause our unit test class to no longer compile):
Person.java
Sure enough, if you review PersonTest.java, it no longer compiles. Before we go any further, let’s update it to get it to compile and then verify that the unit tests still pass.
Replace the following two lines:
with the following four lines
Rerun your tests (Ctrl-F11) and make sure everything is all green.
Next, we want to verify that the address we persist is in the database. Update the unit test method as follows:
PersonTest#insertAndRetrieve
Run your program and make sure it’s all green.
Add an Entity with a One to Many Relationship
title: JPA_Tutorial_1_Entity_with_One_to_Many_Relationship
—
Now we’ll make a company. In this first tutorial we’re keeping things simple so we’ll just create a Company that has a 1 to many relationship with People, who are its employees:
Company.java
Factor out Common Test Code
We have some common initialization we can move up into a base since we are going to have two tests classes, PersonTest and CompanyTest:
TestBase.java
Update PersonTest.java to remove the two fields, emf and em and the initEmfAndEm() and cleanup() methods.
PersonTest.java
Make sure everything is green before going on (rerun using Ctrl-F11).
Now we need to create a new CompanyTest class. Here’s the first version:
Run this unit test and make sure it is all green before going on (right-click in the source pane, select Run As:JUnit Test).
If you’d like to run all of your tests, right-click on the test folder, select Run As:JUnit Test and eclipse will execute all of your tests classes’ test methods.
Hire some people
We need to create some people and add them to the company. The PersonTest class already has some people. Rather than re-creating new people, let’s update PersonTest to make those fields available. Update the a1, p1, a2, and p2 fields as follows:
You will also need to update the beginning of the method insertAndRetrieve from:
to:
Now we’ll add a new test into CompanyTest to verify that we can hire people:
Update persistence.xml
Again, given our environment, this step is optional.
persistence.xml
Make sure everything compiles and runs green.
Make a Relationship Bi-Directional
title: JPA_Tutorial_1_Make_Relationship_Bi-directional
—
Now we’re going to make sure the Person knows the Company for which it works. This is the “one” side of a one to many relationship. We need to explicitly set this value and map it. We also need to update the Company @OneToMany relationship so that the Entity Manager knows it is a bi-directional relationship rather than just two unidirectional relationships.
First we need to update Person:
Person.java
Next, we’ll change Company to maintain both sides of the relationship:
Before going any further, make sure all of your tests still run green.
We are now adding and removing Person objects from collections. To make this work, we need to add an equals() method and a hashCode() method to the Person class:
Finally, we’ll update CompanyTest in several stages:
First, add a utility method to retrieve companies by name:
Add another support method to create a company and hire a few people:
The method createCompany used to directly lookup a company by name. Update the test method to use this private method by changing this line:
to:
Update the method createCompanyAndHirePeopl by using the support method createCompanyWithTwoEmployees():
Finally, add an additional unit test to hire and fire people:
Make sure everything compiles and is green.
Exercises
title: JPA_Tutorial_1_Exercises
—
Questions
Describe what the @Entity annotation means to a class.
Describe what the @Id annotation means to a class.
Describe what the @GeneratedValue means to a class
Describe the difference between @Embeddable and @Embedded
In the previous section we mentioned using** mappedBy** to let the container know this was a bi-directional relationship instead of a unidirectional relationship. What does this even mean? Draw an instance diagram that would explain this difference.
New Class
Right now the relationship between Person and Company is direct. Let’s make that a little less direct. The Person should now have a Job with a title, salary and employeeId. The company still has employees as before. This picture describes the before and after relationships.
In order to refactor to the [above] “after” picture consider some of the following advice:
Create Job
Create a class, Job, with the following attributes:
Update Employee
The Person class should no longer have a Company attribute. Instead it has a Job attribute.
Update Company
Update Company.hire(). Change the signature to take a person, title, salary. It will then create the job, generate an employeeId, and set up all the relationships and return the job.
Update the Company.fire() as necessary.
Advanced: Person can have multiple jobs
Make the relationship between Person and Job 1 to many. Now fix everything to make it work.
Advanced: First cut at a Data Access Object
If you look at your various unit tests, there are several places were they perform direct queries, inserts and removes. Move all of the code behind one or more Data Access Objects. Update your unit tests to use the Dao’s.
Entire Source Base
title: JPA_Tutorial_1_Entire_Source_Base
—
Address.java
Person.java
Company.java
TestBase.java
CompanyTest.java
PersonTest.java
FAQ
title: JPA_Tutorial_1_FAQ
—
JPA Tutorial 1 - FAQ
What’s the entity Manager? Object cache which persists entities. Manages any objects with the @Entity annotation. Allows starting/stopping transactions, crud’ing database. “Your facade to working with the database”
Is hibernate using an in-memory database? Hibernate is one implementation of JPA. It connects to the database through a jdbc url. The database we use in the early exercises is Hypersonic SQL.
When do you need a default constructor? Spec says you always need it. If there are no other constructors, java provides the default constructor. If you add a single constructor (w/parms), keep in mind the default constructor is removed by java.
Annotations? Annotations are type-safe meta-data about a class. They can target fields/methods/classes. Reflection allows you to query the state of any annotation. Annotations have ‘lifetimes’ (compile-time, load-time, run-time).
Compared to toplink: How are isolation levels handled? What kind of caching concerns do we have to worry about? There will be similiar challenges in tuning.
JEE source? Download from JBoss (svn) or get from Brett.
Where does @Id go? (method or field?) If it’s on an attribute, JPA will only look for annotations on fields, and use reflection to access fields (without getter’s and setter’s). If it’s on a method (getId()), JPA will only look for annotations on methods, and will use getter’s and setter’s to access fields.
Is there a reason @id is not private? Brett forgets things as he gets older. (It should be private)
**When creating the job class, do we need equals() and hashcode()? ** not yet
In Company.java there is a lazy-initialization in getEmployees() . Why? When you retrieve from the db, hibernate creates an object with newInstance (reflection). Lazily initializing the employees collections could decrease unnecessary garbase collection when retrieving large result sets. This is just a consideration (not always the ‘best’ way).
What’s with the equals() method on Person? You don’t want an equals() who’s value changes over time. (pre-insert, the id might be null, post-insert, it would have a value)
**How many times does it go to the database when you have a one-to-many and you retrieve the ‘one’ side. ** By default, once for the root (‘one’) object, and then one or more times (up to the container’s discretion) to retrieve the ‘many’ side – as you iterate through the collection. You can override with fetch=FetchType.EAGER (to fetch with a join and retrieve everything up front). See the actual sql with hibernate.show_sql=true.
Can you turn off the ‘caching’ part of JPA?You can define transactional boundries to limit the scope of the cache. Look up ‘report queries’ for some examples.
**How do you know what you set ‘mappedBy’ to? ** Use the name of the field that defines the relationship
**What happens if you manipulate your objects outside of a transaction? ** In a JSE environment, objects are still managed by the EntityManager. So if you make a change to an object, then later start a transaction and commit it, the changes made outside of the transaction are also sent to the database. If, on the other hand, you close the EntityManager or flush it, the changes are lost.
Brett: What have you learned in this tutorial?
Class responses:
Eclipse is good
JPA hides a lot of JDBC complexity.
How to define relationships of entities
Using entity notations
Responses to questions in the exercises
**What does @Entity do? **
defines a class as being an entity bean.
Tells container what behavior to add through bytecode instrumentation or dynamic proxies
**What does the @Id do ? **
defines primary key
required for entities
only @Id fields can be passed into the em.find(class, id) method
**What does the ‘generatedValue’ do ? **
automatically assigns id based on the defined strategy
**What’s embeddable vs. embedded? **
Defines how the data is stored in the db. (serialization vs fields being persisted to columns)
Day 1 Review
What we learned today . . .
JUnit
many-to-one & vice versa (bi-directional)
Annotations & JUnit
Eclipse
Entity Managers
hibernate
refactoring
eclipse shortcuts, embeddable stuff, understanding the relationships
eclipse shortcuts (!)
identifying annotation and attributes/properties
static imports
persisting all the entities (without using cascade attributes)
feedback so far on the class format
“better than just hearing somebody talk”
hands-on is good, maybe should have an overview at the beginning though. “pedagogical”
Comments