14 Replies Latest reply on Feb 17, 2010 9:11 AM by jkronegg

    Second level cache and seam managed persistence.

      Used seam-gen to generate a project. Configured 2nd level caching. Persistence context is not scoped in components.xml.


         <persistence:managed-persistence-context name="entityManager"
                                           auto-create="true"
                                entity-manager-factory="#{ch1EntityManagerFactory}"/>
      
         <persistence:entity-manager-factory name="ch1EntityManagerFactory" 
                            persistence-unit-name="ch1"/>
      



      I have a user entity


      @Entity
      @Table(name = "users", catalog = "chapters")
      @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
      public class Users implements java.io.Serializable {



      I Accessed UserList.xhtml which displayed the userlist in a rich:datatable. Modified user data directly in the database and refreshed the userlist page and I see the changes. Is this the right behavior? What happened to the readonly cache which was loaded on the first request? Am I scoping things wrong?


      Am I supposed to read the data using @Factory and scope it to application? But if I scope it then whats the point of having a second level cache? I am totally confused about 2nd level caching. Does it only work with conversation scoped persistence-context?

        • 1. Re: Second level cache and seam managed persistence.
          swd847

          As far as I know hibernate will only use the second level cache when doing a primary key lookup or when using the query cache. If hibernate has already issued a database query and retrieved the entity data, why would it then do a second level cache lookup to retrieve the same (but possibly out of date) data when it already has fresh data from the database.


          To get the behavior you want you have to use the query cache as well.

          • 2. Re: Second level cache and seam managed persistence.
            gonorrhea

            http://solutionsfit.com/blog/2009/04/06/second-level-caching-still-an-effective-performance-tuning-technique/


            You are supposed to use 2nd level cache for read-only or read-mostly data.  Read JPA/Hibernate book for more info.

            • 3. Re: Second level cache and seam managed persistence.
              gonorrhea

              Stuart Douglas wrote on Jun 18, 2009 01:10:

              To get the behavior you want you have to use the query cache as well.


              what is the query cache?  is that Seam or Hibernate/JPA-specific?

              • 4. Re: Second level cache and seam managed persistence.
                swd847

                Hiberbernate specific. You need to make a named query and set cachable to true. You also need to enable the query cache in the configuration.

                • 5. Re: Second level cache and seam managed persistence.

                  Thanks to both Arbi and Stuart. One of the few people that I expected answers from :)


                  First, I apologize for stripping out the details. I used query cache and had the same outcome. I should have mentioned it.


                  @Entity
                  @Table(name = "users", catalog = "chapters")
                  @NamedQueries({@NamedQuery(name = "Users.findAll", query = "Select u from Users u")})
                  @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)
                  public class Users implements java.io.Serializable {
                  


                  My Action class


                    
                     @Factory(value = "myUsersList")  
                     public List<Users> getUserList() {              
                         Session session = (Session) entityManager.getDelegate();
                         Query query = session.getNamedQuery("Users.findAll");
                         query.setCacheable(true);  
                         return query.list()      
                     }
                  



                  persistence.xml


                    <!-- Cache settings -->
                    <property name="hibernate.cache.provider_class" value="org.hibernate.cache.EhCacheProvider" />
                    <property name="hibernate.cache.use_second_level_cache" value="true" />
                    <property name="hibernate.cache.use_query_cache" value="true" />



                  I cannot do query.setCacheable(true) because JPA Query doesn't support that. I had to use hibernate session. I get the same result. I will try to load a single record using primary key and would let you know.

                  • 6. Re: Second level cache and seam managed persistence.

                    Ok. I have tried loading the record with primary key and I got the same result.


                    I modified my action method to load the data with primary key. If I modify data in the database directly after the first fetch and refresh the page, I see the modified data from the database.




                          @Factory(value = "myUsersList")  
                          public List<Users> getUserList() {              
                              Session session = (Session) entityManager.getDelegate();
                              Users user = (Users)session.load(Users.class, 1);
                              System.out.println("*************name " + user.getName());
                              Query query = session.getNamedQuery("Users.findAll");
                              query.setCacheable(true);  
                              return query.list();
                          }
                    



                    I can share the project if need be.

                    • 7. Re: Second level cache and seam managed persistence.
                      swd847

                      setCachable has never worked for me, try using the org.hibernate.cacheable query hint in the @NamedQuery annotation.

                      • 8. Re: Second level cache and seam managed persistence.
                        Ok, finally it worked.

                        FYI: @NamedQuery from hibernate with cacheable="true" did not work. Of course, as you suggested, I had to use @NamedQuery from JPA with hint "org.hibernate.cacheable".

                        So, should I conclude that the only way to use 2nd level caching work with seam is by providing a hint to @NamedQuery?
                        • 9. Re: Second level cache and seam managed persistence.
                          swd847

                          XML also seems to work.

                          • 10. Re: Second level cache and seam managed persistence.
                            sbasinge
                            I've made a slight modification to EntityQuery so that it will accept Boolean hints and then can use:

                            public CustomerSearchList() {
                              setEjbql(EJBQL);
                              setRestrictionExpressionStrings(Arrays.asList(RESTRICTIONS));
                              setMaxResults(25);
                              setOrder("upper(c.lastName), upper(c.firstName)");
                              getHints().put("org.hibernate.cacheable", Boolean.TRUE);
                              getHints().put("org.hibernate.readOnly", Boolean.TRUE);
                            }

                            and the query is cached.

                            Mods to EntityQuery createQuery method are:

                            if (getHints() != null) {
                              for (Map.Entry<String, Object> me : getHints().entrySet()) {
                                if (me.getValue() instanceof String)
                                  query.setHint(me.getKey(), me.getValue());
                                else if (me.getValue() instanceof Boolean) {
                                  Boolean value = (Boolean) me.getValue();
                                  query.setHint(me.getKey(), value.booleanValue());
                                } else {
                                  throw new UnsupportedOperationException(
                                      "Query hint of type " + me.getValue().getClass()
                                      + " not supported.");
                                }
                              }
                            }


                            persistence.xml changes are:

                            <!-- Second level cache config -->
                            <property name="hibernate.cache.use_second_level_cache" value="true"/>
                            <property name="hibernate.cache.use_query_cache" value="true"/>
                            <property name="hibernate.cache.region.jbc2.query.localonly" value="true"/>
                            <property name="hibernate.cache.region.factory_class" value="org.hibernate.cache.jbc2.SharedJBossCacheRegionFactory"/>
                            <property name="hibernate.cache.provider_class" value="org.hibernate.cache.TreeCacheProvider" />
                            <property name="hibernate.cache.region.jbc2.cachefactory" value="java:CacheManager"/>        
                            <property name="hibernate.cache.region.jbc2.cfg.entity" value="mvcc-entity"/>        
                            <property name="hibernate.cache.region.jbc2.cfg.query" value="local-query"/>        
                            <property name="hibernate.cache.region_prefix" value="myDb"/>

                            I can use the @Cache annots on entities and they cache also.
                            @Cache(usage = CacheConcurrencyStrategy.READ_ONLY)


                            • 11. Re: Second level cache and seam managed persistence.

                              If it is not already submitted I think its a useful patch to submit and the way you implemented it will be nicely integrated with the entity framework.

                              • 12. Re: Second level cache and seam managed persistence.
                                jayadevs
                                Hi,



                                Really the information posted above is uiseful.

                                One query, I am trying to cache named queries in JPA, to cache the Named Query results for a particular time period of more than 20 minutes.

                                I have written the ehcache.xml and defined the same reference in the persistence.xml, In the Entity option object, for the Named Query I have defined the Hints with QueryHint  cacheable to true and the region.

                                But the query is being cached for only 2 minutes(120seconds). I would like to cache the query about 20 minutes.


                                Please find the below are the code in persistence.xml, ehcache.xml, POJO(Example: Option.java) and DAO(OptionDAO.java).



                                POJO(Option.java):

                                @NamedQuery(name\=\"findOptionsByLineOfBusinessAndStatus\", query\=\"from Option where uniqueOptionKey.lineOfBusinessId\=:lineOfBusiness AND optionStatus\=:stateCode\", hints\={@QueryHint(name \=\"org.hibernate.cacheable\", value\=\"true\"),@QueryHint(name\="org.hibernate.cacheRegion\", value \=\"query.AdministrativeAreasPerCountry\") })



                                persistence.xml:

                                \<property name\=\"hibernate.cache.use_second_level_cache\" value\=true/\>
                                \<property name\=\"hibernate.cache.use_query_cache\" value\=true/\>
                                \<property name\=\"hibernate.generate_statistics\" value\=true/\>
                                \<property name\=\"hibernate.cache.provider_configuration_file_resource_path\" value\=ehcache.xml/\>  \<!-- ehcache.xml is along with the persistence.xml in META-INF--\>


                                ehcache.xml

                                \<ehcache\>
                                    \<diskStore path\=\"c:\\web\\"/\>
                                    \<defaultCache
                                        maxElementsInMemory\=\"10000\"
                                        eternal\=\"false\"
                                        timeToIdleSeconds\=\"360000\"
                                        timeToLiveSeconds\=\"360000\"
                                        overflowToDisk\=\"true\"
                                        diskPersistent\=\"false\"
                                        diskExpiryThreadIntervalSeconds\=\"360000\"
                                        memoryStoreEvictionPolicy\=\"LRU\"
                                        /\>

                                     \<cache name\=\"org.hibernate.cache.UpdateTimestampsCache\"
                                            maxElementsInMemory\=\"1000\"
                                            eternal\=\"false\"
                                            timeToIdleSeconds\=\"360000\"
                                            timeToLiveSeconds\=\"360000\"
                                            overflowToDisk\=\"true\"
                                            diskPersistent\=\"false\"
                                            diskExpiryThreadIntervalSeconds\=\"360000\"
                                            memoryStoreEvictionPolicy\=\"LRU\"
                                            /\>

                                       \<cache name\=\"org.hibernate.cache.StandardQueryCache\"
                                            maxElementsInMemory\=\"1000\"
                                            eternal\=\"false\"
                                            timeToIdleSeconds\=\"360000\"
                                            timeToLiveSeconds\=\"360000\"
                                            overflowToDisk\=\"true\"           
                                            diskPersistent\=\"false\"
                                            diskExpiryThreadIntervalSeconds\=\"360000\"
                                            memoryStoreEvictionPolicy\=\"LRU\"
                                            /\>  

                                         \<cache name\=\"query.AdministrativeAreasPerCountry\"
                                            maxElementsInMemory\=\"500\"
                                            eternal\=\"false\"
                                            timeToIdleSeconds\=\"180000\"
                                            timeToLiveSeconds\=\"864000\"                  
                                            overflowToDisk\=\"true\"/\> 
                                \</ehcache\>



                                OptionDAO:

                                Query query\=getEntityManager().createNamedQuery(\"from Option where uniqueOptionKey.lineOfBusinessId\= :lineOfBusiness AND optionStatus\= :stateCode)\";
                                query.setParameter(LINE_OF_BUSINESS, lineOfBusiness);
                                query.setParameter(STATE_CODE, stateCode);

                                options\=(List\<Option\>) query.getResultList();


                                Could you please provide some information on the same. where exactly is missing the configuration properties being set are overridden to the default. The query being cached for 2 minutes is the default time to cache.


                                Thanks and Regards,
                                Jayadev S


                                • 13. Re: Second level cache and seam managed persistence.
                                  jayadevs
                                  Hi,



                                  Really the information posted above is uiseful.

                                  One query, I am trying to cache named queries in JPA, to cache the Named Query results for a particular time period of more than 20 minutes.

                                  I have written the ehcache.xml and defined the same reference in the persistence.xml, In the Entity option object, for the Named Query I have defined the Hints --> QueryHint = cacheable to true and the region.

                                  But the query is being cached for only 2 minutes(120seconds). I would like to cache the query about 20 minutes.


                                  Please find the below are the code in persistence.xml, ehcache.xml, POJO(Example: Option.java) and DAO(OptionDAO.java).



                                  POJO(Option.java):

                                  @NamedQuery(name = "findOptionsByLineOfBusinessAndStatus", query = "from Option where uniqueOptionKey.lineOfBusinessId= :lineOfBusiness AND optionStatus= :stateCode", hints = {       @QueryHint(name = "org.hibernate.cacheable", value = "true"),            @QueryHint(name = "org.hibernate.cacheRegion", value = "query.AdministrativeAreasPerCountry") })



                                  persistence.xml:

                                  <property name="hibernate.cache.use_second_level_cache" value="true"/>
                                  <property name="hibernate.cache.use_query_cache" value="true"/>
                                  <property name="hibernate.generate_statistics" value="true"/>
                                  <property name="hibernate.cache.provider_configuration_file_resource_path" value="ehcache.xml"/>  <!-- ehcache.xml is along with the persistence.xml in META-INF-->


                                  ehcache.xml

                                  <ehcache>
                                      <diskStore path="c:\\web\\"/>
                                      <defaultCache
                                          maxElementsInMemory="10000"
                                          eternal="false"
                                          timeToIdleSeconds="360000"
                                          timeToLiveSeconds="360000"
                                          overflowToDisk="true"
                                          diskPersistent="false"
                                          diskExpiryThreadIntervalSeconds="360000"
                                          memoryStoreEvictionPolicy="LRU"
                                          />

                                       <cache name="org.hibernate.cache.UpdateTimestampsCache"
                                              maxElementsInMemory="1000"
                                              eternal="false"
                                              timeToIdleSeconds="360000"
                                              timeToLiveSeconds="360000"
                                              overflowToDisk="true"
                                              diskPersistent="false"
                                              diskExpiryThreadIntervalSeconds="360000"
                                              memoryStoreEvictionPolicy="LRU"
                                              />

                                         <cache name="org.hibernate.cache.StandardQueryCache"
                                              maxElementsInMemory="1000"
                                              eternal="false"
                                              timeToIdleSeconds="360000"
                                              timeToLiveSeconds="360000"
                                              overflowToDisk="true"           
                                              diskPersistent="false"
                                              diskExpiryThreadIntervalSeconds="360000"
                                              memoryStoreEvictionPolicy="LRU"
                                              />  

                                           <cache name="query.AdministrativeAreasPerCountry"
                                              maxElementsInMemory="500"
                                              eternal="false"
                                              timeToIdleSeconds="180000"
                                              timeToLiveSeconds="864000"                  
                                              overflowToDisk="true"/> 
                                  </ehcache>



                                  OptionDAO:

                                  Query query = getEntityManager().createNamedQuery("from Option where uniqueOptionKey.lineOfBusinessId= :lineOfBusiness AND optionStatus= :stateCode)";
                                  query.setParameter(LINE_OF_BUSINESS, lineOfBusiness);
                                  query.setParameter(STATE_CODE, stateCode);

                                  options = (List<Option>) query.getResultList();


                                  Could you please provide some information on the same. where exactly is missing the configuration properties being set are overridden to the default. The query being cached for 2 minutes is the default time to cache.


                                  Thanks and Regards,
                                  Jayadev S
                                  • 14. Re: Second level cache and seam managed persistence.
                                    jkronegg

                                    Alternatively, you can enable the query cache on a query using:


                                    myEntityQuery.getHints().put("name=org.hibernate.cacheable", "value=true");