Search code examples
hibernatehazelcast

Hibernate - Hazelcast. Second level cache.Could not find a SessionFactory exception


Legend:

  • 2 application instances with Hazelcast on each.
  • Hazelcast instances configured in cluster. Configuration is properly configured, synchronization performed (tested in manual mode).
  • Hibernate is using Hazelcast as second-level cache provider.

In application exists entity with next class level annotations:

@Entity
@Cache( usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE )
@Table( name = "entity", catalog = "main" )
@IdClass( EntityPK.class )

When update for this entity performed to database on first instance, Exception com.hazelcast.nio.serialization.HazelcastSerializationException: org.hibernate.HibernateException: Could not find a SessionFactory [uuid=ee9f3ccd-1f7e-4345-83ed-e58440a52123,name=null] is thrown on second instance.

After debug I located cause of this exception - it thrown by org.hibernate.type.spi.TypeConfiguration.Scope#readResolve method during deserialization. Instance of this class is part of default Hibernate cache key object.

From what I found out. Object that cause problem is "session scoped". In other words it is bounded to specific SessionFactory and contain in its fields session factory UUID and reference to factory itself. During serialization factory UUID is preserved. When deserialization is performed, object tries to restore link to its factory but it deserializaed in other instance where session factory with specified UUID not exists. Because session factory is missing exception is thrown.

Is there are way to avoid this exception?

Hibernate and related libs versions is next:

<hibernate.version>5.3.14.Final</hibernate.version>
<hibernate-types-52.version>2.5.0</hibernate-types-52.version>
<hazelcast.version>3.11.5</hazelcast.version>
<dependency>
    <groupId>com.hazelcast</groupId>
    <artifactId>hazelcast-hibernate53</artifactId>
    <version>1.3.2</version>
</dependency>
        <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-entitymanager</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-jpamodelgen</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <dependency>
        <groupId>org.hibernate</groupId>
        <artifactId>hibernate-envers</artifactId>
        <version>${hibernate.version}</version>
    </dependency>

    <dependency>
        <groupId>com.vladmihalcea</groupId>
        <artifactId>hibernate-types-52</artifactId>
        <version>${hibernate-types-52.version}</version>
    </dependency>

Solution

  • In your Hibernate configuration, include the following property:

    <property name="hibernate.session_factory_name">some_sf_name</property>
    

    When a composite primary key is used it's mapped to org.hibernate.usertype.UserType which has a reference to a SessionFactory. That's why the other instance raises error when it cannot find the proper SF.

    From the Hibernate doc:

    hibernate.session_factory_name (e.g. A JNDI name): Setting used to name the Hibernate SessionFactory. Naming the SessionFactory allows for it to be properly serialized across JVMs as long as the same name is used on each JVM.