Enterprise Java Development@TOPIC@
Earlier versions of EJB Spec defined persistence as part of javax.ejb.EntityBean
JavaEE 5 moved persistence to its own specification
Java Persistence API (JPA) version 1.0
javax.persistence
Ease of use API above JDBC
Provides
Object/Relational Mapping (ORM) Engine
Query Language (JPA-QL) - SQL-like - main carryover from EJB 2.x
JavaEE 6 advanced specification
Java Persistence API (JPA) version 2.0
More mapping capabilities
More entity manager capabilities
Standardization of properties
Criteria API
JavaEE 7 enhanced specification
Java Persistence API (JPA) version 2.1
Converters - to convert attributes to/from DB types
Criteria API Bulk Updates
Stored Procedure Query support
Partial fetching of objects
...
Replaced EJB 2.x Home Functionality
Handles O/R Mapping to the database
Provides APIs for
Inserting into database
Updating entities in database
Finding and querying for entities in database
Removing entities from database
Provides caching
Integrates with JTA transactions
Tightly integrated with JavaEE and EJB, but not coupled to it
Plain Old Java Objects (POJOs)
Nothing special happens when calling new()
Author author = new Author();
From JPA perspective the above is a new/unmanaged entity
Persistent when associated with an entity manager/persistence context
em.persist(author);
@javax.persistence.Entity
public class Author {
@Id
@GeneratedValue
private long id;
private long version=0;
private String firstName;
private String lastName;
private String subject;
private Date publishDate;
public Author() {
}
...
}
Entity minimum requirements:
Annotated as entity or declared in orm.xml
Unique identity (form primary key(s))
Non-private default constructor
Author author = new Author();
author.setFirstName("dr");
author.setLastName("seuss");
author.setSubject("children");
author.setPublishDate(new Date());
log.debug("creating author:" + author);
assertFalse("unexpected initialized id", author.getId() > 0);
log.debug("em.contains(author)=" + em.contains(author));
em.persist(author);
log.debug("created author:" + author);
assertTrue("missing id", author.getId() > 0);
log.debug("em.contains(author)=" + em.contains(author));
-creating author:ejava.examples.daoex.bo.Author@1d8e9e, id=0, fn=dr, ln=seuss, subject=children, pdate=Mon Sep 17 00:22:25 EDT 2012, version=0 -em.contains(author)=false -created author:ejava.examples.daoex.bo.Author@1d8e9e, id=50, fn=dr, ln=seuss, subject=children, pdate=Mon Sep 17 00:22:25 EDT 2012, version=0 -em.contains(author)=true
Associated with persistence context
Has identity
Changes to the entity will impact the database
Method em.contains(entity)
returns true
Has identity but not associated with persistence context
Changes to entity will not impact the database
Method em.contains(entity)
returns false
An entity becomes detached when:
Has not yet been persisted
After a transaction-scoped transaction is committed
After a transaction rollback
Manually detaching entity from persistence context thru em.detach()
Manually clearing the persistence context thru em.clear()
Closing EntityManager
Serializing entity thru a remote interface
A set of managed instances managed by an EntityManager
All entities become detached once closed
Two types:
Extended
Author author = new Author();
...
em.persist(author);
em.getTransaction().begin();
em.getTransaction().commit();
author.setFirstName("foo");
em.getTransaction().begin();
em.getTransaction().commit();
em.getTransaction().begin();
author.setFirstName("bar");
em.getTransaction().commit();
Live beyond a single transaction
Allow long-lived algorithms to process without tying up a database transaction
Transaction-Scoped
@TransactionAttribute(TransactionAttributeType.REQUIRED)
public Author createAuthor(...) {
Author author = new Author();
...
em.persist(author);
return author;
}
Begin/end at transaction boundaries
Injected by containers
A set of classes that are mapped to the database
Defined in META-INF/persistence.xml
Entity classes may be named in persistence.xml or searched for
Entity mapping may be provided, augmented, or overridden with orm.xml
mapping file
|-- ejava | `-- examples | `-- daoex | |-- AuthorDAO.class | |-- bo | | `-- Author.class | |-- DAOException.class | `-- jpa | `-- JPAAuthorDAO.class `-- META-INF |-- orm.xml `-- persistence.xml
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.0">
<persistence-unit name="jpaDemo">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<mapping-file>META-INF/orm.xml</mapping-file>
<properties>
<!-- standard properties -->
<property name="javax.persistence.jdbc.url" value="jdbc:h2:./target/h2db/ejava"/>
<property name="javax.persistence.jdbc.driver" value="org.h2.Driver"/>
<property name="javax.persistence.jdbc.user" value="sa"/>
<property name="javax.persistence.jdbc.password" value=""/>
<!-- hibernate-specific properties -->
<property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.hbm2ddl.auto" value="create"/>
<property name="hibernate.show_sql" value="true"/>
<property name="hibernate.format_sql" value="true"/>
<!-- set to 0 to improve error messages when needed
<property name="hibernate.jdbc.batch_size" value="0"/>
-->
</properties>
</persistence-unit>
</persistence>
Above example defines properties for entity manager to establish physical connections to database
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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"
version="2.0">
<persistence-unit name="ejbsessionbank">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
<jar-file>lib/ejbsessionBankImpl-3.0.2012.2-SNAPSHOT.jar</jar-file>
<properties>
<property name="hibernate.dialect"
value="org.hibernate.dialect.H2Dialect"/>
<property name="hibernate.show_sql" value="false"/>
<!-- create is used here for demo project only -->
<property name="hibernate.hbm2ddl.auto" value="create"/>
<!--
<property name="hibernate.jdbc.batch_size" value="0"/>
-->
</properties>
</persistence-unit>
</persistence>
Above example used DataSource from JNDI tree to obtain connections to database
Can be used to specify connection properties outside of persistence.xml
Useful in separating production mapping information from runtime connection properties
#hibernate-specific alternate source of persistence.xml properties hibernate.dialect=org.hibernate.dialect.H2Dialect hibernate.connection.url=jdbc:h2:./target/h2db/ejava hibernate.connection.driver_class=org.h2.Driver hibernate.connection.password= hibernate.connection.username=sa hibernate.hbm2ddl.auto=create hibernate.show_sql=true hibernate.format_sql=true #hibernate.jdbc.batch_size=0
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation=
"http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_2_0.xsd"
version="2.0">
<entity class="ejava.examples.daoex.bo.Author"
access="FIELD"
metadata-complete="false"
name="jpaAuthor">
<table name="DAO_AUTHOR"/>
<attributes>
<id name="id">
<generated-value strategy="SEQUENCE"
generator="AUTHOR_SEQUENCE"/>
</id>
</attributes>
</entity>
</entity-mappings>
The JPA 2.1 schema references are shown below. They have been left out of all class examples because they are not yet compatible with the schema generation plugin (hibernate3) used in class. It is unlikely that you will need features unique to JPA 2.1 declared in your XML files but know if you include references to JPA 2.1 you must use an alternate means of generating schema -- possibly manually.
<?xml version="1.0" encoding="UTF-8"?>
<persistence 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_1.xsd" version="2.1">
<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm_2_1.xsd" version="2.1">
name
Identity used to reference persistence unit
provider
Fully qualified name of javax.persistence.PersistenceProvider
Not needed if provider is in classpath
mapping-file
Path reference to an orm.xml
mapping file
jta-data-source
JNDI path of a JTA javax.sql.DataSource
non-jta-datasource
JNDI path of a RESOURCE_LOCAL javax.sql.DataSource
jarfile
Reference to an archive with entity classes
class
Fully qualified package name of entity class
One source of entity information
exclude-unlisted-classes
If set, provider will not scan to discover entity classes
properties
name/value property pairs to express additional configuration info
setUp
Create EntityManagerFactory
public class javax.persistence.Persistence extends java.lang.Object{
public static javax.persistence.EntityManagerFactory createEntityManagerFactory(java.lang.String);
public static javax.persistence.EntityManagerFactory createEntityManagerFactory(java.lang.String, java.util.Map);
...
}
private static EntityManagerFactory emf;
@BeforeClass
public static void setUpClass() {
emf = Persistence.createEntityManagerFactory("jpaDemo");
Create EntityManager
public interface javax.persistence.EntityManagerFactory{
public abstract javax.persistence.EntityManager createEntityManager();
public abstract javax.persistence.EntityManager createEntityManager(java.util.Map);
...
}
private EntityManager em;
@Before
public void setUp() throws Exception {
em = emf.createEntityManager();
Runtime
Start Transaction
em.getTransaction().begin();
Interact with EntityManager
em.persist(author);
Commit Transaction
em.getTransaction().commit();
tearDown
Close EntityManager
@After
public void tearDown() throws Exception {
try {
if (em != null) {
if (!em.getTransaction().isActive()) {
em.getTransaction().begin();
em.getTransaction().commit();
}
else if (!em.getTransaction().getRollbackOnly()) {
em.getTransaction().commit();
}
else {
em.getTransaction().rollback();
}
}
}
finally {
if (em != null) { em.close(); em=null;}
}
Close EntityManagerFactory
@AfterClass
public static void tearDownClass() {
if (emf != null) {
emf.close();
emf=null;
}
}
public interface javax.persistence.EntityManager{ ... }
void persist(Object entity);
<T> T find(Class<T> entityClass, Object primaryKey);
<T> T find(Class<T> entityClass, Object primaryKey, Map<String, Object> properties);
<T> T merge(T entity);
void remove(Object entity);
<T> T getReference(Class<T> entityClass, Object primaryKey);
void clear();
void detach(Object entity);
boolean contains(Object entity);
void flush();
void setFlushMode(javax.persistence.FlushModeType);
javax.persistence.FlushModeType getFlushMode();
void refresh(Object);
void refresh(Object, java.util.Map);
void lock(Object entity, javax.persistence.LockModeType);
void lock(Object entity, javax.persistence.LockModeType, Map<String, Object> properties);
<T> T find(Class<T> entityClass, Object primaryKey, javax.persistence.LockModeType);
<T> T find(Class<T> entityClass, Object primaryKey, javax.persistence.LockModeType, Map<String, Object> properties);
void refresh(Object, javax.persistence.LockModeType);
void refresh(Object, javax.persistence.LockModeType, Map<String, Object> properties);
javax.persistence.LockModeType getLockMode(Object entity);
javax.persistence.Query createQuery(String jpaql);
<T> javax.persistence.TypedQuery<T> createQuery(String jpaql, Class<T> resultClass);
javax.persistence.Query createNamedQuery(String name);
<T> javax.persistence.TypedQuery<T> createNamedQuery(String name, Class<T> resultClass);
javax.persistence.Query createNativeQuery(String sql);
javax.persistence.Query createNativeQuery(String sql, Class resultClass);
javax.persistence.Query createNativeQuery(String sql, String resultMapping);
<T> javax.persistence.TypedQuery<T> createQuery(javax.persistence.criteria.CriteriaQuery<T> criteria);
javax.persistence.criteria.CriteriaBuilder getCriteriaBuilder();
void close();
boolean isOpen();
javax.persistence.EntityTransaction getTransaction();
void joinTransaction();
void setProperty(String key, Object value);
java.util.Map getProperties();
<T> T unwrap(Class<T> clazz);
Object getDelegate();
javax.persistence.metamodel.Metamodel getMetamodel();
javax.persistence.EntityManagerFactory getEntityManagerFactory();