官术网_书友最值得收藏!

The Java Persistence API

The Java Persistence API (JPA) was introduced to Java EE in version 5 of the specification. Like its name implies, it is used to persist data to a relational database management system. JPA is a replacement for the Entity Beans that were used in J2EE. Java EE Entities are regular Java classes; the Java EE container knows these classes are Entities because they are decorated with the @Entity annotation. Let's look at an Entity mapping to the CUSTOMER table in the CUSTOMERDB database:

package net.ensode.javaee8book.jpaintro.entity; 
 
import java.io.Serializable; 
 
import javax.persistence.Column; 
import javax.persistence.Entity; 
import javax.persistence.Id; 
import javax.persistence.Table; 
 
@Entity 
@Table(name = "CUSTOMERS") 
public class Customer implements Serializable 
{ 
  @Id 
  @Column(name = "CUSTOMER_ID") 
  private Long customerId; 
 
  @Column(name = "FIRST_NAME") 
  private String firstName; 
 
  @Column(name = "LAST_NAME") 
  private String lastName; 
 
  private String email; 
 
  public Long getCustomerId() 
  { 
    return customerId; 
  } 
  public void setCustomerId(Long customerId) 
  { 
    this.customerId = customerId; 
  } 
  public String getEmail() 
  { 
    return email; 
  } 
  public void setEmail(String email) 
  { 
    this.email = email; 
  } 
  public String getFirstName() 
  { 
    return firstName; 
  } 
  public void setFirstName(String firstName) 
  { 
    this.firstName = firstName; 
  } 
  public String getLastName() 
  { 
    return lastName; 
  } 
  public void setLastName(String lastName) 
  { 
    this.lastName = lastName; 
  } 
} 

In the preceding code, the @Entity annotation lets any other Java EE-compliant application server know that this class is a JPA entity.

The @Table(name = "CUSTOMERS") annotation lets the application server know what table to map the entity to. The value of the name element contains the name of the database table that the entity maps to. This annotation is optional; if the name of the class maps the name of the database table, then it isn't necessary to specify what table the entity maps to.

The @Id annotation indicates that the customerId field maps to the primary key.

The @Column annotation maps each field to a column in the table. If the name of the field matches the name of the database column, then this annotation is not needed. This is the reason why the email field is not annotated.

The EntityManager class (this is actually an interface; each Java EE compliant application server provides its own implementation) is used to persist entities to a database. The following example illustrates its usage:

package net.ensode.javaee8book.jpaintro.namedbean; 
 
import javax.annotation.Resource; 
import javax.enterprise.context.RequestScoped; 
import javax.inject.Named; 
import javax.persistence.EntityManager; 
import javax.persistence.PersistenceContext; 
import javax.transaction.HeuristicMixedException; 
import javax.transaction.HeuristicRollbackException; 
import javax.transaction.NotSupportedException; 
import javax.transaction.RollbackException; 
import javax.transaction.SystemException; 
import javax.transaction.UserTransaction; 
import net.ensode.javaee8book.jpaintro.entity.Customer; 
 
@Named 
@RequestScoped 
public class JpaDemoBean { 
 
    @PersistenceContext 
    private EntityManager entityManager; 
 
    @Resource 
    private UserTransaction userTransaction; 
 
    public String updateDatabase() { 
 
        String retVal = "confirmation"; 
 
        Customer customer = new Customer(); 
        Customer customer2 = new Customer(); 
        Customer customer3; 
 
        customer.setCustomerId(3L); 
        customer.setFirstName("James"); 
        customer.setLastName("McKenzie"); 
        customer.setEmail("jamesm@notreal.com"); 
 
        customer2.setCustomerId(4L); 
        customer2.setFirstName("Charles"); 
        customer2.setLastName("Jonson"); 
        customer2.setEmail("cjohnson@phony.org"); 
 
        try { 
            userTransaction.begin(); 
            entityManager.persist(customer); 
            entityManager.persist(customer2); 
            customer3 = entityManager.find(Customer.class, 4L); 
            customer3.setLastName("Johnson"); 
            entityManager.persist(customer3); 
            entityManager.remove(customer); 
 
            userTransaction.commit(); 
        } catch (HeuristicMixedException | 
                HeuristicRollbackException | 
                IllegalStateException | 
                NotSupportedException | 
                RollbackException | 
                SecurityException | 
                SystemException e) { 
            retVal = "error"; 
            e.printStackTrace(); 
        } 
 
        return retVal; 
    } 
} 

The preceding CDI named bean obtains an instance of a class implementing the javax.persistence.EntityManager interface via dependency injection. This is done by decorating the EntityManager variable with the @PersistenceContext annotation.

An instance of a class implementing the javax.transaction.UserTransaction interface is then injected via the @Resource annotation. This object is necessary, since, without it invoking calls to persist Entities to the database, the code would throw a javax.persistence.TransactionRequiredException .

EntityManager performs many database-related tasks, such as finding entities in the database, updating them, or deleting them.

Since JPA Entities are plain old Java objects ( POJOs ), they can be instantiated via the new operator.

The call to the setCustomerId() method takes advantage of autoboxing, a feature added to the Java language in JDK 1.5. Notice that the method takes an instance of java.lang.Long as its parameter, but we are using long primitives. The code compiles and executes properly thanks to this feature.

Calls to the persist() method on EntityManager must be in a transaction, therefore it is necessary to start one by calling the begin() method on UserTransaction.

We then insert two new rows to the CUSTOMERS table by calling the persist() method on entityManager for the two instances of the Customer class we populated earlier in the code.

After persisting the data contained in the customer and customer2 objects, we search the database for a row in the CUSTOMERS table with a primary key of four. We do this by invoking the find() method on entityManager. This method takes the class of the Entity we are searching for as its first parameter, and the primary key of the row corresponding to the object we want to obtain. This method is roughly equivalent to the findByPrimaryKey() method on an entity bean's home interface.

The primary key we set for the customer2 object was 4, therefore what we have now is a copy of this object. The last name for this customer was misspelled when we originally inserted his data into the database. We can now correct Mr. Johnson's last name by invoking the setLastName() method on customer3, then we can update the information in the database by invoking entityManager.persist().

We then delete the information for the customer object by invoking entityManager.remove() and passing the customer object as a parameter.

Finally, we commit the changes to the database by invoking the commit() method on userTransaction.

In order for the preceding code to work as expected, an XML configuration file named persistence.xml must be deployed in the WAR file containing the previously-named bean. This file must be placed in the WEB-INF/classes/META-INF/ directory inside the WAR file. The contents of this file for the preceding code are shown here:

<?xml version="1.0" encoding="UTF-8"?> 
<persistence version="2.2" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_2.xsd"> 
  <persistence-unit name="customerPersistenceUnit"> 
    <jta-data-source>jdbc/__CustomerDBPool</jta-data-source> 
  </persistence-unit> 
</persistence> 

persistence.xml must contain at least one <persistence-unit> element. Each <persistence-unit> element must provide a value for its name attribute and must contain a <jta-data-source> child element whose value is the JNDI name of the data source to be used for the persistence unit.

The reason more than one <persistence-unit> element is allowed is because an application may access more than one database. A <persistence-unit> element is required for each database the application will access. If the application defines more than one <persistence-unit> element, then the @PersistenceContext annotation used to inject EntityManager must provide a value for its unitName element; the value for this element must match the name attribute of the corresponding <persistence-unit> element in persistence.xml.

Cannot persist detached object Exception: Frequently, an application will retrieve a JPA entity via the EntityManager.find() method, then pass this entity to a business or user interface layer, where it will potentially be modified, and later the database data corresponding to the entity will be updated. In cases such as this, invoking EntityManager.persist() will result in an exception. In order to update JPA entities this way, we need to invoke EntityManager.merge(). This method takes an instance of the JPA entity as its single argument and updates the corresponding row in the database with the data stored in it.

主站蜘蛛池模板: 铁岭县| 宜都市| 临潭县| 黄梅县| 武宁县| 吉林省| 西青区| 冷水江市| 芦山县| 阳春市| 明光市| 建平县| 河池市| 牙克石市| 祁东县| 乌什县| 宿州市| 安阳市| 石台县| 于都县| 汕尾市| 金塔县| 古交市| 台州市| 衡山县| 沅江市| 炎陵县| 马关县| 银川市| 同德县| 石泉县| 金塔县| 东阿县| 盖州市| 宁强县| 县级市| 商水县| 新泰市| 外汇| 壤塘县| 太康县|