Personal notes on Java
For other technologies like HTML, CSS, .NET, PHP, etc. check my other blog

JPA

References


Introduction

Check this tutorial for a good overview on JPA: JPA 2.0 with EclipseLink - Tutorial

What is JPA?

JPA is a ORM persistence standard to which there are many implementations on the market:

EclipseLink

Eclipse Link is the JPA reference implementation (but there are other popular JPA implementations like Hibernate).
The EclipseLink official page has lots of info:

Why use JPA instead of JDBC or Entity Beans?

  • JDBC is too low level and not so productive (too verbose; error prone; developers need to code SQL statements by hand for a specific DBMS and later re-code it if they need to change DBMS);
  • "Entity Beans" were used in old Java EE apps but got deprecated for a much simpler model: JPA!
  • JPA is:
     - simple to use (classes are POJOs with just a couple of annotations);
     - standardized, meaning that your code is not vendor specific, it will run in any compliant implementation (like EclipseLink or Hibernate;
     - the ORM of JPA is not DBMS specific (ex. MySQL; Oracle; etc.), meaning that your code will run in any DBMS supported by your JPA implementation product (ex. Hibernate, EclipseLink, etc.).
Prior to Java EE 5 there were many complaints about the complexity of building enterprise applications in Java.
So, the Java EE 5 came with the theme "ease of development" and a hand full of changes. With it, EJB 3.0 found ways to make Enterprise JavaBeans easier and more productive to use:
  • In the case of session beans and message-driven beans, solutions to usability issues were reached by simply removing some of the more onerous implementation requirements and letting components look more like plain Java objects
  • BUT in the case of "entity beans", the solution to make it simple was to start over! I.e. leave entity beans alone and introduce a new model for persistence: JPA.
    JPA was developed in collaboration with the leading vendors of ORM solutions (Hibernate and TopLink) that standardized the best practices represented by their products.   

Where can I use JPA?

JPA specification is part of Java EE but you can use it either in Java EE and Java SE applications.
Check the section "using JPA in Java SE" further down on this page for more info.

Entities

Entities are just POJOs with a couple of annotations.

To turn a class into an entity:
  • Annotate the class with @Entity (javax.persistence.Entity);
  • The class must have a field annotated with @Id (javax.persistence.Id);
  • The class must be serializable, i.e. it must implement Serializable (java.io.Serializable);
  • The class must have a default no-args constructor;


Entity Manager


Check the EntityManager Javadoc.
Child pages for Entity Manager: Entity Manager Notes;

The EntityManager API is defined in JPA, and is is used to:
  • create and remove persistent entity instances;
  • find entities by their primary key;
  • query over entities;
I.e. the entity manager is used to operate over the database. Until an entity manager is used to actually create, read, or write an entity, the entity is nothing more than a regular (nonpersistent) Java object.

  Related concepts:

  • Entity Manager persistence context:
    The set of managed entity instances within an entity manager at any given time is called its persistence context.

    An EntityManager instance is associated with a persistence context.
    When an entity manager obtains a reference to an entity, either by having it explicitly passed in as an argument to a method call or because it was read from the database, that object is said to be managed by the entity manager.

    Only one Java instance with the same persistent identity may exist in a persistence context at any time.
    For example: if an Employee with a persistent identity (or id) of 158 exists in the persistence context, then no other Employee object with its id set to 158 may exist within that same persistence context.
     
  • Persistence Unit (PU):
    Check the next section

How to use the Entity Manager

Obtaining an Entity Manager

In order to start working with persistent entities you need to obtain a entity manager object.
An entity manager is always obtained from an EntityManagerFactory.
  • In a Java EE application server environment, you dont't usually interact directly with the EntityManagerFactory (you get the object through container injetion).
    Example:
    TODO
  • In a Java SE environment, we can use a simple bootstrap class called Persistence, for example (using a PU named “EmployeeServicePU”):
    EntityManagerFactory emf =
        Persistence.createEntityManagerFactory("EmployeeServicePU");
    EntityManager em = emf.createEntityManager();
Full class paths used in this example:
  • javax.persistence.EntityManager;
  • javax.persistence.EntityManagerFactory;
  • javax.persistence.Persistence;

NOTE: all the operations that follow should be used in conjuntion with a transaction service for the changes to be actually persisted into the database. Check the transactions section further down on this page for more info.

Persisting an entity

Persisting an entity is the operation of taking a transient entity, or one that does not yet have any persistent representation in the database, and storing its state so that it can be retrieved later.
Employee emp = new Employee(158);
em.persist(emp);
Calling persist() is all that is required to initiate it being persisted in the database.
If the entity manager encounters a problem doing this, then it will throw an unchecked PersistenceException.
When the persist() call returns, emp will have become a managed entity within the entity manager’s persistence context.

NOTE: you may want to use @GeneratedValue in conjunction with the Employee @Id field to auto-generate the id.

Finding an entity

Employee emp = em.find(Employee.class, 158);

Notes:
  • The employee that gets returned will be a managed entity, meaning that it will exist in the current persistence context associated with the entity manager.
  • Passing in the class as a parameter also allows the find method to be parameterized and return an object of same type that was passed in, saving the caller an extra cast.
  • In the event that the object was not found (ex. object has been deleted or we supplied the wrong id), then the find() call simply returns null.

Removing an entity

In order to remove an entity, the entity itself must be managed, meaning that it is present in the persistence context. This means that the calling application should have already loaded or accessed the entity and is now issuing a command to remove it.
public void removeEmployee(int id) {
    Employee emp = em.find(Employee.class, id);
    if (emp != null) {
        em.remove(emp);
    }
}

Updating an entity

There are a few different ways of updating an entity, the simplest and most common case is like this:
Employee emp = em.find(Employee.class, id);
if (emp != null) {
    emp.setSalary(emp.getSalary() + raise);
}
Note the difference between this operation and the others. In this case we are not calling into the entity manager to modify the object, but directly calling the object itself. For this reason it is important that the entity be a managed instance; otherwise, the persistence provider will have no means of detecting the change, and no changes will be made to the persistent representation of the employee.

Ref.:
  • [Book1, pag. 23] - "Entity Manager"

Persistence Unit (PU)

A PU is used to define:
  • the set of entities that can be managed by a given EntityManager instance, i.e. the set of all classes that are related or grouped by the application;
  • the connection to the database (server name, port and database name);
  • the database user account to be used to connect to the database (user name and pass);
  • the JPA provider;
  • the JDBC driver to connect to the database;
  • the type of transaction API to be used;
Every PU has a name that identifies it (in the example below the chosen name was "JPAJavaSEPU").
This name will be used as an argument when creating a new Entity Manager.

A Persistence Unit is defined in XML inside the "persistence.xml" configuration file (this file resides on the META-INF of your project).

Example of a persistence.xml containing a PU definition (section between the <persistence-unit> tags):
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd">
  <persistence-unit name="JPAJavaSEPU" transaction-type="RESOURCE_LOCAL">
    <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
    <class>myentities.Employee</class>
    <properties>
      <property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/jpa_javase"/>
      <property name="javax.persistence.jdbc.password" value="1234"/>
      <property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver"/>
      <property name="javax.persistence.jdbc.user" value="root"/>
    </properties>
  </persistence-unit>
</persistence> 

This PU defines:
  • PU name is "JPAJavaSEPU";
  • JPA provider is EclipseLink;
  • Transaction type is "RESOURCE_LOCAL";
  • Connecting to a MySQL database:
     - database name is "jpa_javase";
     - database server name is "localhost" listening on port  "3306";
     - JDBC driver is Connector/J ("com.mysql.jdbc.Driver");
     - database connection user/pass is "root" "1234";


Transaction management in JPA

In JPA all changes to entities must be made persistent using a transaction.
This, of course, applies to mutating operations - non mutating operations(like find()) dont require a transaction.

  • Java EE:
    The typical situation when running inside the Java EE container environment is that the standard Java Transaction API (JTA) is used.

    The transaction model when running in the container is to assume the application will ensure that a transactional context is present when one is required. If a transaction is not present, then either the modifying operation will throw an exception or the change will simply never be persisted to the data store.

     
  • Java SE:
    When executing in Java SE, we need to begin and commit the transaction before and after calling an operational method.

    In a Java SE environment the transaction service that should be used is the EntityTransaction service.
    You get the EntityTransaction service by calling:
    em.getTransaction();

    and then use it to start and commit the transactions.

    Example using EntityTransaction service:
    em.getTransaction().begin();
    createEmployee(158, "John Doe", 45000);
    em.getTransaction().commit();

Ref:
  • [Book1, pag. 26] - "Transactions";
  • [Book1, Chapter 3] - more info about Java EE Transactions;

Queries in JPA

JP QL (Java Persistence Query Language)

"JP QL is a query language that is derived from EJB QL and modeled after SQL for its familiarity, but it is not tied to the database schema or defined using the criteria API." [Book1, pag. 15]
NOTE: do not confuse "JP QL" and "EJB QL".

In JPA, a query is similar to a database query, except that instead of using SQL to specify the query criteria, we are querying over entities and using a language called JP QL (Java Persistence Query Language).

A query is implemented in code as a Query or TypedQuery object.
The EntityManager interface includes a variety of API calls that return a new javax.persistence.Query or javax.persistence.TypedQuery object.

A query can be defined either statically or dynamically:
  • A static query (aka named query): is defined in either annotation or XML metadata, and it must include the query criteria as well as a user-assigned name.
    This kind of query is also called a named query, and it is later looked up by its name at the time it is executed.
  • A dynamic query: can be issued at runtime by supplying the JP QL query criteria, or a criteria object.
    They may be a little more expensive to execute because the persistence provider cannot do any query preparation beforehand, but JP QL queries are nevertheless very simple to use and can be issued in response to program logic or even user logic.
    Example of a dynamic query using a TypedQuery with a JP QL string that defines the query criteria (select all Employee objects):
    TypedQuery<Employee> query = 
         em.createQuery("SELECT e FROM Employee e", Employee.class);
    List<Employee> emps = query.getResultList();
    
Ref.:
  • [Book1, pag. 28] - Section "Queries" introduces this concepts;
  • [Book1, Chapter 7] - info about queries;
  • [Book1, Chapter 7 and 8] - JP QL;
  • [Book1, Chapter 9] - criteria queries;
todo


Using JPA in JavaSE

You can use JPA in JavaSe apps almost the same way has you use it in JavaEE apps (with just a few peculiarities)
For more information jump to page: Using JPA in JavaSE

Sem comentários:

Enviar um comentário