5

I'm struggling to configure hibernate jmx in order to have some metrics with the hibernate jconsole plugin.

actually I followed the configuration from the official website of hibernate jconsole plugin: http://hibernate-jcons.sourceforge.net/usage.html#pre-requisites

but it doesn't work so I searched on internet for hours, tested things. the only relevant thing I found, related to my problem, is that: How to configure Hibernate statistics in Spring 3.0 application?

But It still doesn't work. I need your help.

here is the configuration:

@PersistenceContext(unitName = DomainConstants.JPA_PU_BACKEND)
private EntityManager em;

@Bean(name="jmxExporter")
public MBeanExporter    jmxExporter() throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, NotCompliantMBeanException {
    MBeanExporter exporter = new MBeanExporter();
    Map<String, Object> beans = new HashMap<String, Object>();
    beans.put("Hibernate:application=Statistics", "hibernateStatisticsBean");
    MBeanServerFactoryBean serverFactory = new MBeanServerFactoryBean();
    serverFactory.setLocateExistingServerIfPossible(true);
    // --- new1
    MBeanServer MBeanServer = serverFactory.getObject();
    exporter.setServer(MBeanServer);
    exporter.setRegistrationPolicy(RegistrationPolicy.REPLACE_EXISTING);
    // end -- new1
    exporter.setBeans(beans);
    return exporter;
}


@Bean(name="hibernateStatisticsBean")
public StatisticsService hibernateStatisticsBean() {
    StatisticsService service = new StatisticsService();
    service.setStatisticsEnabled(true);
    service.setSessionFactory(((Session)em.getDelegate()).getSessionFactory());
    return service;
}

I also set hibernate.generate_statistics to true to the hibernate configuration.

I'm stuck. I really need this tool to work since we have queries that take a lot of time. this tool would be perfect.

EDIT: The MBean seems to be loaded. the attributes change when I do queries. image2 http://imageshack.com/a/img838/5904/dj8c.png

But when I tried to invoke one of the operations: getQueryStatistics, getCollectionStatistics etc.. I get the following error: image1 http://imageshack.com/a/img838/9693/ibkd.png

And actually I have no stats about the queries, nothing displayed: image3 http://imageshack.com/a/img835/8088/laoz.png

Community
  • 1
  • 1
Jeremy S.
  • 125
  • 3
  • 9
  • Try setting the bean reference directly, instead of its name: `beans.put("Hibernate:application=Statistics", hibernateStatisticsBean())`. – Andrei Stefan May 03 '14 at 22:11
  • thank you Andrei for your help. I tried your solution but it doesn't change anything. – Jeremy S. May 04 '14 at 16:02
  • When you say it doesn't work, what does that mean? The MBean don't show up in JMX, you can connect to JMX server etc? Can you post some logs? – Andrei Stefan May 04 '14 at 17:38
  • I edited the main post. I got the following log when starting the application : mai 04, 2014 9:10:22 PM org.springframework.jmx.export.MBeanExporter afterPropertiesSet Infos: Registering beans for JMX exposure on startup mai 04, 2014 9:10:22 PM org.springframework.jmx.export.MBeanExporter registerBeanInstance Infos: Located MBean 'Hibernate:application=Statistics': registering with JMX server as MBean [Hibernate:application=Statistics] – Jeremy S. May 04 '14 at 20:52
  • 1
    The docs say hibernate jar needs to be on the jconsole's classpath. Do you have it where it should? – Andrei Stefan May 04 '14 at 23:45
  • Hi Andrei. thank you very much for your help. Actually I was using a hibernate jar that I download and I didn't used the jar used by the app. I inform the one used by the app and now it works. thank you very much! – Jeremy S. May 21 '14 at 11:00
  • @AndreiStefan thank you. Even after three years your answer is helping. – Tareq May 23 '17 at 13:40

2 Answers2

7

I know this post is two years old, but I wanted to share this in case other people have been having trouble getting the Hibernate JConsole plugin working with the latest Spring and Hibernate.

My environment is Java 8, Spring Boot 1.4.0 (Spring 4.3.2 and Hibernate 5.0.9).

I tried several different things that people mentioned worked for them in Hibernate 4.3, but they didn't work for me. Finally, I decided to take some advice from someone else I found in the Hibernate feature request forums (asking to bring back JMX support for Hibernate Statistics) who suggested grabbing the old StatisticsServiceMBean from Hibernate 3.2.7.

I updated the MBean and used it to wrap the Statistics object from Hibernate 5 using JMX Annotations, and of course it worked.

So you don't have to type all this in, here it is:

import javax.persistence.EntityManagerFactory;
import javax.servlet.ServletContext;

import org.hibernate.jpa.HibernateEntityManagerFactory;
import org.hibernate.SessionFactory;
import org.hibernate.stat.CollectionStatistics;
import org.hibernate.stat.EntityStatistics;
import org.hibernate.stat.QueryStatistics;
import org.hibernate.stat.SecondLevelCacheStatistics;
import org.hibernate.stat.Statistics;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jmx.export.annotation.ManagedAttribute;
import org.springframework.jmx.export.annotation.ManagedOperation;
import org.springframework.jmx.export.annotation.ManagedResource;
import org.springframework.stereotype.Component;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

@Component
@ManagedResource("Hibernate:application=Statistics")
public class HibernateStatisticsMBean implements InitializingBean {

    @Autowired 
    private ServletContext servletContext;

    private Statistics stats;

    @Override
    public void afterPropertiesSet() throws Exception {
        WebApplicationContext wac = WebApplicationContextUtils.getWebApplicationContext(servletContext);
        EntityManagerFactory emf = (EntityManagerFactory) wac.getBean("entityManagerFactory");
        SessionFactory sessionFactory = ((HibernateEntityManagerFactory) emf).getSessionFactory();
        sessionFactory.getStatistics().setStatisticsEnabled(true);
        this.stats = sessionFactory.getStatistics();
    }

    @ManagedOperation
    public void clear() {
        stats.clear();
    }

    @ManagedOperation
    public EntityStatistics getEntityStatistics(String entityName) {
        return stats.getEntityStatistics(entityName);
    }

    @ManagedOperation
    public CollectionStatistics getCollectionStatistics(String role) {
        return stats.getCollectionStatistics(role);
    }

    @ManagedOperation
    public SecondLevelCacheStatistics getSecondLevelCacheStatistics(String regionName) {
        return stats.getSecondLevelCacheStatistics(regionName);
    }

    @ManagedOperation
    public QueryStatistics getQueryStatistics(String hql) {
        return stats.getQueryStatistics(hql);
    }

    @ManagedAttribute
    public long getEntityDeleteCount() {
        return stats.getEntityDeleteCount();
    }

    @ManagedAttribute
    public long getEntityInsertCount() {
        return stats.getEntityInsertCount();
    }

    @ManagedAttribute
    public long getEntityLoadCount() {
        return stats.getEntityLoadCount();
    }

    @ManagedAttribute
    public long getEntityFetchCount() {
        return stats.getEntityFetchCount();
    }

    @ManagedAttribute
    public long getEntityUpdateCount() {
        return stats.getEntityUpdateCount();
    }

    @ManagedAttribute
    public long getQueryExecutionCount() {
        return stats.getQueryExecutionCount();
    }

    @ManagedAttribute
    public long getQueryCacheHitCount() {
        return stats.getQueryCacheHitCount();
    }

    @ManagedAttribute
    public long getQueryExecutionMaxTime() {
        return stats.getQueryExecutionMaxTime();
    }

    @ManagedAttribute
    public long getQueryCacheMissCount() {
        return stats.getQueryCacheMissCount();
    }

    @ManagedAttribute
    public long getQueryCachePutCount() {
        return stats.getQueryCachePutCount();
    }

    @ManagedAttribute
    public long getFlushCount() {
        return stats.getFlushCount();
    }

    @ManagedAttribute
    public long getConnectCount() {
        return stats.getConnectCount();
    }

    @ManagedAttribute
    public long getSecondLevelCacheHitCount() {
        return stats.getSecondLevelCacheHitCount();
    }

    @ManagedAttribute
    public long getSecondLevelCacheMissCount() {
        return stats.getSecondLevelCacheMissCount();
    }

    @ManagedAttribute
    public long getSecondLevelCachePutCount() {
        return stats.getSecondLevelCachePutCount();
    }

    @ManagedAttribute
    public long getSessionCloseCount() {
        return stats.getSessionCloseCount();
    }

    @ManagedAttribute
    public long getSessionOpenCount() {
        return stats.getSessionOpenCount();
    }

    @ManagedAttribute
    public long getCollectionLoadCount() {
        return stats.getCollectionLoadCount();
    }

    @ManagedAttribute
    public long getCollectionFetchCount() {
        return stats.getCollectionFetchCount();
    }

    @ManagedAttribute
    public long getCollectionUpdateCount() {
        return stats.getCollectionUpdateCount();
    }

    @ManagedAttribute
    public long getCollectionRemoveCount() {
        return stats.getCollectionRemoveCount();
    }

    @ManagedAttribute
    public long getCollectionRecreateCount() {
        return stats.getCollectionRecreateCount();
    }

    @ManagedAttribute
    public long getStartTime() {
        return stats.getStartTime();
    }

    @ManagedAttribute
    public boolean isStatisticsEnabled() {
        return stats.isStatisticsEnabled();
    }

    @ManagedOperation
    public void setStatisticsEnabled(boolean enable) {
        stats.setStatisticsEnabled(enable);
    }

    @ManagedOperation
    public void logSummary() {
        stats.logSummary();
    }

    @ManagedAttribute
    public String[] getCollectionRoleNames() {
        return stats.getCollectionRoleNames();
    }

    @ManagedAttribute
    public String[] getEntityNames() {
        return stats.getEntityNames();
    }

    @ManagedAttribute
    public String[] getQueries() {
        return stats.getQueries();
    }

    @ManagedAttribute
    public String[] getSecondLevelCacheRegionNames() {
        return stats.getSecondLevelCacheRegionNames();
    }

    @ManagedAttribute
    public long getSuccessfulTransactionCount() {
        return stats.getSuccessfulTransactionCount();
    }

    @ManagedAttribute
    public long getTransactionCount() {
        return stats.getTransactionCount();
    }

    @ManagedAttribute
    public long getCloseStatementCount() {
        return stats.getCloseStatementCount();
    }

    @ManagedAttribute
    public long getPrepareStatementCount() {
        return stats.getPrepareStatementCount();
    }

    @ManagedAttribute
    public long getOptimisticFailureCount() {
        return stats.getOptimisticFailureCount();
    }

    @ManagedAttribute
    public String getQueryExecutionMaxTimeQueryString() {
        return stats.getQueryExecutionMaxTimeQueryString();
    }

}
Chris Jensen
  • 291
  • 3
  • 4
1

Great answer from @Chris Jensen

In my case I needed to tweak it a little to make it working:

...
@Component
@ManagedResource("Hibernate:application=Statistics")
public class HibernateStatisticsMBean implements InitializingBean {

@Autowired
private EntityManagerFactory entityManagerFactory;

private Statistics stats;

@Override
public void afterPropertiesSet() throws Exception {
    SessionFactory sessionFactory = entityManagerFactory.unwrap(SessionFactory.class);
    sessionFactory.getStatistics().setStatisticsEnabled(true);
    this.stats = sessionFactory.getStatistics();
}
...
Martin Patsov
  • 366
  • 5
  • 10