JPA stands for "Java Persistence API" - an API that tries to replace direct Hibernate (or other ORM) usage with more generic layer that allows to replace underlying ORM with no application code changes.
Although ORM (object relational mappers) typically use relational database under the hood JPA is not restricted to relational databases. I'll present how object database (objectdb) can be used using JPA interface.
All the source code can be located here: https://github.com/dcieslak/jee-samples/tree/master/jpa.
Classes
Firstly, you have to define your model and relations using POJO with JPA annotations. We try to make model as simple as possible, so no getters/setters pairs if not really required.
@Entity class SystemUser implements Serializable { @Id @Column @GeneratedValue(strategy=GenerationType.AUTO) public Integer userId; @Column public String systemUserName; @Column public Departament department; public String toString() { return "SystemUser(" + systemUserName + ", " + department + ")"; } }
A bit of explanation:
- @Entity: annotation marks class that will be mapped to persistent entity. If the name of corresponding table is the same as class name you don't have to specify it explicitly. It makes class description more compact
- @Id: marks given property to be primary identifier of a class. Uniqueness is assumed for the column.
- @GeneratedValue: primary key must be assigned an unique value when object is created. By this annotation you can select generation method for identifiers.
- @Column: a property of the persisted entity.
- Departament department: here we have relation many to one to Department class. It's implemented as foreign key pointing to Department table with index for speeding up access.
- toString(): in order to be able to print object description to the stdout I've redefined toString() method, it makes debugging much easier.
Department can be defined in a very similar way.
Setup
In order to use JPA (except classpath dependencies) you have to initialize the persistence engine. As stated above we will use objectdb implementation of JPA.
EntityManagerFactory factory = Persistence.createEntityManagerFactory( "$objectdb/db/samplejpa.odb"); EntityManager em = factory.createEntityManager();
Here we will use database stored in db/samplejpa.odb file in the classpath where objectdb.jar is stored. Of course for production deployment client-server architecture will be more efficient, we leave file usage for sake of setup simplicity.
CRUD operations with JPA
CRUD operations look very familiar for anyone coming from Hibernate world:
em.getTransaction().begin(); System.out.println("Clearing database:"); em.createQuery("DELETE FROM SystemUser").executeUpdate(); em.createQuery("DELETE FROM Departament").executeUpdate(); System.out.println("Two objects created with 1-N association:"); Departament d = new Departament(); d.departamentName = "Dept1"; em.persist(d); SystemUser u = new SystemUser(); u.systemUserName = "User1"; u.department = d; em.persist(u); System.out.println("Querying database:"); TypedQuery<Departament> dq = em.createQuery("SELECT D FROM Departament D", Departament.class); for (Departament d2: dq.getResultList()) { System.out.println("Loaded: " + d2); } TypedQuery<SystemUser> sq = em.createQuery("SELECT S FROM SystemUser S", SystemUser.class); for (SystemUser s: sq.getResultList()) { System.out.println("Loaded: " + s); } em.getTransaction().commit();
Some notes to above code:
- Every database updates set must be enclosed in a transaction (begin() / commit())
- TypedQuery<T> interface is a very nice extension to old-style Query interface that was not parametrized.
- persist(obj) is responsible for storing object in a database, JPA implementation discovers target table by reflection
- DB state mutable queries: executed by executeUpdate() call - sometimes can save much time when handling big database tables
Maven project
And finally: you have to build/execute all the example app. I've selected Maven as it makes collecting dependencies much easier (and you don't have to store jars in your source code repository).
<repositories> <repository> <id>objectdb</id> <name>ObjectDB Repository</name> <url>http://m2.objectdb.com</url> </repository> </repositories> <dependencies> <dependency> <groupId>com.objectdb</groupId> <artifactId>objectdb</artifactId> <version>2.2.5</version> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.5</source> <target>1.5</target> </configuration> </plugin> <plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>exec-maven-plugin</artifactId> <version>1.2</version> <executions> <execution> <phase>test</phase> <goals> <goal>java</goal> </goals> <configuration> <mainClass>samplejpa.Main</mainClass> </configuration> </execution> </executions> </plugin> </plugins> </build>
In order to build application execute: mvn test and the result of program run will be presented on screen.