28 Feb 2014

Configure ehcache with JPA

  • Advance


Many times in our projects we need to access static data tables, sometimes accessing all the data and sometimes recovering one key element. These calls are the same data again and again, consuming time accessing the database. An important part of our developments is the speed and database accesses are a major penalty. Let's see how to improve the speed using ehcache in accessing methods based on static data tables

  • Explanation


In our repository we created the example working properly SVN repository. It´s a maven proyect and We need a local mysql database to make it work. The script of our example is in the Main.java in the svm. With the script you can create you the schema, table and data necessary. To model the table 'Vehicle' will use JPA.

@Entity
@Table(name = "VEHICLES")
public class Vehicle implements Serializable {
 
 private static final long serialVersionUID = -4295164392260587011L;

 public Vehicle() {
  super();
 }
 
 /**
  * Id
  */
 @Id
 @Column(name = "IDVEHICLE")
 private Integer id;
 
 /**
  * Name
  */
 @Column(name = "NAME", nullable = false, length = 45)
 private String name;
 
 /**
  * Name
  */
 @Column(name = "DESCRIPTION", length = 150)
 private String description;
 
 /**
  * Constructor
  * @param id
  * @param name
  * @param description
  */
 public Vehicle(Integer id, String name, String description) {
  super();
  this.id = id;
  this.name = name;
  this.description = description;
 }
  
 /**
  * @return the id
  */
 public Integer getId() {
  return id;
 }


 /**
  * @param id the id to set
  */
 public void setId(Integer id) {
  this.id = id;
 }

 /**
  * @return the name
  */
 public String getName() {
  return name;
 }

 /**
  * @param name the name to set
  */
 public void setName(String name) {
  this.name = name;
 }

 /**
  * @return the description
  */
 public String getDescription() {
  return description;
 }

 /**
  * @param description the description to set
  */
 public void setDescription(String description) {
  this.description = description;
 }

 @Override
 public String toString() {
  return "Vehicle [id=" + this.id + ", name=" + this.name + ", description=" + this.description + "]";
 }
}
And we create a DAO with the methods getAll y getVehicle. We can see how we use the @Cacheable annotation to indicate that the method we want to be cached
@Component("vehicleDAO")
@Repository
public class VehicleDAO extends AbstractJpaDAO{
 
 public VehicleDAO(){
  setClassName(Vehicle.class);
 }
 
 
 @Cacheable(value = "vehicleCache")
 public List getAll() {
  
  List lstVehicles0 = this.findAll();
  
  return lstVehicles0;
  
 }
 
 @Cacheable(value = "vehicleCache", key = "#id")
 public Vehicle getVehicle(Integer id) {
  
  Vehicle objVehicle = this.findOne(id);
     
  return objVehicle;
 }
 
 public void insert(Vehicle vehicle) {
  
  this.save(vehicle);
 }
 
}
ehcache need a configuration file, ehcache.xml, which will in the classpath together spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 xsi:noNamespaceSchemaLocation="http://ehcache.org/ehcache.xsd"
 updateCheck="false">
 
 <!-- Default Cache Configuration, with name 'default' -->
 <defaultCache maxElementsInMemory="50" eternal="false" 
               overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />
 
 <cache name="vehicleCache" maxElementsInMemory="50" eternal="false" 
        overflowToDisk="false" memoryStoreEvictionPolicy="LFU" />

</ehcache>
In this configuration file we create the cache "vehicleCache", which will be used for our methods in VehicleDAO. Now, we show how would the spring-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xmlns:tx="http://www.springframework.org/schema/tx"
 xmlns:cache="http://www.springframework.org/schema/cache"
 xmlns:context="http://www.springframework.org/schema/context"
 xsi:schemaLocation="
    http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/cache 
    http://www.springframework.org/schema/cache/spring-cache.xsd
    http://www.springframework.org/schema/tx
    http://www.springframework.org/schema/tx/spring-tx.xsd
    http://www.springframework.org/schema/context
    http://www.springframework.org/schema/context/spring-context-3.0.xsd">
 
    <cache:annotation-driven />
    
    
    <bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
       <property name="dataSource" ref="dataSource" />
       <property name="packagesToScan" value="geekzpacho.examples.ehcache" />
       <property name="jpaVendorAdapter">
          <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
             <property name="showSql" value="false" />
             <property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect" />
          </bean>
       </property>
    </bean>
    
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
       <property name="driverClassName" value="com.mysql.jdbc.Driver" />
       <property name="url" value="jdbc:mysql://localhost:3306/geekzpacho" />
       <property name="username" value="root" />
       <property name="password" value="root" />
    </bean>
    
    <bean id="txManager" class="org.springframework.orm.jpa.JpaTransactionManager">
       <property name="entityManagerFactory" ref="entityManagerFactory" />
    </bean>
    <tx:annotation-driven transaction-manager="txManager" />
    
    
    <context:component-scan base-package="geekzpacho.examples.ehcache" />
    
    <bean id="cacheManager" class="org.springframework.cache.ehcache.EhCacheCacheManager">
        <property name="cacheManager" ref="ehcache" />
    </bean>
    
    <bean id="ehcache" class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
        <property name="configLocation" value="classpath:ehcache.xml" />
    </bean>
        
     <bean id="vehicleDAO" class="geekzpacho.examples.ehcache.VehicleDAO">
     </bean>
</beans>
Para comprobar la eficacia de ehcache y que todo sea correcto. Lanzamos en el Main.jav dos veces cada método dao (getAll y getVehicle), esperando que en la segunda llamada el tiempo de ejecución sea menor. Este es el resultado:
*** SELECT ALL ***
First call without cache: 319246710 ns
Vehicle [id=1, name=Car, description=Motor vehicle small or medium size, used for carrying people and can accommodate no more than nine seats.]
Vehicle [id=2, name=MotorBike, description=Two-wheeled motor vehicle with one or two saddles and sometimes with sidecar.]
Vehicle [id=3, name=Truck, description=Four or more vehicle wheels which is used to transport heavy loads.]
Second call with cache: 597881 ns
Vehicle [id=1, name=Car, description=Motor vehicle small or medium size, used for carrying people and can accommodate no more than nine seats.]
Vehicle [id=2, name=MotorBike, description=Two-wheeled motor vehicle with one or two saddles and sometimes with sidecar.]
Vehicle [id=3, name=Truck, description=Four or more vehicle wheels which is used to transport heavy loads.]
**************
*** SELECT BY ID ***
First call without cache: 57306107 ns
Vehicle [id=1, name=Car, description=Motor vehicle small or medium size, used for carrying people and can accommodate no more than nine seats.]
Second call with cache: 113113 ns
Vehicle [id=1, name=Car, description=Motor vehicle small or medium size, used for carrying people and can accommodate no more than nine seats.]
**************

  • Conclusions

Using ehcache in 533 getall method is faster in the second than in the first iteration. The same goes for getVehicle method. In conclusion, if you perform an analysis of static data tables that are accessed in greater numbers in our application we can cache the query methods to get better response time and our development faster.

2 comments:

  1. mola, podrias compartir el código en github o algún otro sitio?

    ReplyDelete
  2. El código está compartido en nuestro repositorio google code. En el punto "explanation" tienes la url.

    Gracias!

    ReplyDelete