• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

Propagation of Persistence Contexts

 
Greenhorn
Posts: 29
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello everybody!
I hope you can help me to get a better understanding of how Persistence Contexts get propagated... I spent a lot of time with this problem but am still not sure of what happens behind the scenes..
Here follows a short description of what I have done..

I am using EJB 3.1 together with JPA2 (eclipseLink) and have the following Entities (simplified):



They model the fact that a Testsuite groups several Tests which fall under a specific name (e.g.: "Standard testsuite"). Every time a Testsuite is executed on a Server, a file is produced that looks something like this:

Testsuite: Standard testsuite
Executed on: Server1
Started at: 2011-10-10 10:11:24

TEST-1024 "Test with name X": Success
TEST-1025 "Test whit another name": Failure
...



At this point, other Entities come into play:



The idea is that an output File as the one above describes a TestsuiteRun, which has an association to the TestSuite that got executed (its name is Unique) together with a collection of TestRuns, each corresponding to a Test. For brevity, in the pseudo-code above I've omitted to specify that most of the associations are bidirectional, i.e. a Test knows all of its TestRuns (and viceversa); a Machine knows all of the TestsuiteRuns which got executed on it; a TestRun knows the TestsuiteRun it belongs to, and so on..

Now, my application parses a file at a time with the twofold aim of:

  • inserting (if they have not been already stored) new Testsuites/Tests/Server into the DB
  • creating a TestsuiteRun object together with all the related TestRuns.


  • For better performances at point 1), I use a cache object, which gets initialized with pre-existing data from the DB and is responsible for adding new records when it is the case. Here is a reduced version of it:



    All of the DAOs use a Transaction-scoped EntityManager:



    As you can see, I use an extended PersistenceContext and every time I read or write to the DB I use em.merge() in order to keep the entities managed. I have read in the book "Pro JPA 2" that in situations like this the PC gets propagated (in my case from Cache to TestDAO): this should mean that doing testDao.persist(t) within retrieveTestCreateIfNotPresent() should be enough to make sure t remains managed (hence the em.merge() in this case could be omitted)?

    The situation is more unclear when the file parser comes into play. The code which does the job is something like:



    Being the TestsuiteRunBuilder declared as follows:



    Also this class uses an Extended PC and such a bean should live only in the time span which goes from the beginning of the file parsing to the insertion into the DB (build is annotated with Remove). Of course the associations of TestsuiteRun are instructed to propagate merge..
    You can see that I've marked Cache as Singleton, as I'd like to let the cache remain in memory also for the next file..
    The application seems to work, but I am not really sure why.. What happens for example when I parse the second file? In what relation is the PersistenceContext of the new (the 2nd) TestsuiteRunBuilder object with that of Cache (which should be still "alive")?


    I am really, really confused... What shall I change in this design? Isn't there a way to make things easier?

    Thanks a lot for your help!

    Bye!
     
    Ranch Hand
    Posts: 553
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I think you are probably making things more complicated than they need to be. Since JPA (EclipseLink) already maintains an object cache, you can probably do away with your Cache. That should simplify things considerably.

    Just call find() with the id to find the entity, and if it is in the cache, it will not access the database. You will only need to call merge() if you have changed a detached object.
     
    Federico Minarelli
    Greenhorn
    Posts: 29
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    James Sutherland wrote:I think you are probably making things more complicated than they need to be. Since JPA (EclipseLink) already maintains an object cache, you can probably do away with your Cache. That should simplify things considerably.

    Just call find() with the id to find the entity, and if it is in the cache, it will not access the database. You will only need to call merge() if you have changed a detached object.



    Hi and thanks for answering!
    As far as I understood, shared cache is enabled by default in EclipseLink. To make sure to activate it, I added to my persistence.xml. Shouldn't then the result of each query be automatically cached?
    I've changed my Cache class to query directly the DB (throught DAOs'methods) instead of storing the values into Maps, but with a FINE log level I can see the SQL SELECT queries get executed every time I call a findXXXCreateIfAbsent() method.. What is wrong in this approach?

    thanks again for your help! Bye
     
    James Sutherland
    Ranch Hand
    Posts: 553
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    If you call find() using the Id, this will first check the cache.

    If you execute a Query, this will not check the cache by default. If the Query is by the Id, just use find() instead. You could also set the "eclipselink.cache-usage" Query hint to "CheckCacheByPrimaryKey", to make a Query access the cache.

    If the Query is not by Id then you can use a query cache, set "eclipselink.query-results-cache"="true".
     
    what if we put solar panels on top of the semi truck trailer? That could power this tiny ad:
    Gift giving made easy with the permaculture playing cards
    https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
    reply
      Bookmark Topic Watch Topic
    • New Topic