3

We are starting to develop a new web application using JSF (MyFaces on TomEE) and JPA (Eclipselink).

To make develop time faster, we are planning to NOT develop a DTO layer, basically because we do not need it. Following the JSF and Java EE experts advises like Bauke Scholtz How to use DTO in JSF + Spring + Hibernate and Adam Bien How evil are Data Transfer Objects, we'll use JPA entities directly in the presentation layer.

Yet this application must run in a server cluster with sticky session. When a server goes down for maintenance or it is excluded from the cluster for application deploying, user sessions of that server must be served by other servers, without losing the session.

The problem we are facing is that JPA entities that are saved in session (for example in a @ViewScoped bean), are not "completely" replicated on other servers. In fact collection attributes of JPA entities that uses lazy loading are not usable on other servers. When accessing a collection attibute (@OneToMany that use lazy loading) on a server that has the session replica, the exception

org.eclipse.persistence.exceptions.ValidationException 
Exception Description: An attempt was made to traverse a relationship 
using indirection that had a null Session.  
This often occurs when an entity with an uninstantiated LAZY 
relationship is serialized and that relationship is traversed 
after serialization. 
To avoid this issue, instantiate the LAZY relationship 
prior to serialization

is thrown.

I know that EntityManager is not serializable and JPA entities goes completely detached when serialized during session migration, see Struberg's Blog.

So the question is, is there a way to maintain JPA entities in a consistent way in a server cluster, without using EAGER loading?

Alexcat
  • 87
  • 4
  • Do you have cache turned on ? – Sorin Penteleiciuc Feb 20 '19 at 11:48
  • Maybe something like https://stackoverflow.com/questions/7058843/when-and-how-to-use-hibernate-second-level-cache helps (a question about cache like the previous comment refers to) and use it in a replicated way – Kukeltje Feb 20 '19 at 11:48
  • 1
    Did you try to check if the entity is detached + merge on that entity before accessing the collection? – tandraschko Feb 20 '19 at 12:10
  • 1
    @SorinPenteleiciuc yes cache is turned on – Alexcat Feb 20 '19 at 12:56
  • @tandraschko Yes, entities are obviously detached when sessions are migrated in a replica server. How to reattach them in a transparent way from the application point of view? – Alexcat Feb 20 '19 at 13:03
  • @Kukeltje thank you, but I think the problem is not cache related. The problem is that entities in replica server are detached. So for example when accessing OneToMany collections exception is thrown. – Alexcat Feb 20 '19 at 13:08
  • If you don't use them in the session but reuse them from the cache, that is not a problem iirc. And entities put in the session are detached from the entity manager anyway, even on the same server (unless you use an extended persistence context which by itself is 'dangerous' iirc). – Kukeltje Feb 20 '19 at 13:45
  • @Kukeltje I don't put nothing in session, it is JSF the uses the session for saving the scope, for example ViewScoped. So if a server goes down, the user session is redirected to the backup server, but all entities declared in the ViewScoped page are detached. I do not use extended persistence context, accessing collections through lazy loading in detached entities is permitted, see https://www.objectdb.com/issue/326 – Alexcat Feb 20 '19 at 14:10
  • I always use EntityManager#merge - same problem happens when you use ViewScope with entities + RequestScoped EM. – tandraschko Feb 20 '19 at 20:05

1 Answers1

1

You could configure the cache only for some Entities only (the once who change very rare)

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://xmlns.jcp.org/xml/ns/persistence"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd"
             version="2.1">

    <persistence-unit name="name" transaction-type="JTA">
        <!-- disable shared cache because we are in multi instance environment -->
        <shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>
        <validation-mode>CALLBACK</validation-mode>

        <properties> 
            <!-- disable object caching because we are in multi instance environment -->
            <property name="eclipselink.cache.shared.default" value="true"/>
            <property name="javax.persistence.sharedCache.mode" value="ENABLE_SELECTIVE"/>
            </properties>
    </persistence-unit>

</persistence>

You can also see here how to do it in a shared environment https://wiki.eclipse.org/EclipseLink/UserGuide/JPA/Basic_JPA_Development/Caching/Query_Cache

Sorin Penteleiciuc
  • 653
  • 1
  • 10
  • 26
  • It is not a cache problem. If a server goes down, the user session is redirected to the backup server, but all entities declared in the ViewScoped page are detached. For example, if I access a lazy @OneToMany collection on the backup server an Exception is thrown. This not happens on the server that at first as loaded entities. – Alexcat Feb 21 '19 at 08:51
  • 1
    @Alexcat: (Http)Session cache/failover != jpa cache/failover – Kukeltje Jul 11 '19 at 10:41
  • @Kukeltje yes I know. So do you believe that the exception I reported above `org.eclipse.persistence.exceptions.ValidationException` is related to jpa cache? The exception description states clearly that it occurs when the entity is serialized, and during (Http)Session migration enities are serialized! – Alexcat Jul 11 '19 at 12:40