首页 > 解决方案 > 检测表中插入数据并调用方法

问题描述

我在检测向表中添加新行时遇到问题。当有人在数据库(Postgres)上执行插入查询时,我想从某个服务(Spring boot)触发一个方法

有人告诉我,我可以使用 @Scheduled 注释并检查是否使用存储库添加了某些内容。我必须立即进行一些更改(通过使用另一种方法)。计划的方法应每 5 秒运行一次以立即执行此操作。当然,这是一个非常糟糕的主意,因为它有一天会杀死数据库并且效率不高。我怎样才能做得更好?

标签: springpostgresqlspring-boothibernatejpa

解决方案


您可以编写org.hibernate.integrator.spi.Integrator. 并将其提供给hibernate.integrator_provider FromServiceRegistry我们可以获取EventListenerRegistry然后附加类型的侦听器EventType.POST_INSERT。更多活动在这里

主要参考Hibernate Integrator 参考

根据查询,我还添加了如何从侦听器类调用服务方法。

以下是我的做法:

package com.example.samplejdbctemplatecall;

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.service.spi.EventListenerRegistry;
import org.hibernate.event.spi.EventType;
import org.hibernate.event.spi.PostInsertEvent;
import org.hibernate.event.spi.PostInsertEventListener;
import org.hibernate.integrator.spi.Integrator;
import org.hibernate.jpa.boot.spi.IntegratorProvider;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.orm.jpa.HibernatePropertiesCustomizer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.repository.CrudRepository;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.util.Collections;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;


@RequestMapping(path = "/entity-listener")
@RestController
public class SampleLogController {

    private final SampleLogRepository sampleLogRepository;
    private final SampleLogEntries sampleLogEntiries;

    @Autowired
    public SampleLogController(SampleLogRepository sampleLogRepository, SampleLogEntries sampleLogEntiries) {
        this.sampleLogRepository = sampleLogRepository;
        this.sampleLogEntiries = sampleLogEntiries;
    }


    // This is usually post method but for test purpose creating new log with uuid random and inserting
    @GetMapping(path = "insert")
    public SampleLog insertNewEntry() {
        final String uuid = UUID.randomUUID().toString();
        final SampleLog sampleLog = new SampleLog();
        sampleLog.setMessage(uuid);
        return sampleLogRepository.save(sampleLog);
    }

    @GetMapping(path = "list-recent-inserts")
    public Map<Long, String> entries() {
        return sampleLogEntiries.data();
    }

}

@Slf4j
@Component
class HibernateConfig implements HibernatePropertiesCustomizer {

    private final JpaEventListenerIntegrator jpaEventListenerIntegrator;

    @Autowired
    HibernateConfig(JpaEventListenerIntegrator jpaEventListenerIntegrator) {
        this.jpaEventListenerIntegrator = jpaEventListenerIntegrator;
    }

    @Override
    public void customize(Map<String, Object> hibernateProperties) {
        log.warn("Called hibernate configuration");
        hibernateProperties.put("hibernate.integrator_provider",
                (IntegratorProvider) () -> Collections.singletonList(jpaEventListenerIntegrator));
    }
}

@Configuration
class SampleConfiguration {

    @Bean
    SampleLogEntries sampleEntries() {
        return new SampleLogEntries();
    }
}


class SampleLogEntries {
    private final ConcurrentMap<Long, String> map = new ConcurrentHashMap<>();

    public void add(SampleLog sampleLog) {
        this.map.put(sampleLog.getId(), sampleLog.getMessage());
    }

    public Map<Long, String> data() {
        return Collections.unmodifiableMap(this.map);
    }

}

@Repository
interface SampleLogRepository extends CrudRepository<SampleLog, Long> {

}


@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Entity
class SampleLog {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String message;
}

@Service
@Slf4j
class JpaEventListenerIntegrator implements Integrator, PostInsertEventListener {

    private final SampleLogEntries sampleLogEntiries;

    @Autowired
    JpaEventListenerIntegrator(SampleLogEntries sampleLogEntiries) {
        this.sampleLogEntiries = sampleLogEntiries;
    }


    @Override
    public void integrate(Metadata metadata, SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
        eventListenerRegistry
                .appendListeners(EventType.POST_INSERT, this);
    }

    @Override
    public void disintegrate(SessionFactoryImplementor sessionFactory, SessionFactoryServiceRegistry serviceRegistry) {
        final EventListenerRegistry eventListenerRegistry = serviceRegistry.getService(EventListenerRegistry.class);
        EventListenerGroup<PostInsertEventListener> eventListenerGroup = eventListenerRegistry
                .getEventListenerGroup(EventType.POST_INSERT);
        log.info("listener attached were: " + eventListenerGroup.getClass().getSimpleName());
        log.error("disintegrate : " + getClass().getCanonicalName());
        eventListenerGroup.clearListeners();
    }

    @Override
    public void onPostInsert(PostInsertEvent event) {
        log.info("Inserted : " + event.getEntity());
        final Object entity = event.getEntity();
        if (entity instanceof SampleLog) {
            sampleLogEntiries.add((SampleLog) entity);
        }
    }


    @Override
    public boolean requiresPostCommitHanding(EntityPersister persister) {
        return false;
    }
}


推荐阅读