DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones AWS Cloud
by AWS Developer Relations
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Partner Zones
AWS Cloud
by AWS Developer Relations
Building Scalable Real-Time Apps with AstraDB and Vaadin
Register Now

Trending

  • Design Patterns for Microservices: Ambassador, Anti-Corruption Layer, and Backends for Frontends
  • Managing Data Residency, the Demo
  • Micro Frontends on Monorepo With Remote State Management
  • Tomorrow’s Cloud Today: Unpacking the Future of Cloud Computing

Trending

  • Design Patterns for Microservices: Ambassador, Anti-Corruption Layer, and Backends for Frontends
  • Managing Data Residency, the Demo
  • Micro Frontends on Monorepo With Remote State Management
  • Tomorrow’s Cloud Today: Unpacking the Future of Cloud Computing
  1. DZone
  2. Data Engineering
  3. Databases
  4. Open JPA - L2 Cache Issue and Workaround

Open JPA - L2 Cache Issue and Workaround

Atul Kshirsagar user avatar by
Atul Kshirsagar
·
Dec. 30, 14 · Interview
Like (1)
Save
Tweet
Share
3.10K Views

Join the DZone community and get the full member experience.

Join For Free

I ran into an interesting issue with OpenJPA in one of my projects. I thought it would be good to share the issue I faced and the workaround I found for benefit of anyone who might run into the same issue.

The issue comes up when we are trying to load an entity that has some relations with fetch type set to LAZY. This issue is observed only when L2 cache is turned ON. L2 cache is typically turned ON to improve performance and can be done by adding following property to persistence unit in persistence.xml:

<property name="openjpa.DataCache" value="true" />  

To explain the issue in detail I will use a model so that we can base our discussion around it. So first lets get that down:

ER model

As can be seen from above ER diagram Person has one to one relation with Address and one to many relation with PhoneNumber.
Relevant code snippet from entities is shown below

@Entity  
public class Person {  
     @Id  
     @GeneratedValue(generator = "person_seq", strategy = GenerationType.SEQUENCE)  
     private int id;  
   
     private String firstName;  
     
     private String lastName;  
     
     @OneToOne(mappedBy = "person", fetch = FetchType.LAZY)  
     private Address address;  
     
     @OneToMany(cascade = CascadeType.ALL, mappedBy = "person", orphanRemoval=true)  
     private List<PhoneNumber> phoneNumbers;  
     ....  
 } 

 @Entity  
 public class Address {  
     @Id  
     @GeneratedValue(strategy = GenerationType.AUTO)  
     private int id;  
 
     private String streetAddress;  
 
     private String city;  
 
     private String zipCode;  

     @OneToOne  
     @JoinColumn(name="PERSON_ID")  
     private Person person;  
     ...  
 } 


 @Entity  
 public class PhoneNumber {  
     @Id  
     @GeneratedValue(strategy = GenerationType.AUTO)  
     private int id;  
 
     private String number;  
   
     @OneToOne  
     @JoinColumn(name="PERSON_ID")  
     private Person person;  
     ...  
 } 


Problem

When we create a new instance of Person and Address, since Person is non-owing side of relation, we set Person instance in Address but don't set Address instance in Person (this is quite possible when Person and Address entities are persisted by different parts of application). We then persist both Person and Address instance. Later when we query Person entity by using EntityManager.find() method (may be in different part of application) the returned instance of Person doesn't have Address field set. This field doesn't get set even if we query Address entity independently. What this means is that applications depending on the lazy field to be loaded when they access it will run into NullPointerException. So in this case when you invoke Person.getAddress() then the returned value will always be null.This is because the Person instance that was cached was the one that did not have "Address" field set (the instance constructed during persistence of Person instance) and that instance never gets refreshed even after subsequent queries.

This issue was observed with OpenJPA 2.2.2. Looking up online revealed that there was a defect that was fixed on trunk that was related to L2 cache (https://issues.apache.org/jira/browse/OPENJPA-2285), which appeared to be the one that would solve this issue. However, even after back porting that fix in 2.2.2 branch same issue was seen.

Workaround

The only way I found that we can work around this issue is by evicting the entity under consideration from the cache after you have persisted the entity. So in the above case evicting Person instance after persisting (and committing the transaction) will make sure that subsequent find calls to entity manager would return an entity whose fields will be appropriately populated and we won't run into any NullPointerException.

// Here emf is EntityManagerFactory  
emf.getCache().evict(Person.class, this.personId);  

With above fix Person.getAddress() would return appropriate instance of Address when Person instance is obtained by using find method on EntityManager.

This workaround ensures that you can use l2 cache (and gain the performance improvements it brings) while making sure you won't run into any unexpected NullPointerExceptions when trying to access lazily loaded children/relations of an entity. If possible use this workaround in your application until a fix is available from OpenJPA to load the entity appropriately.

I have logged a defect against OpenJPA (https://issues.apache.org/jira/browse/OPENJPA-2522) to track this issue and have also submitted a test case to the community.
Cache (computing) Workaround Database Relational database

Published at DZone with permission of Atul Kshirsagar. See the original article here.

Opinions expressed by DZone contributors are their own.

Trending

  • Design Patterns for Microservices: Ambassador, Anti-Corruption Layer, and Backends for Frontends
  • Managing Data Residency, the Demo
  • Micro Frontends on Monorepo With Remote State Management
  • Tomorrow’s Cloud Today: Unpacking the Future of Cloud Computing

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com

Let's be friends: