title: Why EhCache not caching this query?
body: <p>Looking at Hibernate metrics, it appears that there is no use of second level cache for specific query:</p>
  
  <pre><code>org.hibernate.HibernateException: More than one row with the given identifier was found: 1242, for class: com.hibernate.query.performance.persistence.model.Store
  INFO: Session Metrics {
      28572828 nanoseconds spent acquiring 1 JDBC connections;
      0 nanoseconds spent releasing 0 JDBC connections;
      6518980126 nanoseconds spent preparing 1396 JDBC statements;
      9007649169 nanoseconds spent executing 1396 JDBC statements;
      0 nanoseconds spent executing 0 JDBC batches;
      77148015 nanoseconds spent performing 1486 L2C puts;
      0 nanoseconds spent performing 0 L2C hits;
      71112 nanoseconds spent performing 1 L2C misses;
      0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
      0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
  }
  org.hibernate.HibernateException: More than one row with the given identifier was found: 1242, for class: com.hibernate.query.performance.persistence.model.Store
  org.hibernate.engine.internal.StatisticalLoggingSessionEventListener end
  INFO: Session Metrics {
      25857570 nanoseconds spent acquiring 1 JDBC connections;
      0 nanoseconds spent releasing 0 JDBC connections;
      3010741744 nanoseconds spent preparing 1396 JDBC statements;
      8950885558 nanoseconds spent executing 1396 JDBC statements;
      0 nanoseconds spent executing 0 JDBC batches;
      54506271 nanoseconds spent performing 1486 L2C puts;
      0 nanoseconds spent performing 0 L2C hits;
      20938 nanoseconds spent performing 1 L2C misses;
      0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
      0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
  }
  </code></pre>
  
  <p>Code:</p>
  
  <pre><code>@Override
      public List&lt;Customer&gt; getFilteredCustomers(String filter) {
          Session session = null;
          List&lt;Customer&gt; customers = new ArrayList&lt;&gt;();
              try {
                  session = sessionFactory.openSession();
                  Query query = session.createQuery("select c " +
                          " from Rental r, Customer c join fetch c.address address " +
                          " where r.customer = c " +
                          " and r.returnDate is null");
                  query.setCacheable(true);
                  customers = (List&lt;Customer&gt;)query.list();
              }catch (Exception e){
                  System.out.println(e);
              }finally {
                  if (session!=null) session.close();
              }
  
          return customers;
      }
  </code></pre>
  
  <p><strong>Configuration:</strong></p>
  
  <pre><code>import net.sf.ehcache.config.CacheConfiguration;
  import org.springframework.cache.CacheManager;
  import org.springframework.cache.annotation.CachingConfigurer;
  import org.springframework.cache.annotation.EnableCaching;
  import org.springframework.cache.ehcache.EhCacheCacheManager;
  import org.springframework.cache.interceptor.CacheErrorHandler;
  import org.springframework.cache.interceptor.CacheResolver;
  import org.springframework.cache.interceptor.KeyGenerator;
  import org.springframework.cache.interceptor.SimpleKeyGenerator;
  import org.springframework.context.annotation.Bean;
  import org.springframework.context.annotation.Configuration;
  
  @Configuration
  @EnableCaching
  public class CachingConfig implements CachingConfigurer {
  
      @Bean(destroyMethod="shutdown")
      public net.sf.ehcache.CacheManager ehCacheManager() {
          CacheConfiguration cacheConfiguration = new CacheConfiguration();
          cacheConfiguration.setName("theEHCache");
          cacheConfiguration.setMemoryStoreEvictionPolicy("LRU");
          cacheConfiguration.setMaxElementsInMemory(1000);
  
          net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
          config.addCache(cacheConfiguration);
  
          return net.sf.ehcache.CacheManager.create(config);
      }
  
      @Bean
      @Override
      public CacheManager cacheManager() {
          return new EhCacheCacheManager(ehCacheManager());
      }
  
      @Override
      public CacheResolver cacheResolver() {
          return null;
      }
  
      @Bean
      @Override
      public KeyGenerator keyGenerator() {
          return new SimpleKeyGenerator();
      }
  
      @Override
      public CacheErrorHandler errorHandler() {
          return null;
      }
  }
  </code></pre>
  
  <p><strong>ApplicationConfig:</strong></p>
  
  <pre><code>    @Configuration
  @EnableTransactionManagement
  @EnableJpaRepositories (basePackages = { "com.hibernate.query.performance.persistence" }, transactionManagerRef = "hibernateTransactionManager")
  @EnableJpaAuditing
  @PropertySource({ "classpath:persistence-postgresql.properties" })
  @ComponentScan(basePackages = { "com.hibernate.query.performance" })
  @EnableCaching
  public class ApplicationConfig {
  
      @Autowired
      private Environment env;
  
      public ApplicationConfig() {
          super();
      }
  
      @Bean
      public LocalSessionFactoryBean sessionFactory() {
          final LocalSessionFactoryBean sessionFactory = new LocalSessionFactoryBean();
          sessionFactory.setDataSource(applicationDataSource());
          sessionFactory.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
          sessionFactory.setHibernateProperties(hibernateProperties());
  
          return sessionFactory;
      }
  
      @Bean
      public LocalContainerEntityManagerFactoryBean entityManagerFactory() {
          final LocalContainerEntityManagerFactoryBean emf = new LocalContainerEntityManagerFactoryBean();
          emf.setDataSource(applicationDataSource());
          emf.setPackagesToScan(new String[] { "com.hibernate.query.performance.persistence.model" });
  
          final JpaVendorAdapter vendorAdapter = new HibernateJpaVendorAdapter();
          emf.setJpaVendorAdapter(vendorAdapter);
          emf.setJpaProperties(hibernateProperties());
  
          return emf;
      }
  
      @Primary
      @Bean
      public DriverManagerDataSource applicationDataSource() {
          final DriverManagerDataSource dataSource = new DriverManagerDataSource();
          dataSource.setDriverClassName(Preconditions.checkNotNull(env.getProperty("jdbc.driverClassName")));
          dataSource.setUrl(Preconditions.checkNotNull(env.getProperty("jdbc.url")));
          dataSource.setUsername(Preconditions.checkNotNull(env.getProperty("jdbc.user")));
          dataSource.setPassword(Preconditions.checkNotNull(env.getProperty("jdbc.pass")));
          return dataSource;
      }
  
      @Bean
      @Autowired
      @Primary
      public HibernateTransactionManager hibernateTransactionManager(SessionFactory sessionFactory) {
          final HibernateTransactionManager transactionManager = new HibernateTransactionManager();
          transactionManager.setSessionFactory(sessionFactory().getObject());
          transactionManager.setDataSource(applicationDataSource());
          return transactionManager;
      }
  
      /**
       * JTA (usually through JtaTransactionManager) is necessary for accessing multiple transactional resources within the same transaction.
       * The DataSource that Hibernate uses needs to be JTA-enabled in such a scenario (see container setup).
       * http://stackoverflow.com/questions/26562787/hibernateexception-couldnt-obtain-transaction-synchronized-session-for-current
       * @return
       */
      @Bean
      public PlatformTransactionManager jpaTransactionManager() {
          final JpaTransactionManager transactionManager = new JpaTransactionManager();
          transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
          return transactionManager;
      }
  
      @Bean
      public PersistenceExceptionTranslationPostProcessor exceptionTranslation() {
          return new PersistenceExceptionTranslationPostProcessor();
      }
  
      private final Properties hibernateProperties() {
          final Properties hibernateProperties = new Properties();
          hibernateProperties.setProperty("hibernate.dialect", env.getProperty("hibernate.dialect"));
          hibernateProperties.setProperty("hibernate.show_sql", env.getProperty("hibernate.show_sql"));
          hibernateProperties.setProperty("hibernate.format_sql", env.getProperty("hibernate.format_sql"));
          hibernateProperties.setProperty("hibernate.generate_statistics", env.getProperty("hibernate.generate_statistics"));
          hibernateProperties.setProperty("hibernate.cache.use_second_level_cache", env.getProperty("hibernate.cache.use_second_level_cache"));
          hibernateProperties.setProperty("hibernate.cache.use_query_cache", env.getProperty("hibernate.cache.use_query_cache"));
          hibernateProperties.setProperty("hibernate.cache.region.factory_class", env.getProperty("hibernate.cache.region.factory_class"));
          hibernateProperties.setProperty("hibernate.current_session_context_class", "managed"); // https://docs.jboss.org/hibernate/core/3.3/reference/en-US/html/architecture.html#architecture-current-session
          hibernateProperties.setProperty("hibernate.current_session_context_class", "org.hibernate.context.internal.ThreadLocalSessionContext");
          hibernateProperties.setProperty("hibernate.cache.region_prefix", env.getProperty("hibernate.cache.region_prefix"));
          return hibernateProperties;
      }
      @Bean
      public EhCacheCacheManager cacheManager() {
          return new EhCacheCacheManager(ehCacheCacheManager().getObject());
      }
  
      @Bean
      public EhCacheManagerFactoryBean ehCacheCacheManager() {
          EhCacheManagerFactoryBean cmfb = new EhCacheManagerFactoryBean();
          cmfb.setConfigLocation(new ClassPathResource("ehcache.xml"));
          cmfb.setShared(true);
          return cmfb;
      }
  }
  </code></pre>
  
  <p><strong>ehcache.xml</strong></p>
  
  <pre><code>&lt;ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns=""
           xsi:noNamespaceSchemaLocation="ehcache.xsd"
           updateCheck="true"
           monitoring="autodetect"
           dynamicConfig="true"
           maxBytesLocalHeap="150M"&gt;
  
      &lt;diskStore path="java.io.tmpdir" /&gt;
  
  
      &lt;cache name="customerCache"
             maxElementsInMemory="10000"
             maxElementsOnDisk="1000"
             eternal="false"
             diskSpoolBufferSizeMB="20"
             timeToIdleSeconds="300" timeToLiveSeconds="600"
             memoryStoreEvictionPolicy="LFU"
             transactionalMode="off"&gt;
      &lt;/cache&gt;
  
      &lt;defaultCache
             maxElementsInMemory="10000"
             maxElementsOnDisk="1000"
             eternal="false"
             diskSpoolBufferSizeMB="20"
             timeToIdleSeconds="300" timeToLiveSeconds="600"
             memoryStoreEvictionPolicy="LFU"
             transactionalMode="off"&gt;
      &lt;/defaultCache&gt;
  &lt;/ehcache&gt;
  </code></pre>
  
  <p><strong>persistence-postgresql.properties</strong></p>
  
  <pre><code>hibernate.dialect=org.hibernate.dialect.PostgreSQLDialect
  hibernate.show_sql=false
  hibernate.format_sql=false
  hibernate.generate_statistics=true
  hibernate.cache.use_second_level_cache=true
  hibernate.cache.region.factory_class=org.hibernate.cache.ehcache.EhCacheRegionFactory
  hibernate.cache.use_query_cache=true
  hibernate.cache.region_prefix=""
  </code></pre>
  
  <p>Console:</p>
  
  <pre><code>    INFO: HCANN000001: Hibernate Commons Annotations {4.0.5.Final}
  54  org.hibernate.dialect.Dialect &lt;init&gt;
  INFO: HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
  54  org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
  INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
  55  org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory &lt;init&gt;
  INFO: HHH000397: Using ASTQueryTranslatorFactory
  55  org.hibernate.cache.spi.UpdateTimestampsCache &lt;init&gt;
  INFO: HHH000250: Starting update timestamps cache at region: "".org.hibernate.cache.spi.UpdateTimestampsCache
  55  org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory getCache
  WARN: HHH020003: Could not find a specific ehcache configuration for cache named ["".org.hibernate.cache.spi.UpdateTimestampsCache]; using defaults.
  55  org.hibernate.cache.internal.StandardQueryCache &lt;init&gt;
  INFO: HHH000248: Starting query cache at region: "".org.hibernate.cache.internal.StandardQueryCache
  55  org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory getCache
  WARN: HHH020003: Could not find a specific ehcache configuration for cache named ["".org.hibernate.cache.internal.StandardQueryCache]; using defaults.
  55  org.hibernate.validator.internal.util.Version &lt;clinit&gt;
  INFO: HV000001: Hibernate Validator 5.2.2.Final
  57  org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory getCache
  WARN: HHH020003: Could not find a specific ehcache configuration for cache named ["".customerCache]; using defaults.
  58  org.hibernate.dialect.Dialect &lt;init&gt;
  INFO: HHH000400: Using dialect: org.hibernate.dialect.PostgreSQLDialect
  58  org.hibernate.engine.jdbc.internal.LobCreatorBuilder useContextualLobCreation
  INFO: HHH000424: Disabling contextual LOB creation as createClob() method threw error : java.lang.reflect.InvocationTargetException
  58  org.hibernate.engine.transaction.internal.TransactionFactoryInitiator initiateService
  INFO: HHH000399: Using default transaction strategy (direct JDBC transactions)
  58  org.hibernate.hql.internal.ast.ASTQueryTranslatorFactory &lt;init&gt;
  INFO: HHH000397: Using ASTQueryTranslatorFactory
  58  org.hibernate.cache.spi.UpdateTimestampsCache &lt;init&gt;
  INFO: HHH000250: Starting update timestamps cache at region: "".org.hibernate.cache.spi.UpdateTimestampsCache
  58  org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory getCache
  WARN: HHH020003: Could not find a specific ehcache configuration for cache named ["".org.hibernate.cache.spi.UpdateTimestampsCache]; using defaults.
  58  org.hibernate.cache.internal.StandardQueryCache &lt;init&gt;
  INFO: HHH000248: Starting query cache at region: "".org.hibernate.cache.internal.StandardQueryCache
  58  org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory getCache
  WARN: HHH020003: Could not find a specific ehcache configuration for cache named ["".org.hibernate.cache.internal.StandardQueryCache]; using defaults.
  59  org.hibernate.cache.ehcache.AbstractEhcacheRegionFactory getCache
  WARN: HHH020003: Could not find a specific ehcache configuration for cache named ["".customerCache]; using defaults.
  :03  org.apache.catalina.core.ApplicationContext log
  INFO: Initializing Spring FrameworkServlet 'SpringDispatcher'
  :03  org.apache.coyote.AbstractProtocol start
  INFO: Starting ProtocolHandler ["http-bio-8080"]
  </code></pre>
  
  <hr>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Based on a few unit tests I came to conclusion derived from results of test:</p>
  
  <p>The <strong>given query</strong> is not cached in both cases: where there is present <code>join fetch c.address address</code> or not. However, <code>join fetch c.address address</code> speeds up the query more than 2x times. If anyone can explain why underlying frameworks think the query is not worth caching I would be glad.</p>