How do Hibernate event listeners behave using HQL (named queries)?

I create many sleep event listeners to catch all database events, such as loading, saving, updating, deleting, etc. All events will be caught, but named requests will not be caught by my listener on load events, and I would like to ask what should I implement in order to find out the name request?

+3
source share
1 answer

Basically, the participation of events is determined by the type of event (listener) and the method of data extraction. Although you are correct, there is actually a difference between working with entity queries (EntityManager.find ..., Session.load ...) and working with HQL queries. But it doesn’t matter if HQL queries are used as a named query or as a regular query in the case of HQL.

To show this, I created a small example using Spring Boot, Spring Data JPA and Hibernate, because it works easily with this combination. The effects are similar to other application architectures using Hibernate.

, , LoadEvent, EntityManager.find/Session.load Entity. HQL ( Spring Data JPA, Hibernate) , . , PostLoadEvents .

, .

InterceptionByEventCandidate ( , ):

package com.example.model;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;

@Entity
public class InterceptionByEventCandidate {

    public static final String FETCH_ALL_QUERY = "SELECT c FROM InterceptionByEventCandidate c";
    public static final String FETCH_ALL_NAMED_QUERY = "selectAll";

    @Id
    @GeneratedValue
    private long id;

    private boolean interceptedOnLoad;

    private boolean interceptedOnPostLoad;

    public long getId() {
        return id;
    }

    public boolean isInterceptedOnLoad() {
        return interceptedOnLoad;
    }

    public void setInterceptedOnLoad(boolean interceptedOnLoad) {
        this.interceptedOnLoad = interceptedOnLoad;
    }

    public boolean isInterceptedOnPostLoad() {
        return interceptedOnPostLoad;
    }

    public void setInterceptedOnPostLoad(boolean interceptedOnPostLoad) {
        this.interceptedOnPostLoad = interceptedOnPostLoad;
    }

}

CandidateHost ( ):

package com.example.model;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToOne;

@Entity
public class CandidateHost {

    public static final String FETCH_ALL_QUERY = "SELECT h FROM CandidateHost h JOIN h.candidate c";
    public static final String FETCH_ALL_NAMED_QUERY = "selectAllHosts";

    @Id
    @GeneratedValue
    private long id;

    @OneToOne(cascade = CascadeType.PERSIST)
    private InterceptionByEventCandidate candidate;

    public InterceptionByEventCandidate getCandidate() {
        return candidate;
    }

    public void setCandidate(InterceptionByEventCandidate candidate) {
        this.candidate = candidate;
    }

}

, HqlEventListener:

package com.example.event;

import org.hibernate.HibernateException;
import org.hibernate.event.spi.LoadEvent;
import org.hibernate.event.spi.LoadEventListener;
import org.hibernate.event.spi.PostLoadEvent;
import org.hibernate.event.spi.PostLoadEventListener;
import org.springframework.stereotype.Component;

import com.example.model.InterceptionByEventCandidate;

@Component
public class HqlEventListener implements LoadEventListener, PostLoadEventListener {

    private static final long serialVersionUID = -7248393324424903264L;

    @Override
    public void onLoad(LoadEvent event, LoadType loadType) throws HibernateException {
        final Object object = event.getResult();
        if (object instanceof InterceptionByEventCandidate) {
            ((InterceptionByEventCandidate) object).setInterceptedOnLoad(true);
        }
    }

    @Override
    public void onPostLoad(PostLoadEvent event) {
        final Object object = event.getEntity();
        if (object instanceof InterceptionByEventCandidate) {
            ((InterceptionByEventCandidate) object).setInterceptedOnPostLoad(true);
        }
    }

}

Hibernate, , :

package com.example.event;

import javax.annotation.PostConstruct;
import javax.persistence.EntityManagerFactory;
import javax.persistence.PersistenceUnit;

import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.internal.SessionFactoryImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;

@Configuration
public class EntityListenerConfiguration {

    @PersistenceUnit
    private EntityManagerFactory entityManagerFactory;

    @Autowired
    private HqlEventListener hqlEventListener;

    @PostConstruct
    protected void init() {
        final SessionFactoryImpl sessionFactory = entityManagerFactory.unwrap(SessionFactoryImpl.class);
        final EventListenerRegistry eventListenerRegistry = sessionFactory.getServiceRegistry()
                .getService(EventListenerRegistry.class);

        eventListenerRegistry.getEventListenerGroup(EventType.LOAD).appendListener(hqlEventListener);
        eventListenerRegistry.getEventListenerGroup(EventType.POST_LOAD).appendListener(hqlEventListener);

    }
}

, :

@NamedQueries({
        @NamedQuery(name = InterceptionByEventCandidate.FETCH_ALL_NAMED_QUERY, query = InterceptionByEventCandidate.FETCH_ALL_QUERY),
        @NamedQuery(name = CandidateHost.FETCH_ALL_NAMED_QUERY, query = CandidateHost.FETCH_ALL_QUERY) })

package com.example.event;

import org.hibernate.annotations.NamedQueries;
import org.hibernate.annotations.NamedQuery;

import com.example.model.CandidateHost;
import com.example.model.InterceptionByEventCandidate;

, , JPA Spring , , .

InterceptionByEventCandidateRepository:

package com.example.repository;

import java.util.Set;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.example.model.InterceptionByEventCandidate;

@Repository
public interface InterceptionByEventCandidateRepository extends CrudRepository<InterceptionByEventCandidate, Long> {

    @Query(InterceptionByEventCandidate.FETCH_ALL_QUERY)
    @Transactional(readOnly = true)
    Set<InterceptionByEventCandidate> findByHQL();

    @Query(name = InterceptionByEventCandidate.FETCH_ALL_NAMED_QUERY)
    @Transactional(readOnly = true)
    Set<InterceptionByEventCandidate> findByNamedHQL();
}

CandidateHostRepository:

package com.example.repository;

import java.util.Set;

import org.springframework.data.jpa.repository.Query;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import com.example.model.CandidateHost;

@Repository
public interface CandidateHostRepository extends CrudRepository<CandidateHost, Long> {

    @Query(CandidateHost.FETCH_ALL_QUERY)
    @Transactional(readOnly = true)
    Set<CandidateHost> findByHQL();

    @Query(name = CandidateHost.FETCH_ALL_NAMED_QUERY)
    @Transactional(readOnly = true)
    Set<CandidateHost> findByNamedHQL();

}

, ( ) , , :

package com.example.repository;

import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertThat;

import java.util.Set;

import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import org.hibernate.Query;
import org.hibernate.Session;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.Transactional;

import com.example.model.CandidateHost;
import com.example.model.InterceptionByEventCandidate;

@RunWith(SpringRunner.class)
@Transactional
@SpringBootTest
public class HqlEventTests {

    @Autowired
    private CandidateHostRepository candidateHostRepository;

    @Autowired
    private InterceptionByEventCandidateRepository interceptionByEventCandidateRepository;

    @PersistenceContext
    private EntityManager entityManager;

    @Before
    public void setUp() {
        final CandidateHost host = new CandidateHost();
        final InterceptionByEventCandidate interceptionByEventCandidate = new InterceptionByEventCandidate();
        host.setCandidate(interceptionByEventCandidate);
        candidateHostRepository.save(host);
        entityManager.flush();
        entityManager.clear();
    }

    @Test
    public void interceptCandidateAtFindingHostBySpringDataJpaHql() {
        final Set<CandidateHost> result = candidateHostRepository.findByHQL();
        verifyInterceptions(result.stream().findFirst().get().getCandidate(), true, true);
    }

    @Test
    public void interceptCandidateAtFindingHostBySpringDataJpaNamedHql() {
        final Set<CandidateHost> result = candidateHostRepository.findByNamedHQL();
        verifyInterceptions(result.stream().findFirst().get().getCandidate(), true, true);
    }

    @Test
    public void interceptCandidateAtFindingHostByHibernateHql() {
        final Session session = entityManager.unwrap(Session.class);
        final Query query = session.createQuery(CandidateHost.FETCH_ALL_QUERY);

        verifyInterceptions(((CandidateHost) query.list().stream().findFirst().get()).getCandidate(), true, true);
    }

    @Test
    public void interceptCandidateAtFindingHostByHibernateNamedHql() {
        final Session session = entityManager.unwrap(Session.class);
        final Query query = session.getNamedQuery(CandidateHost.FETCH_ALL_NAMED_QUERY);

        verifyInterceptions(((CandidateHost) query.list().stream().findFirst().get()).getCandidate(), true, true);
    }

    @Test
    public void interceptCandidateBySpringDataJpaHql() {
        final Set<InterceptionByEventCandidate> result = interceptionByEventCandidateRepository.findByHQL();
        verifyInterceptions(result.stream().findFirst().get(), false, true);
    }

    @Test
    public void interceptCandidateBySpringDataJpaNamedHql() {
        final Set<InterceptionByEventCandidate> result = interceptionByEventCandidateRepository.findByNamedHQL();
        verifyInterceptions(result.stream().findFirst().get(), false, true);
    }

    @Test
    public void interceptCandidateByHibernateHql() {
        final Session session = entityManager.unwrap(Session.class);
        final Query query = session.createQuery(InterceptionByEventCandidate.FETCH_ALL_QUERY);

        verifyInterceptions((InterceptionByEventCandidate) query.list().stream().findFirst().get(), false, true);
    }

    @Test
    public void interceptCandidateByHibernateNamedHql() {
        final Session session = entityManager.unwrap(Session.class);
        final Query query = session.getNamedQuery(InterceptionByEventCandidate.FETCH_ALL_NAMED_QUERY);

        verifyInterceptions((InterceptionByEventCandidate) query.list().stream().findFirst().get(), false, true);
    }

    @Test
    public void interceptCandidateByHibernateFind() {
        long id = interceptionByEventCandidateRepository.findAll().iterator().next().getId();

        entityManager.flush();
        entityManager.clear();

        final Session session = entityManager.unwrap(Session.class);
        final InterceptionByEventCandidate candidate = session.load(InterceptionByEventCandidate.class, id);
        verifyInterceptions(candidate, true, true);
    }

    private void verifyInterceptions(final InterceptionByEventCandidate candidate, final boolean expectedLoadEventState,
            final boolean expectedPostLoadEventState) {
        assertThat("Expected load state did not match!", candidate.isInterceptedOnLoad(), is(expectedLoadEventState));
        assertThat("Expected postload state did not match!", candidate.isInterceptedOnPostLoad(),
                is(expectedPostLoadEventState));
    }
}

, , . , , .

+3

Source: https://habr.com/ru/post/1776166/


All Articles