Download JPA - KSU Web Home

Survey
yes no Was this document useful for you?
   Thank you for your participation!

* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project

Document related concepts

Oracle Database wikipedia , lookup

Microsoft SQL Server wikipedia , lookup

Serializability wikipedia , lookup

SQL wikipedia , lookup

Extensible Storage Engine wikipedia , lookup

Open Database Connectivity wikipedia , lookup

PL/SQL wikipedia , lookup

Entity–attribute–value model wikipedia , lookup

Microsoft Jet Database Engine wikipedia , lookup

Database wikipedia , lookup

Concurrency control wikipedia , lookup

Relational model wikipedia , lookup

Clusterpoint wikipedia , lookup

ContactPoint wikipedia , lookup

Versant Object Database wikipedia , lookup

Database model wikipedia , lookup

Transcript
Java Persistence
7.1 Persistence Basics
7.1.1 Introduction
Java objects that represent an application's data model must undergo
some transformation in order for the information they contain to be saved in
a database. The traditional method of persisting object information to a
database is to use the Java Database Connectivity API (JDBC). JDBC allow
Java programs to interact with a relational database by exposing a
programming interface that allows the programmer to embed SQL
statements into an application's source code. To save an object to a database
the programmer would create a SQL statement that mapped object data into
table columns and then execute the SQL statement. Some of the drawbacks
to this early approach include:
 Programmers must be proficient with SQL in addition to Java in order
to persist data.
 Embedding SQL in the program means that the database-specific code
might be spread out through multiple files in an application, making
changes and debugging difficult
 Programmers must deal with time-consuming tasks like determining if
a particular record already exists in the database. This leads to a lot of
redundant boiler-plate code.
 Complex data structures and relationships can be difficult and timeconsuming to map by hand.
Some time later the J2EE specification introduced Entity Beans 2.x. While
they were a step in the right direction, programmers found them to be
prohibitively complex. In response to this the Enterprise Java Beans 3
specification completely did away with Entity Beans and replaced it with
JPA. Although JPA has some complexity (transforming an object into
something that can be used efficiently by a relation database is a complex
problem), it is much simpler than previous attempts.
JPA bridges the two separate domains of relational databases and objectoriented programming by using object-relational mapping (ORM). JPA
takes the objects you specify and converts them automatically to rows in a
relational database, saving the time and hassle of writing all the boilerplate
code involved in opening connections, updating database relations, and
tidying up after the connections.
Java and SQL cover different domains and represent data in different ways.
For example, relations in a DBMS cannot be nested. That is, a table cannot
contain or encapsulate another table the way a Java object can contain
another object. If an e-commerce site is using JPA to save orders to a
database, it may contain an Order object that contains information about the
order (when it was placed, the total amount, etc) and an array of LineItem
objects that represent each item in the order and the quantity ordered. In a
relational database the line items must be in a separate table. The order table
would contain the information corresponding to the Order object and a
line_item table would contain the information associated with each LineItem
object. JPA will do the heavy lifting behind the scenes to make this
conversion happen, but the programmer must supply the information about
the ways the different objects relate to each other.
7.1.2 Entity Classes
The basic element of JPA is an entity class. Entity classes make up the
model in the MVC design pattern. Essentially an entity is a plain old Java
object (POJO) that holds data for the purposes of saving that data in a
database. An entity class has the following characteristics:

The class is annotated with the @Entity annotation so that the
Enterprise container will recognize it as an entity class.

The class's member variables should not be public. Access to the
variables should be through accessor (getter) and mutator (setter)
methods.

The class should have a no-argument constructor. It may have other
constructors, but the no-argument constructor must exist.

The member variables that will be persisted to a database should be
primitive types , serializable classes (such as java.util.Date), or classes
that implement the Collection interface (like Lists or Sets).
List 7.1 shows a simple entity class;
@Entity
public class Customer {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
protected String ssn;
@Column(name=”full_name”)
protected String name;
}
A simple entity class <Listing 7.1>
As you can see from list 7.1 an entity class is a simple POJO class decorated
with some annotations. These annotations are the magic that make all of the
object-relational mapping work. Entity classes should have the @Entity
annotation applied so that Java can tell that it is supposed to be an entity
class instead of a simple non-persistent class. The ssn member variable has
two annotations, @Id and @GeneratedValue. Each entity must have an @Id
annotation. This tells JPA that the data element is the primary key in the
database. Without a primary key JPA would have no way to distinguish one
record from another in the database. The @GeneratedValue annotation is
optional and we will look at it further in the next section.
The name member variable is annotated with @Column. This is an optional
annotation that tells JPA that the database column name for this variable is
full_name. If this annotation was not present JPA would look for a column
with the same name as the variable. Because the ssn String has no
@Column annotation JPA will look for a column named “ssn” to store the
contents of the name String.
The entity class in listing 7.1 uses persistent fields. An entity class may use
either persistent fields or persistent properties depending on where the
annotations are placed. If the annotations are applied to the member
variables then the entity will use persistent fields. If persistent properties are
used, then the member variable's accessor (getter) method would be
annotated. If persistent properties are used then JPA will use the getter and
setter methods when persisting the object to the database. If persistent fields
are used then it will access the fields directly. An entity class may use either
persistent fields or properties, but cannot mix the two in the same class (or
class hierarchy if there is any inheritance is involved). It is often convenient
to use persistent fields because the corresponding getter and setting methods
do not need to be written. The convenience comes at a price, however, since
accessing the fields directly means giving up some of the benefits of
encapsulating the fields in an object-oriented manner such as validating the
data in the setter methods. To offset the inconvenience, NetBeans provides
a quick way to generate getter and setter methods which we will see later.
If persistent properties are used, the getter and setter methods for each
persistent property must conform to the JavaBeans convention, including:

Accessor methods are in the form of type getXyz() for variable xyz

Mutator methods are in the form of setXyz(type xyz) for variable xyz

Boolean accessor methods may be named isXyz() instead of getXyz()
The annotations for persistent properties must be applied to the getter
methods. Annotations applied to setter methods will be ignored.
Composite Key:
A primary key in a database table need not be a single column. Likewise an
entity's Id doesn't have to be a single variable. Consider the simple class that
keeps track of software installed on a company's workstations in Listing 7.2.
The class has fields for the software name, version, and the number of
licenses the company owns. Using the name field as an entity Id may cause
problems since there may be different versions of the same software
installed on different computers. The software name and version must be
used together to uniquely identify a particular Software object. Using
multiple @Id annotations would be problematic sine we need a clearly
defined way to determine if two Id's are the same. We can use a primary
key class to represent both values in one tidy package with the @IdClass
annotation. The primary key class will include the logic to compare itself
against another primary key class to determine if they are the same by means
of the equals(Object otherObject) method.
public class Software {
String name;
String version;
int licenses;
}
A simple entity representing installed software licenses <Listing 7.2>
A primary key class must follow some simple conventions:

It must have a no-argument constructor.

It must be declared public and the fields or properties declared public
or protected.

It must implement the Serializable interface.

It must implement an equals(Object otherObject) method and the
hashCode() method.

The names of the fields or properties must match the names in the
entity it represents exactly.
Listing 7.3 shows the SoftwareId class and the corresponding Software
entity class. The member variables have been made public and accessed
directly to keep the listing short although in a real implementation the Id
class would use getter and setter methods.
public class SoftwareId implements Serializable {
public SoftwareId() {
}
public boolean equals(Object o) {
if(o instanceof SoftwareId) {
return name.equals(o.name) &&
version.equals(o.version);
}
else {
return false;
}
public int hashCode() {
return super.hashCode();
}
public String name;
public String version;
}
@Entity
@IdClass(SoftwareId.class)
public class Software {
@Id
public String name;
@Id
public String version;
public int licenses;
}
Software entity and its IdClass SoftwareId <Listing 7.3>
7.2 Entity Relationships
It would be difficult to model an entire application around a single entity
class. A non-trivial application will have several entity classes making up
the data model. These entities usually have some sort of relationship to each
other. Take for example an application for a university that keeps track of a
student's GPA. The data model would include a Students who are assigned
Grades for taking Courses. In addition a GPA is maintained for each
Student and stored separately. The Java objects represent these relationships
by maintaining references to other objects to which they are related. The
Student class would have an array (or a List or other Collection in an entity
class) of Grade objects. Each Grade object could in turn have a reference to
the Student object that it is assigned to. So Student instance student1 would
have a list of Grade objects accessible my means of the getter method
student1.getGrades(). Each Grade in the list would have a
grade.getStudent() method that would refer to the student who earned the
grade. In order to tell the ORM provider how to store this relationship
information in the database correctly and efficiently we must provide
information about the multiplicity of these relationships.
7.2.1 Multiplicity
Multiplicity refers to the number of object instances that can participate in
the relationship. The objects relate to each other in the following ways:
Each Student takes many Courses
Each Course has many Students enrolled in it
Each Grade is assigned to only one Student
Each Student may be assigned several Grades (from taking several
courses)
Each Student has a single GPA
Each GPA belongs to a specific Student
Diagram showing the relationships between Course, GPA, Grade, and
Student. The triangular arrows indicate that many of these entities
participates in the relationship. <Figure 7.1>
There are several different relationships here (see figure 7.1) which we will
examine one at a time.
One To One
The Student and GPA objects participate in a one to one relationship. A
single Student may have one (and only one) GPA. Likewise, a GPA may
belong to only one student. Note that this does not mean that two students
may not have the same value for their grade point average. It simply means
that each Student object will hold its own unique instance of a GPA object,
regardless of what value that object holds. A one to one relationship is
signaled by annotating the appropriate field or property with the
@OneToOne annotation.
One To Many
The Student object contains a List of Grade objects. This is a one to many
relationship since one Student contains many Grades. Remember that in an
entity class the many part must be a reference to a Java Collection (such as a
List or Set of objects) of objects and not just a simple object reference. To
declare a one to many relationship, annotate the Collection field or property
with the @OneToMany annotation.
Many To One
The many to one relationship is the direct inverse of the one to many
relationship. In our example each Grade has a reference to the Student it is
assigned to, so the Student field or property in the Grade object would be
annotated with the @ManyToOne annotation.
Many To Many
The Student and Course entities have a many to many relationship. That is,
a Student may take many Courses and a Course may have many Students in
it. To distinguish a many to many relationship from a one to many
relationship the @ManyToMany annotation is used on the corresponding
Collection field or property.
7.2.2 Direction and Ownership in Relationships
Relationships between entities may be unidirectional or bidirectional. A
unidirectional relationship goes one way. An example would be a Student
entity that has a reference to a GPA entity but the GPA entity does not have
a corresponding Student reference. The distinction is important because it
restricts the path you can take to get to any particular piece of data. A
unidirectional relationship from Student to GPA mean that, given a
particular Student you can find the GPA associated with it. If you have a
particular GPA entity, however, you cannot find out which Student it
belongs to without making the relationship bidirectional.
In practice what this means is that the Student entity has a reference to a
GPA entity as one of its persistent fields or properties which has been
annotated with the appropriate relationship annotation (@OneToOne in this
example). To make the relationship bidirectional we must add a persistent
Student entity to the GPA entity and tag it with the corresponding
relationship annotation. For Student and GPA, both entities will have the
@OneToOne annotation on the field or property representing the other
entity.
Care must be taken when dealing with bidirectional many to one
relationships, however. While a Student entity has a List of Grade entities
marked as @OneToMany, the Grade entity will have a single Student entity
field or property annotated with @ManyToOne. Because many to one is the
inverse of one to many you must change the annotation when the direction
changes. You can think of it from the point of view of the entity you are
annotating. @OneToMany means one of this entity (the one you are adding
the annotation to) to many of an outside entity. Likewise @ManyToOne
means there will be many of this entity to one outside entity. The two fit
together to represent a bidirectional relationship from each entity's point of
view. Many to many bidirectional relationships are similar to one to one
relationships in the sense that the same annotation is used on both entities
participating in the relationship since the relationship appears the same from
both sides.
When bidirectional relationships are used one of the entities must be
specified as the owner. Ownership simply means that one of the entities is
responsible for maintaining the relationship. There is no extra programming
involved in maintaining the relationship, it is a matter of which of the tables
in the relational database has the primary key and which one as the foreign
key. In many to one relationships the many side is always the owning side
(that is, the side with the @ManyToOne annotation). The one to many side
cannot be the owning side in JPA. For one to one and many to many
relationships either side may be the owning side.
To make clear which side is the owning side of a relationship we add some
additional parameters to the side that does not own the relationship. The
entity which does not own the relationship will have the mappedBy=”XXX”
property set in the relationship annotation where XXX is the name of the
field or property in the other entity that refers to this one. All of the
relationship annotation support the mappedBy property except
@OneToMany, since it cannot be the owning side of a relationship. In
addition, the @OneToOne and @ManyToOne annotations have a property
named optional which defaults to “true.” If this is set to false then the entity
that is annotated must exist. That is to say that the entity reference cannot be
null in the object. For example, our annotation in the GPA entity which
refers to the Student entity would have the optional parameter set to false.
This mean that in order to have a GPA entity we must also have a Student
entity for it to refer to. It would not make much sense to have GPA records
that did not belong to any student.
7.3 Storing and Manipulating Entities
So far we've looked at entities, how they are annotated, and how they relate
to each other. Now we will discuss how to make use of them with the
EntityManager interface.
7.3.1 Persistence Context and EntityManager
The persistence context is the collection of managed entities in a particular
data store. The persistence context is manipulated by means of the
EntityManager interface. Unlike session beans, entities are not directly
managed by the enterprise container. They are managed by the persistence
context (which does not require an enterprise container). The
EntityManager is the the means by which an application accesses the
persistence context.
Entity Life Cycle <Figure 7.2>
Entities exist in one of four distinct states: detached, managed, new, or
removed (see figure 7.2). New entities are just that – new. When you create
a new instance of an entity class you have an entity in the new state. Once
an entity has become managed it is represented in the data store and is
associated with a persistence context. An entity becomes managed when it
is persisted to the data store using the EntityManager (which we will see
shortly). An entity may become detached if it is serialized or if the
EntityManager it is attached to goes out of scope (at the end of a method if
the EntityManager instance is local the method, for example). Finally an
entity enters the removed state when it has been removed from the data store
by the EntityManager. Although the record is gone from the data store the
entity itself may still be around in the application until it goes out of scope.
In an enterprise application the EntityManager is obtained by injecting it into
a managed component (like a session bean) through the
@PersistenceContext annotation. This is typically all that is required to use
entities in a session bean. Using JPA in a servlet typically requires a little
more care, however. Servlets may also have an EntityManager injected in
this manner, but it usually is not a good idea to do so because the
EntityManger is not thread safe. Thread safety is an important consideration
with servlets since a single servlet instance may handle all incoming
requests, so instance variables may be shared. When using JPA with
servlets it is better practice to inject the thread safe EntityManagerFactory
using the @PersistenceUnit annotation and use it to obtain an
EntityManager through its createEntityManager() method.
All EntityManager operations must take place within a transaction. A
transaction is a set of individual actions that must be performed as a single
unit. Imagine an application that keeps track of payments for a bank. When
a customer pays with a debit card, two things have to happen. The
customer's account must be debited by the amount of the purchase and the
seller's account must be credited by the same amount. Both of these can be
handled by entity beans representing the different accounts. If the bank's
data center has a power outage between the time the customer's account
entity is saved to the database and the time the seller's account entity is
saved, then the money is effectively lost. It has been subtracted from the
customer's account but was never added to the seller's account. This is
certainly sub-optimal and leads to angry customers. Transactions enforce an
all-or-nothing approach to all of the entity operations they contain. If one
part of the transaction fails, then all parts have failed and must be undone so
that the database is not left in an inconsistent state. After all an inconsistent
database is arguably worse than no database at all.
In a session bean the container takes care of all of the transaction details
behind the scenes automatically as part of the Java Transaction Architecture
(JTA). When an EntityManager is injected into a session bean the container
has already made sure that it is associated with a transaction. In a servlet,
controlling the transaction requires a little more work involving a
UserTransaction object. A UserTransaction object may also be injected into
the servlet with the @Resource annotation to provide transaction control.
Beginning and ending the transaction is as simple as surrounding the
EntityManager method calls with the UserTransaction's begin() and
commit() methods. We will show an example of this usage in section 7.4.
7.3.2 Manipulating Entities
Relational databases support four basic operations: create, read, update, and
delete (often abbreviated CRUD). It is not surprising that the EntityManager
offers methods corresponding to each of these four operations.
For creating new records in the database the void
EntityManager.persist(Object entity) method. This method will take a new
entity and persist it to the database, perforiming the JPA analog of a Create
database operation. The entity that was persisted will enter the managed
state. Unless the entity's Id field or property is automatically generated there
may be the possibility of trying to create a record with the same Id as an
existing record. In order to avoid this you should make sure that the Id field
or property does not already exist in the database (see section 7.3.3).
The <T> T EntityManager.find(Class<T> entityClass, Object primaryKey)
method corresponds to a database's Read operation. When passed in the
class of the entity you need and its Id value as parameters, the find method
will retrieve the entity from the database and return it. The returned entity
will be in the managed state.
<T> T EntityManager.merge(T entity) performs the JPA version of the
database's Update operation. The values held in the entity will be merged
with the existing record in the database. When dealing with a managed
entity there are, at any given time, two versions of the entity – one that has
been persisted to the database's data store, and one that resides in memory in
the Java application. This method will effectively synchronize the two by
making the version in the database match the version represented by the Java
object. If this is not the desired result and the Java object must instead be
made to match the database version, then a different method is needed. The
void EntityManager.refresh(Object entity) method will synchronize the two
versions in the opposite direction, making the Java object match the version
in the database.
The final database operation, Delete, is performed by the void
EntityManager.remove(Object entity) method. This method will remove the
record that corresponds to the entity from the database and place the entity in
the removed state.
The relationship annotations discussed in section 7.2.1 support the optional
named parameter cascade. This parameter specifies whether persistence
operations such as saving to or deleting from the database follow the
relationship links between entities, similar to the way cascading works in
relational databases. For example, if we have a Grade entity that belongs to
a Student entity and both are in the new state, one might expect that
persisting the Student entity would also save the Grade entity to the
database. By default, this is not the case. If this is the desired behavior, the
cascade parameter may be set to one of the following values:
CascadeType.ALL – all operations (persist, merge, refresh, and remove)
follow the relationship.
CascadeType.MERGE – only merge operations are cascaded to the
referenced entities.
CascadeType.PERSIST – only persist oerations are cascaded to referenced
entities.
CascadeType.REFRESH – only the refresh operation is cascaded to the
referenced entities.
CascadeType.REMOVE – only the remove oeration is cascaded to
referenced entities.
Cascading can be helpful some situations, keeping the developer from
having to call EntityManager methods on multiple related entities when new
entities are persisted or old entities removed. It should be used judiciously,
however. If relationships are set to cascade remove operations it is possible
to accidentally remove more than you intend. For example, if the Grade and
Student relationship is bidirectional and set to cascade remove operations,
then removing a Grade could remove the Student it is assigned to as well.
7.3.3 Finding Entities
While performing CRUD operations makes the EntityManager a very useful
tool, there is one more method that makes it invaluable. The Query
EntityManager.createQuery(String qlString) method plays and important
role in retrieving data. It allows a query to be sent to the database and a
Query object which contains the results of the query. The reason this is so
useful is because an Id value is required to retrieve an entity from the
database using the EntityManager's find method. Even if you have a
person's name, birthdate, and address you will have a difficult time
retrieving the entity instance associated with that person without the Id. To
fnd the entity's Id or a set of possible Id's you would create a query and
retrieve the Id from the results (see Listing 7.4).
Query q = EntityManager.createQuery(“select p from
person p where
p.name = 'John Doe' and
p.birthdate = '1977-08-21'”);
Person p = q.getSingleResult();
String ssn = p.getSSN();
A query created to find an entity's Id when other information is known
<Listing 7.4>
You may have noticed that the syntax is similar to SQL. This is no
coincidence. It is not SQL, however, but a special language designed for
retrieving entities from a database called the Java Persistence Query
Language (JPQL). EntityManager's createQuery method also has a close
relative called createNativeQuery which takes a SQL statement to send to
the database. This may be simpler for developers who are familiar with
SQL and who know what kind of database their entities will reside in, but
has the potential to reduce the portability of the entities since some databases
may have slightly different syntax or vendor-specific features that are
unsupported elsewhere.
The major difference between JPQL and SQL is that SQL is designed to
retrieve specific rows from a table made up of columns specified in the
query. For example, selecting the last name and first name of all people in
Oklahoma might look like this: “select last_name, first_name from people
where state = 'Oklahoma'”. The columns that are returned are specified in
the select clause, the table to look is specified in the from clause, and the
conditions to match on appear in the where clause. JPQL on the other hand
is designed to operate on entities. The same query in JPQL might be written
as: “select p from person p where p.state = 'Oklahoma'”. The columns aren't
specified in the select clause because entities or entity properties are returned
instead of certain specified columns. Here p refers to person (the entity
which shows up in the from clause). In essence the query is saying “Look in
the person storage for a person entity that has its state member set to the
value 'Oklahoma'.”
The createQuery method returns a Query object. The Query object has
several methods used to retrieve the results. getResultsList() will return a
List containing the resulting entities from the database. getSingleResult()
will return a single entity. Once you have retrieved the entity you are
looking for you may manipulate it using the EntityManager's CRUD
methods because you now know its unique Id.
7.4 Your First JPA Application
Now that we have covered the basics of the Java Persistence API we will
construct a simple application to try it out. We will create a simple guest
book application that records the first and last name of visitors who visit the
website.
1. Open the NetBeans IDE
2. Choose File → New Project
3. Choose Java Web from the Categories menu on the left and choose
Web Application from the Projects menu on the right and click
“Next”
4. Name the project “MyFirstJPA” in the Project Name box and click
“Next”
5. Choose GlassFish V2 as the Server and click “Finish” to create the
project
6. Open the automatically generated index.jsp that was created in the
project and replace the default HTML with the following:
<%@page import="java.util.*"%>
<%@page import="myfirstjpa.entities.*"%>
<%@page contentType="text/html" pageEncoding="UTF8"%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01
Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type"
content="text/html; charset=UTF-8">
<title>JPA Guest Book</title>
</head>
<body>
<%
List<Guest> guestList = (List<Guest>)
request.getAttribute("guestList");
if(guestList != null) {
Iterator<Guest> itr = guestList.iterator();
while(itr.hasNext()) {
Guest g = itr.next();
%><%=g.getLastName()%>,
<%=g.getFirstName()%><br/>
<%
}
}
%>
<form method="post" action="GuestBook">
<h1>Sign the Guest Book</h1>
<table>
<tr><td>First Name:</td><td><input
type="text" name="firstname" /></td></tr>
<tr><td>Last Name:</td><td><input
type="text" name="lastname" /></td></tr>
<tr><td colspan="2">
<input type="hidden" name="action"
value="add"/>
<input type="submit" value="Sign Guest
Book"/>
</td>
</tr>
</table>
</form>
</body>
</html>
7. In order to save our objects to the database, we need to make sure we
have a database to save them in.
1. Click on the Services pane in the upper-left of the NetBeans IDE
and expand the Databases node.
2. Right-click the Java DB service and click the “Start Server” menu
item. This will start the Java DB engine that comes bundled with
NetBeans.
3. Right-click the Java DB service again and choose the “Create
Database” menu item.
4. In the Create Java DB Database dialog, enter myfirstjpa as the
database name and enter app for both the user name and password
fields.
You should now see a new database named myfirstjpa in the database list.
8. Right-click on the MyFirstJPA project node and choose New →
Entity Class from the context menu.
If Entity Class is not one of the available options you may add it by choosing
Other from the context menu. Choose Persistence from the Categories menu
on the left and Entity Class from the File Types menu on the right and click
“Finish”
9. Enter Guest as the Class Name and myfirstjpa.entities as the Package.
You will also see a warning that a Persistence Unit must be created.
The persistence unit defines some details for JPA such as the data
source for the database. Click the “Create Persistence Unit” button to
create the persistence unit.
10. In the Create Persistence Unit dialog, name the new persistence unit
MyFirstJPAPU and set the persistence provider to TopLink(default)
and leave the Table Generation Strategy on “Create.”
11. In the Data Source drop-down menu, choose the New Data Source
option to create a new data source.
12. In the Create Data Source dialog enter jdbc/myfirstjpa as the JNDI
Name and choose the myfirstjpa database connection that we set up in
step 7. Click “OK” to create the data source. Click “OK” again to
finish the creation of the persistence unit.
13. Click “Finish” to complete the creation of the Guest entity.
14. You will notice that the myfirstjpa.entities package has been created
along with the Guest entity class. Opening the entity class in the editor
will show that NetBeans has already put much of the structure in place
for you, including an auto-generating Id field.
15. Add two additional member variables beneath the id field:
public String firstName;
public String lastName;
16. To auto-generate getter and setter methods for the new String
variables, right-click on Guest.java and choose Refactor →
Encapsulate Fields from the context menu.
Check the boxes in both the Create Getter and Create Setter columns for the
lastName and firstName variables. Click the “Refactor” to have NetBeans
automatically generate the getter and setter methods.
17. Right-click on the MyFirstJPA project node and choose New →
Servlet from the context menu.
18. Enter GuestBook as the Class Name and myfirstjpa.servlets as the
Package and click “Finish” to create the Servlet.
19. Open GuestBook.java in the editor window. You will see the
famework for a servlet.
20. Add the following lines to the class definition to inject a
UserTransaction object into the class:
@Resource
UserTransaction utx;
The @Resource annotation and the UserTransaction class name both appear
with red lines beneath them, indicating that NetBeans cannot find the class
definitions. Click on the light-bulb icon in the left margin next to the
@Resource annotation and choose “Add import for
javax.annotation.Resource” from the menu. This will automatically add the
appropriate import statement. Repeat the procedure for the light-bulb icon
in the margin next to the UserTransaction class name. The UserTransaction
object will allow the servlet access to a transaction for use with the Guest
entity.
21. Add the following lines to the class definition to inject an
EntityManagerFactory object into the class:
@PersistenceUnit
EntityManagerFactory emf;
Follow the procedure in step 20 to automatically import the appropriate class
definitions.
22. Replace the auto-generated contents of the servlet's processRequest
method so that the method looks like this:
protected void processRequest(HttpServletRequest
request, HttpServletResponse response) throws
ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try {
utx.begin();
EntityManager em =
emf.createEntityManager();
String action =
request.getParameter("action");
if("add".equals(action)) {
Guest g = new Guest();
g.setFirstName(request.getParameter("firstname"
));
g.setLastName(request.getParameter("lastname"))
;
em.persist(g);
}
List<Guest> guestList =
em.createQuery("select g from Guest
g").getResultList();
request.setAttribute("guestList",
guestList);
utx.commit();
}
catch(Exception e) {
e.printStackTrace();
try {
utx.rollback();
} catch(Exception ex) {
ex.printStackTrace();
}
} finally {
RequestDispatcher rd =
this.getServletContext().getRequestDispatcher("/ind
ex.jsp");
rd.forward(request, response);
}
}
23. Click the run button to deploy the project.
24. The index page will open in a new web browser and the web form will
appear. Entering a first name and last name and clicking the “Sign
Guest Book” button will result in the information being saved to the
database by means of the Guest entity. Enter a few names to test.
25. Click on the Services pane in the upper left corner of the NetBeans
IDE and expand the Databases node. Right-click on the database we
set up in step 7 and choose “Connect” from the context menu.
26. Right-click on the database again now that you are connected and
choose “Execute Command” from the context menu.
27. In the SQL Command editor that opens, enter the following SQL
query:
select * from guest;
Click the “Run SQL” button at the top of the editor pane to execute the SQL
statement. You will see the database rows containing the entities saved by
the servlet.
The NetBeans IDE makes working with entities very simple. In our first
example most of our time was spent setting up the environment for the
entities to live in, such as the database connection , the servlet, and the JSP
page containing the form.