Вступление
OpenJPA является реализацией с открытым исходным кодом спецификации Java JPA (Java Persistence API) от Apache. JPA предоставляет независимый API на основе Java для хранения и извлечения информации в базу данных бэкэнда. Он имеет канонический язык запросов под названием Java Persistence Query Language или JPQL, который сочетается с методами программирования Java и устраняет необходимость настраивать запросы к конкретной базе данных. Однако JPA также поддерживает собственный SQL, который можно использовать для быстрых портов с известной серверной базой данных. Это руководство предназначено для того, чтобы помочь вам настроить простое веб-приложение для использования OpenJPA Geronimo и провести транзакции с базой данных derby, которая поставляется вместе с Geronimo. В учебном коде используется простая страница Java Server (JSP), поддерживаемая некоторыми базовыми классами. Он отображает таблицу инвентарных предметов и категорий.В этом руководстве мы не будем вдаваться в подробности, касающиеся кода JSP. Его цель — быть окном, через которое вы можете исследовать OpenJPA. Целевая аудитория для этого урока — это те, у кого есть знания и понимание языка программирования Java, и которые только начинают работать с OpenJPA. Для начала необходимо загрузить следующие требования и установить их на свой компьютер. Для целей данного руководства мы используем Eclipse в качестве IDE и Microsoft Windows в качестве операционной системы.Вы должны загрузить следующие требования и установить их на свой компьютер. Для целей данного руководства мы используем Eclipse в качестве IDE и Microsoft Windows в качестве операционной системы.Вы должны загрузить следующие требования и установить их на свой компьютер. Для целей данного руководства мы используем Eclipse в качестве IDE и Microsoft Windows в качестве операционной системы.
Предпосылки
Geronimo V2.2: Вы можете получить это здесь . Загрузите этот файл и разархивируйте его в постоянное место. Установщика нет. Сервер будет работать из командной строки.
Java (J2SE) V1.6: это руководство было разработано и протестировано с Java V1.6. Если у вас еще нет Java V1.6, вы можете получить IBM JDK здесь или Sun JDK здесь .
Eclipse V3.2 или новее: в эту версию включена поддержка аннотаций. Аннотации играют большую роль в OpenJPA. Загрузите Eclipse 3.2 или более позднюю версию . Библиотека
Apache OpenJPA : для реализации этого руководства вы можете выбрать
OpenJPA v1.2 или выше. Вы можете скачать Apache OpenJPA с сайта Apache. Обратите внимание, что Milestone (openjpa-all-2.0.0-M3.jar на момент написания этой статьи) является ранним выпуском OpenJPA 2.0 и может иметь некоторые нестабильности. В этом руководстве не было замечено проблем с использованием.
Файлы кода учебника: Эти файлы поставляются с этим учебником. Вы добавите их в свой проект Eclipse.
Настройка и запуск образца
Теперь, когда у вас есть все необходимые условия для этого учебного руководства, загружены и установлены, следующие разделы проведут вас через настройку проекта Eclipse и конфигурацию OpenJPA. Обязательно прочитайте и внимательно следите за каждой частью.
Настройка Eclipse
После установки Eclipse создайте новый проект в выделенной рабочей области для учебника. Выполните следующие инструкции по установке: Сначала убедитесь, что ваша среда Eclipse обновлена и имеет плагин Geronimo. Если вы не знаете, как это сделать, следуйте инструкциям на веб-сайте Geronimo .
1.) Создайте новый проект Java в Eclipse под названием « OpenJPATutorial ».
В меню выберите: Файл-> Создать-> Проект корпоративного приложения . (Если Enterprise Application Project недоступен в качестве опции, выберите Project, а затем выберите Enterprise Application Project из списка. Затем нажмите кнопку Next ).
Когда появится диалоговое окно «Настройки нового проекта», используйте следующие параметры:
2.) В разделе Target Runtime выберите Apache Geronimo v2.2 .
Если у вас еще нет установки Geronimo в Eclipse, вам придется сделать это сейчас. Нажмите на кнопку Новый …
Если Apache Geronimo v2.2 не отображается в списке под Apache , щелкните ссылку « Загрузить дополнительные серверные адаптеры» в правом верхнем углу диалогового окна. Если адаптер не отображается в этом списке, следуйте инструкциям на сайте Geronimo .
Выберите Apache-> Apache Geronimo v2.2 .
Нажмите Далее .
Установите JRE на jre6, если он еще не установлен.
Найдите каталог установки Geronimo v2.2 в вашей системе.
Нажмите Готово . Вы должны увидеть следующее:
3.) Теперь нажмите кнопку Далее . Вы должны увидеть это:
Установите флажок « Создать дескриптор развертывания application.xml» .
Нажмите кнопку Новый модуль …:
Снимите флажок « Создать модули по умолчанию» .
Выберите веб- вариант.
Нажмите Далее .
Нажмите Готово. Вы увидите следующее:
Нажмите Готово .
4.) Теперь ваш Project Explorer должен выглядеть так (в частности, расширен):
If you double-click on the Deployment Descriptor: OpenJPATutorial, you should see the application.xml open:
5.) Now we will bring in the sample code. The easiest way to add the sample code is to find the source provided with this tutorial and copy it to the src folder under the OpenJPATutorialWeb folder in your project directory in Windows Explorer:
Now go back to Eclipse. Right-click on the OpenJPATutorialWeb folder in the Project Explorer view and select Refresh, or press the F5 key on your keyboard. Now you will see this:
Notice that all the source files compile without error. That is because Geronimo comes with OpenJPA v1.1 built in.
6.) Now copy the index.jsp file from the tutorial into the Web Content directory under the Project directory in Windows Explorer:
Got to the Project Explorer and refresh the project. You should see this:
Running and Configuring Geronimo and Derby
Geronimo has no installer and runs from the command line. Here are some quick instructions to get you started.
1.) In Windows, open a command prompt and navigate to the Geronimo bin directory.
2.) Type the command: start-server.
Press the Enter key.
3.) Open a web browser and go to the address:
The default password is manager.
4.) You will come to the Welcome page. On the left menu, at the bottom, find the section for the Embedded DB. This is the Derby database control page.
5.) Click on the link for the DB Manager.
6.) You will see two sections: DB Viewer and Run SQL.
7.) In the Run SQL section, in the text field labeled Create DB, type in StoreSystem. This is the name of the database that the OpenJPA sample is configured to transact.
8.) Click on the Create button. You should now see the StoreSystem database appear in the DB Viewer section.
9.) We are now ready to deploy and run the sample code.
Running and Deploying the Sample Code in Geronimo
The sample code provided with this tutorial is working code. It is a simple inventory database program that shows items and categories. But even this simple example requires the ability to add, edit and delete entries. It requires the ability to sort and filter database queries and it requires the identification of the relationship of the items to the categories. In this example, the relationship is one to many. Knowing that relationship is important to how the code is written. Before we analyze the code and OpenJPA, we will first deploy the sample and see it work. To deploy the sample code follow these instructions:
1.) In Eclipse, in the Project Explorer, right click on the OpenJPATutorial project and select: Export->EAR file.
2.) In the Ear Export dialog, find a convenient place to put the exported EAR file.
3.) Check the Overwrite existing file check box.
4.) Click Finish.
5.) Go out to Windows Explorer and copy the file TutorialDeploymentPlan.xml to the location of the exported ear. This is the deployment plan that Geronimo requires to deploy the application.
6.) Open the Geronimo console in a web browser and log in.
7.) In the Console Navigation menu on the left, under the Applications section, click on the Deploy New item.
8.) Browse to the location of the exported EAR file and the deployment plan XML file.
9.) Click on the Install button. You should see this.
10.) In the Console Navigation menu on the left, under the Applications section, click on the Web App WARs item.
Notice that the OpenJPATutorial application is now listed and that there is a clickable link under the URL heading:
11.) Click on the link OpenJPATutorial and now you should see this:
Each of the buttons will execute OpenJPA code. The lists are filled by running queries on the Derby database.
1. Add a some categories and items
2. Make sure you test each of the buttons and see the results.
Examining the Sample Code
Now that everything is set up and you have seen it work, let’s look more closely at the parts of the code that use OpenJPA. The JSP code is just a prop to explore OpenJPA and we will not examine it.The sample application source code is provided for this tutorial and you may run as-is with no customizations. However, you have the option of reproducing the code manually using the following explanations. Whichever method you choose, locate the code that corresponds to explanations as you follow along.
Java code: This tutorial comes with the following java source files:
index.jsp: This is the interface code only. It does call into other classes but it does not use any OpenJPA code directly.
InventoryEntityBroker.java: This class contains methods that encapsulate the OpenJPA handling code. It is provided as a way to separate OpenJPA functionality from the web interface.
InventoryItem.java: This is an OpenJPA Entity class file. This file is an example of a simple OpenJPA Entity with a relationship.
InventoryCategory.java: This is an OpenJPA Entity class file. This file is an example of a simple OpenJPA Entity with a relationship.
Persistence code: Each entity concept that would be a database table will be its own class. In this case, the tables are called «InventoryItem» and «InventoryCategory». Annotations in the Java file will associate the properties with the database columns. The annotation, @Column, maps the property name to the column name for synchronization with the database. If the table corresponding tables do not exist, OpenJPA can use these annotations to create the tables’ schema dynamically based on the property type and length.
package tutorial;
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Version;
@Entity
public class InventoryCategory
{
private int version;
private int id;
private String categoryName;
private String categoryDescription;
List<InventoryItem> items;
public InventoryCategory(){}
@Column(name = "categoryName")
public String getCategoryName()
{
return categoryName;
}
public void setCategoryName(String name)
{
this.categoryName = name;
}
@Column(name = "itemDescription")
public String getCategoryDescription()
{
return categoryDescription;
}
public void setCategoryDescription(String description)
{
this.categoryDescription = description;
}
@Version
@Column(name = "version_field")
// not required
public int getVersion()
{
return version;
}
public void setVersion(int version)
{
this.version = version;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
@OneToMany(targetEntity=tutorial.InventoryItem.class,
cascade=CascadeType.ALL,
mappedBy="category")
public List<InventoryItem> getItems()
{
return items;
}
public void setItems(List<InventoryItem> items)
{
this.items = items;
}
public void addItem(InventoryItem item)
{
this.items.add(item);
}
}
Note
In this example, the property annotations ( @Column,@Version, and @Id) are placed on the getter methods. They can alternatively be placed on the property declarations. For more information on these annotations and to see what other annotations are in OpenJPA, see the Apache OpenJPA 2.0 User’s Guide: Chapter 5
- The annotated class and property declarations are all that are required.
- The @Id annotation is needed as the unique identifier (primary key) for each record.
- The @Version annotation is common practice. It ensures data integrity during merges and acts as an optimistic concurrency control.
- Every property must have both a getter and a setter and the standard case convention must be observed.
° Correct: public void setCategoryName(String name)
° Incorrect: public void setcategoryname(String name)
Persistence.xml: JPA requires the use of a XML file called the «persistence.xml» that describes how to access the data. The XML file must be created in the META-INF directory. The META-INF directory containing the persistence.xml must be located with the source files.
In the following example, the file only requires a few fields.
<persistence xmlns=http://java.sun.com/xml/ns/persistence
xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance
version="1.0">
<persistence-unit name="InventorySystem" transaction-type="RESOURCE_LOCAL">
<class>tutorial.InventoryItem</class>
<class>tutorial.InventoryCategory</class>
<properties>
<property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema"/>
<property name="openjpa.ConnectionURL" value="jdbc:derby://localhost:1527/StoreSystem"/>
<property name="openjpa.ConnectionDriverName" value="org.apache.derby.jdbc.ClientDriver"/>
</properties>
</persistence-unit>
</persistence>
The following elements are specific to this tutorial:
persistence-unit: the name is the table name to bind. In this case it is ‘person’.
class: the java class that is bound to the table ‘person’.
property: openjpa.jdbc.SynchronizeMappings: This tells OpenJPA to automatically create the table with the class definition if a table does not already exist.
property: openjpa.ConnectionURL: The URL of the database connection.
property: openjpa.ConnectionDriverName: the class name of the JDBC driver for Derby. This must be available via the classpath. In this tutorial, the driver is built into Geronimo so no extra actions are needed.
A complete explanation of the persistence.xml is in the Apache OpenJPAV2.0 user’s Guide: Chapter 6
Create the Entity Manager. In the provided code, the EntityManager is a property of the InventoryEntityBroker class. The Entity Manager controls the interaction with the database. You must use the Entity Manager to start or access transactions or to send queries.
The following code must be added before using any of the persistence APIs (If you are using the provided sample code, this is already included):
EntityManagerFactory factory = Persistence.createEntityManagerFactory("InventorySystem",
System.getProperties());
EntityManager em = factory.createEntityManager();
Note that the name, «InventorySystem», is the same one identified in the persistence.xml.
This code can be placed just before a query or transaction or they can be class properties.
Regardless of the scope, the EntityManager and the EntityManagerFactory should be closed when they are no longer needed:
...
em.close();
factory.close();
...
The EntityManagerFactory and EntityManager full descriptions are in the following OpenJPA documentation:
EntityManagerFactory: http://openjpa.apache.org/builds/latest/docs/manual/jpa_overview_emfactory.html
EntityManager: http://openjpa.apache.org/builds/latest/docs/manual/jpa_overview_em.html
DB interface class. In this example, the InventoryEntityBroker class contains all the OpenJPA database interaction code. This is not required but it is a good idea for keeping the functionality componentized. For example, if you want to pull all of the records from the InventoryItem table, the code would look like this:
...
List<Person> getAllItems()
{
Query q = em.createQuery("SELECT item FROM InventoryItem item");
return (List<InventoryItem>)q.getResultList();
}
...
...
List<InventoryItem> itemList = getAllItems();
...
All of the specific APIs are described in the OpenJPA javadoc
Notice that the Query is not standard SQL. It is actually JPQL, which is a specialized form of query language specifically designed for JPA.
In the JPQL statement, «SELECT item FROM InventoryItem item», notice that InventoryItem has the same case as the class InventoryItem.
JPQL uses java objects in the query and not the database table names. The statement identifies the variable for InventoryItem as «item».
JPQL provides an object oriented query language that is independent of the database being queried. So, regardless of which database being used, the JPQL does not change. The JPA runtime takes care of doing the translation from the object world to the desired relational database.
For more information on JPQL, check out this Java Persistence Querly Language reference.
Also in the InventoryEntityBroker is code to add entries the database tables. Since you did not create a table for InventoryItem in the StoreSystem database in Derby, OpenJPA 2.0 will create the table the first time an «add» is attempted.
...
void addItem(String name, String description, float price, int categoryID)
{
InventoryItem item = new InventoryItem();
item.setName(name);
item.setDescription(description);
...
em.persist(item);
}
...
You can then call the addItem() method in another part of the code. The EntityManager.persist() method will throw an exception if a transaction has not been started. The transaction must be committed by calling the Transaction.commit() method after all updates have been applied or else the changes will not be saved to the database:
...
em.getTransaction().begin();
addItem(...);
em.getTransaction().commit();
...
When this is executed the first time it will use the annotations to create the Person table, then OpenJPA 2.0 will populate it with the provided data.
Note the use of the getTransaction() method to start an update and then to commit it. The concept is the same as in any database transaction processing.
Also note that while the getAllItems() function requires a JPQL SELECT query, the update type actions have APIs.
Take a look in the InventoryEntityBroker code at the addItem(), updateItem() and deleteItem() functions and note the simplicity of these operations.
An important aspect of relational databases is, of course, the relationships. The basic relationship types are: one to many, many to one, and many to many. OpenJPA provides annotations to identify the related fields.
Open the source file, InventoryCategory.java in Eclipse and find the following code:
...
@OneToMany(targetEntity=tutorial.InventoryItem.class,
cascade=CascadeType.ALL,
mappedBy="category")
public List<InventoryItem> getItems()
{
return items;
}
...
The annotation @OneToMany identifies that:
This object has a one-to-many relationship with targetEntity=tutorial.InventoryItem.class. Meaning that one InventoryCategory can have many InventoryItems associated with it.
The property of InventoryItem that specifies the InventoryCategory it is associated with is mappedBy=»category». In other words, InventoryItem has a class property of type InventoryCategory named «category».
Now open the source file, InventoryItem.java and find the following code:
...
@ManyToOne
@JoinColumn(name="CAT_ID", nullable=false)
public InventoryCategory getCategory()
{
return category;
}
...
The annotation @ManyToOne identifies that:
This object has a many-to-one relationship with the InventoryCategory object. Meaning that there many InventoryItems can reference the same InventoryCategory
The annotation @JoinColumn identifies that:
The column in the database table that holds the InventoryCategory reference by the attribute: name=»CAT_ID».
Remember
These annotations contribute to the creation of the tables and the relationships. It is important to put as much thought into how these objects relate to each other as you would if you were designing the database tables because you are designing the database tables.
You can see more about the relationship annotations at the Apache OpenJPA site. The
documentation is here.
Summary
This was a very basic example of how to use OpenJPA with Geronimo and Derby. However, many applications that require database persistence do not use much more than the basic functionality demonstrated in this tutorial. The purpose of this was to be a primer. Aside from the setup of the server and database, we went through the creation of a persistence.xml file, the basics of the OpenJPA Entity, and EntityManager and some of the functionality.
Exercises
Using this sample code as a base, try to do some of the following:
Add additional fields to the InventoryItem Entity.
Create a Customer Entity and establish a one-to-many relationship with the InventoryItems as one customer having purchased many items.
Since several customers could have purchased the same items and an item could have been purchased by many customers, use the documentation to
To make these changes you may have to delete the existing database tables so that they can recreated with the new relationship fields.