Search This Blog

Thursday 14 March 2013

My First JPA Application - 3

In the last two posts we setup the code to run a simple JPA example. In this post I shall now test out the code. The code to execute is as below:
public class Client {

    public static void main(String[] args) {        
        //Persistence - the start up class
        EntityManagerFactory emFactory = Persistence.createEntityManagerFactory("firstOne");
        //thread safe, and usually a singleton
        
        EntityManager entityManager = emFactory.createEntityManager(); 
        //equivalent to Hibernate session
        
        EntityTransaction transaction = entityManager.getTransaction();
        transaction.begin();
        Owner owner = new Owner();
        owner.setName("Vijay");
        owner.setUserId("v123er");
        entityManager.persist(owner);
        transaction.commit();
        
        entityManager.close();
        emFactory.close();
    }
}
In the above code, the first line is the start point of the code. Persistence.java is a utility class in JPA (the only utility class I could find). The createEntityManagerFactory method is pretty cool
  1. The method searches in the classpath for a file "META-INF/services/javax.persistence.spi.PersistenceProvider".
  2. The hibernate-entitymanager.jar includes the above file in its jar. The file provides the name for the PersistenceProvider to use. In this case "org.hibernate.ejb.HibernatePersistence". The class is Hibernate's plugin point to the JPA interfaces.
  3. The class is responsible for returning Hibernate's implementation of EntityManagerFactory - org.hibernate.ejb.EntityManagerFactoryImpl. The persistence layer is now started.
The location of the persistence.xml file also matters. The Ejb3Configuration instance looks for the persistence.xml file in the predefined META-INF folder on the application classpath. If it does not find one then the logs indicate the start up failure:
Exception in thread "main" javax.persistence.PersistenceException: No Persistenc
e provider for EntityManager named firstOne
344  [main] DEBUG org.hibernate.ejb.Ejb3Configuration  - Look up for persistence unit: firstOne
360  [main] INFO  org.hibernate.ejb.Ejb3Configuration  - Could not find any META-INF
/persistence.xml file in the classpath
The EntityManagerFactory is equivalent to Hibernate's SessionFactory.Once we have the EntityManagerFactory the next step is to get an instance of EntityManager. It is the equivalent of Hibernate's session. Just like the session, it  must be used in a single threaded environment only. The persist() method is used here to save the object.
For transaction management we used the EntityTransaction instance. In this case the actual implementation used was org.hibernate.ejb.TransactionImpl. The class internally uses an instance of org.hibernate.Transaction.
This shows that underneath everything JPA we have the actual hibernate classes doing all the work. If we were to look at the logs:
547  [main] DEBUG org.hibernate.ejb.packaging.PersistenceXmlLoader  - Persistent
 Unit name from persistence.xml: firstOne
547  [main] DEBUG org.hibernate.ejb.Ejb3Configuration  - PersistenceMetadata [
    name: firstOne
    jtaDataSource: null
    nonJtaDataSource: null
    transactionType: RESOURCE_LOCAL
    provider: null
    classes[
    ]
    packages[
    ]
    mappingFiles[
    ]
    jarFiles[
    ]
    hbmfiles: 0
    properties[
        hibernate.ejb.cfgfile: /META-INF/hibernate.cfg.xml
    ]]
...
2125 [main] INFO  org.hibernate.cfg.SettingsFactory  - JDBC driver: PostgreSQL N
ative Driver, version: PostgreSQL 9.1 JDBC4 (build 901)
2125 [main] DEBUG org.hibernate.connection.DriverManagerConnectionProvider  - re
turning connection to pool, pool size: 1
2156 [main] INFO  org.hibernate.dialect.Dialect  - Using dialect: org.hibernate.
dialect.PostgreSQLDialect
2156 [main] INFO  org.hibernate.transaction.TransactionFactoryFactory  - Transac
tion strategy: org.hibernate.transaction.JDBCTransactionFactory
...
3266 [main] DEBUG org.hibernate.impl.SessionFactoryImpl - instantiated session factory
...
3297 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    alter table firstOne.PET 
        drop constraint FK134FF8F6E060D
3422 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    drop table firstOne.OWNER
3516 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    drop table firstOne.PET
3594 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    create table firstOne.OWNER (
        id  bigserial not null,
        NAME varchar(255),
        USER_ID varchar(20) not null unique,
        primary key (id)
    )
3750 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    create table firstOne.PET (
        id  bigserial not null,
        AGE int4,
        NAME varchar(12) not null,
        TAG_ID varchar(255),
        OWNER_ID int8 not null,
        primary key (id),
        unique (TAG_ID)
    )
3828 [main] DEBUG org.hibernate.tool.hbm2ddl.SchemaExport  - 
    alter table firstOne.PET 
        add constraint FK134FF8F6E060D 
        foreign key (OWNER_ID) 
        references firstOne.OWNER
...
4078 [main] DEBUG org.hibernate.impl.SessionImpl  - opened session at timestamp:
 13627517838
...
4187 [main] DEBUG org.hibernate.SQL  - 
    insert 
    into
        firstOne.OWNER
        (NAME, USER_ID) 
    values
        (?, ?)
...
4375 [main] DEBUG org.hibernate.transaction.JDBCTransaction  - committed JDBC Co
nnection
...
4391 [main] INFO  org.hibernate.impl.SessionFactoryImpl  - closing
4391 [main] INFO  org.hibernate.connection.DriverManagerConnectionProvider  - cl
eaning up connection pool: jdbc:postgresql://localhost:5432/pets
As can be seen from the above:
  1. The persistence.xml file was loaded. Details were retrieved and used from hibernate.cfg.xml
  2. Internally the code created and used an instance of Hibernate's SessionFactory
  3. As the hbm2ddl setting was create, tables were created based on the information provided in the annotations.
  4. To execute the code an instance of Hibernate's session was created.
  5. The transaction implementation also deferred to Hibernate's JDBCTransaction.
The query was executed successfully and record was added to the database.

No comments:

Post a Comment