Troubleshooting entity persistence

It is very thorough and clean specification that allows the skilled developer to write persistence code as Java object with meta data. The meta data allows the JPA provider to store data into a relational database. The technical content of JPA specification is of such a high level that cloud computing providers are already attempting to adapt it to their specialist environments, which have included key-value No-SQL database, albeit with limitations.

Nevertheless, if your development is targeted at relational databases then JPA canhelp your application evolve at fast agile pace without having to handcode native SQL statements.

Fetch performance

In the earlier part of the chapter, we introduced the topic of fetching and accessing information from database tables into entity object instances. A huge factor that influences the performance of JPA application is the object model: how an entity is associated with an other dependent entity. The more dependent entities there are in a master entity, the more work the persistence provider must do. The object model and how these entities are mapped to the database tables influence the persistence provider.

It is useful to remember that FetchType.LAZY is the default for @OneToMany and @ManyToMany associations; FetchType.EAGER is the default for @OneToOne and @ManyToOne association.

For certain situations, provided you always follow the golden rule: measure before and rule, then you override the FetchType.EAGER for the one-to-one and many-to-one associations. If you switch to lazily binding dependent object, be prepared to factor in detachment from the entity manager and reattachment.

Prefer lazily binding for maximum performance

If you are sending a master entity with a lazily bounded dependent entity across a JVM boundary across the network, and if the client suddenly expects to access the dependency, then there will be a problem on the client side application. One way to get out of this fix to have an aggregated view, a so-called projection view object.

Finally, binding affects query performance. The way the persistence provider eventually optimizes query could vary between lazily and eagerly bounded dependent entities.

Entity Relationship

The entity relationship and object-relational mapping can be problematic. Choosing the correct java.util.Collection interface obviously early in the development goes a long way to good design. Some persistence providers extend the JPA specification by allowing ordered collections. On the other hand, for true application portability across a number of database vendors it may be best to take control of this in your application. An ordered collection can be achieved with an artificial positioning field and it can, of course, be completed with a JPQL query with a particular ORDER BY clause. There are also a couple of further annotations to look for in the JPA specification that can be applied to entity relationships: they are called @javax.persistence.OrderBy and @javax.persistence.OrderColumn.

Here is an example of @OrderColumn in use with our employee entity, once again, on one-to-many association with phone records:

@Entity
public class Employee implements java.io.Serializable {
    /*...*/
    
    @OneToMany(cascade = CascadeType.ALL)
    @OrderColumn(name="PHONE_ORDER")
    private List<Phone> phones;
    
    public List<Phone> getPhones() { return phones; }
    public void setPhones(List<Phone> phone) {
        this.phones = phones; }    
}

The @OrderColumn may only be specified on a one-to-many or a many-to-many association. This annotation specifies that the persistence provider order the list collection of Phone entities using the field or property accessor called PHONE_ORDER, which must exist on the Phone entity.

The @OrderBy annotation specifies the ordering of a collection of dependent entities when the persistence provider retrieves those entities. Thus @OrderBy has subtly different behavior from the @OrderColumn; the latter implies a modification of the database schema.

Let's rework the employee entity with the @OrderBy annotation:

@Entity
public class Employee implements java.io.Serializable {
    /*...*/
    
    @OneToMany(cascade = CascadeType.ALL)
    @OrderBy("interCode ASC, areaCode ASC")
    private List<Phone> phones;
    /*...*/  
}

In the previous code, the collection of Phone entities are ordered by the international code and then by area code; both orders are ascending. It is possible to reverse the order, make the ordering descend with DESC. If no order is supplied, then the default is ASC. As you can see, you delimit separate different orders by using a comma as a delimiter.

In terms of efficiency, when you have full administrative control of the database, then use @OrderColumn, because the order is then persistent inside the database. If you have no control because the database is owned by a different division, team, or even is a third-party, then you may prefer to use @OrderBy.

Prefer orphan removal

In JPA 2.0 and better you are advised to think about the orphanRemoval attribute in the entity relationship. This flag handles the situation when you remove an entity from a collection of entities, for example in @OneToMany association. In JPA 1.0, the developer had to invoke EntityManager.remove(). In JPA 2.0, the entity itself will handle removal automatically with orphanRemoval=true even if the cascade operation CascadeType.REMOVE is omitted.

Excessive queries

It is quite easy to get into trouble with one-to-many relationships with queries on the master object. Object-relational mapping providers have denoted this issue as the N+1 problem (or more accurately M(1+[N of R(M)])).

Suppose we have Project and Task entities in a one-to-many relationship. We have M projects and each project entity stores N project tasks and if we also say the binding is FetchType.EAGER, then for every Project query the persistence provider has to make N additional queries to retrieve the Task information.

The problem exacerbates itself in search listing. Display a list of projects to the user with their tasks. It is retrieving the list of projects and dependent task entities that causes excessive queries.

From the point-of-view of the persistence provider, the simplest native SQL queries would look exactly like the following:

-- One operation to retrieve
SELECT * FROM PROJECT

-- For each row from EMPLOYEE then execute
SELECT * FROM TASK WHERE PROJECT_ID = ?

The solution is to use a technique called Joined Fetching, which results in both Project and Tasks data being retrieved in a single query.

SELECT p FROM Project p JOIN FETCH p.tasks

Object corruption

JPA specification supports bidirectional relationships and the persistence providers do a fantastic job to allow these entity associations to be mapped to a database. A Java developer has to ensure that the application updates both sides of the relationship. If the entity is added to one side of the relationship, the inverse relationship must be also taken care of, otherwise object corruption will take place at some stage during persistence.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.191.195.111