使用 Hibernate 存储统计数据

Store statistics with Hibernate

我有 AOP 方面来计算某些服务被调用的次数:

@Aspect
@Component
public class CounterAspect {

    private Map<Integer, Integer> gettingEventStatistics = new HashMap<>();

    @Pointcut("execution(Event EventService+.getById(Integer))")
    private void gettingEvent() {}

    @AfterReturning(pointcut = "gettingEvent()", returning = "retVal")
    public void countGettingEvent(JoinPoint joinPoint, Object retVal) {
        Integer id = (Integer) joinPoint.getArgs()[0];
        if (id != null && retVal != null) {
            Integer currentCounterValue = gettingEventStatistics.get(id);
            gettingEventStatistics.put(id, currentCounterValue == null ? 1 : currentCounterValue + 1);
        }
    }
}

如何使用 Hibernate 将此类信息存储在数据库中?

最简单的方法是将其解析为 JSON 并存储为字符串。请记住增加列最大内存大小。

我制定了以下解决方案 - 为统计信息创建了实体

@Entity
public class GettingEventsStats {
    @Id
    private Integer eventId;
    private Integer gettingCounter;
//getters, setters, etc.

在我的方面注入了 DAO 委托,具有这样的功能:

@Repository
public class HibernateStatsDao implements StatsDao {

    @Autowired
    private SessionFactory sessionFactory;

    @Override
    public GettingEventsStats getGettingEventStats(Integer eventId) {
        return sessionFactory.getCurrentSession().get(GettingEventsStats.class, eventId);
    }

    @Override
    public void createGettingEventCounter(Integer eventId) {
        GettingEventsStats gettingEventsStats = new GettingEventsStats();
        gettingEventsStats.setEventId(eventId);
        gettingEventsStats.setGettingCounter(1);
        sessionFactory.getCurrentSession().save(gettingEventsStats);
    }

    @Override
    public void updateGettingEventCounter(Integer eventId) {
        GettingEventsStats gettingEventStats = getGettingEventStats(eventId);
        gettingEventStats.setGettingCounter(gettingEventStats.getGettingCounter() + 1);
        sessionFactory.getCurrentSession().update(gettingEventStats);
    }
}

并将方面逻辑更改为:

@Autowired
private StatsDao statsDao;

@Pointcut("execution(Event EventService+.getById(Integer))")
private void gettingEvent() {}

@AfterReturning(pointcut = "gettingEvent()", returning = "retVal")
public void countGettingEvent(JoinPoint joinPoint, Object retVal) {
    Integer eventId = (Integer) joinPoint.getArgs()[0];
    if (eventId != null && retVal != null) {
        GettingEventsStats gettingEventStats = statsDao.getGettingEventStats(eventId);
        if (gettingEventStats == null) {
            statsDao.createGettingEventCounter(eventId);
        } else {
            statsDao.updateGettingEventCounter(eventId);
        }
    }
}

您将使用此方法保存大量条目。最好使用 Dropwizard Metrics,它使用 Reservoirs 进行数据采样和自定义报告器。

通常,指标最好通过 JMX 暴露给 APM 工具。或者您应该为此目的使用 Graphite 或 Graphana。