Friday, March 4, 2011

Configuring Multiple Databases in Hibernate

Introduction

Hibernate is designed to be used with a large set of databases. The details of those databases are configured in an XML file called hibernate.cfg.xml. This configuration files could be given any name and is usually placed in the root of your application class path. There are many configuration parameters available that makes the mapping of domain model to relational model easier. The same configurations can be done from your Java class uning org.hibernate.cfg.Configuration class. If you are beginner in Hibernate, please read our article on Introduction to Hibernate ORM Framework


Sample Application

The sample we discuss here shows how an Employee object can be configured to store in both Oracle Data base and Derby Database. Here we create a POJO class called Employee and store and retrieve its objects from both Oracle and Derby database.

Software Requirements

For this example I have used the following tools.
  • NetBeans IDE ( may use Eclipse also)
  • Hibernate 3.0
  • Oracle 9i , Derby

Sample Project Structure


Employee.java

package hibernatepack.samples;
        
public class Employee {
    private int empid;
    private String empname;
    private double salary;
    public int getEmpid() {
        return empid;
    }
    public void setEmpid(int empid) {
        this.empid = empid;
    }

    public String getEmpname() {
        return empname;
    }

    public void setEmpname(String empname) {
        this.empname = empname;
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }
}
The mapping details of the Employee class are available in the Employee.hbm.xml file:

<?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" 
     "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
  <hibernate-mapping>
    <class name="hibernatepack.samples.Employee" table="HBEmployeeDetails" >
    <id name= "empid" column="EmpNo" />
     <property name= "empname" column = "EmpName" />
    <property name="salary" column="Salary" />
   </class>
 </hibernate-mapping>  
Since we need to persist the Employee object both in Oracle and in Derby, we need to create 2 configuration files - one for Oracle, another one for Derby.
oracleconfig.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.OracleDialect</property>
<property name="hibernate.connection.driver_class">oracle.jdbc.OracleDriver</property>
<property name="hibernate.connection.url">jdbc:oracle:thin:@10.154.117.76:1521:oracle</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password">password</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<property name="hibernate.show_sql">true</property>
<mapping resource="Employee.hbm.xml" />
</session-factory>
</hibernate-configuration>
derbiconfig.cfg.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.DerbyDialect</property>
<property name="hibernate.connection.driver_class">org.apache.derby.jdbc.ClientDriver</property>
<property name="hibernate.connection.url">jdbc:derby://localhost:1527/HibernateDB</property>
<property name="hibernate.connection.username">user</property>
<property name="hibernate.connection.password">pwd</property>
<property name="hibernate.show_sql">true</property>
<property name="hibernate.hbm2ddl.auto">create</property>
<mapping resource="Employee.hbm.xml"/>
</session-factory>
</hibernate-configuration>
The IEmployeeDAO.java lists the operations on the Employee object.

package hibernatepack.samples;
import java.util.List;
public interface IEmployeeDAO {
     public void findAllEmployees();
    public void insertEmployee(Employee e);
       }
Let us Implement the above interface using a class :
EmloyeeDaoImpl.java

public class EmployeeDaoImpl implements IEmployeeDAO {
    SessionFactory sessionFactory1 = new  Configuration().configure("oracleconfig.cfg.xml").buildSessionFactory();
    SessionFactory sessionFactory2 = new Configuration().configure("derbyconfig.cfg.xml").buildSessionFactory();
    Session session = null;
    Transaction transaction = null;
    public void findAllEmployees() {
        ArrayList empList = new ArrayList();
               try {
            session = sessionFactory1.openSession();
            transaction = session.beginTransaction();
            transaction.begin();
            Criteria crit = session.createCriteria(Employee.class);
            empList = (ArrayList) crit.list();
             System.out.println("Records from Oracle Database");
            for (Employee emp : empList) {
                System.out.println(emp.getEmpid() + " " + emp.getEmpname() + " " + emp.getSalary());
                
            }
            session.close();
            session = sessionFactory2.openSession();
            Criteria crit1 = session.createCriteria(Employee.class);
            empList = (ArrayList) crit1.list();
            System.out.println("Records from Derby Database");
            for (Employee emp : empList) {
                System.out.println(emp.getEmpid() + " " + emp.getEmpname() + " " + emp.getSalary());
            }
            session.close();
        } catch (Exception he) {
            he.printStackTrace();
        }
    }
 public void insertEmployee(Employee e) {
        try {
            session = sessionFactory1.openSession();
            transaction = session.beginTransaction();
            transaction.begin();
            session.save(e);
            transaction.commit();
            session.close();
            session = sessionFactory2.openSession();
            transaction = session.beginTransaction();
            transaction.begin();
            session.save(e);
            transaction.commit();
            session.close();
        } catch (HibernateException he) {
            he.printStackTrace();
        }
    }
}

Creating Session Factory object in Hibernate

Each database has its own SessionFactory object.

SessionFactory sessionFactory1 = new  Configuration().configure("oracleconfig.cfg.xml").buildSessionFactory();
SessionFactory sessionFactory2 = new Configuration().configure("derbyconfig.cfg.xml").buildSessionFactory();
Specify the name of the configuration file as an argument to the configure() method when building the session factory object. Let us create the test application.

package hibernatepack.samples;

import java.awt.Choice;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
public class EmployeeTest {
    private static int choice;
    public static void main(String[] args) {
        EmployeeDaoImpl empOperations = new EmployeeDaoImpl();
        Employee e1 = new Employee();
        do {
            System.out.println("1. Insert ");
            System.out.println("2. List ");
            System.out.println("3. Exit ");
            System.out.println("Enter your choice ");
            Scanner sc = new Scanner(System.in);
            choice = sc.nextInt();
            switch (choice) {
                case 1:
                    System.out.println("Enter the employee Number ");
                    Scanner sc1 = new Scanner(System.in);
                    int empid = sc1.nextInt();
                    System.out.println("Enter the employee Name ");
                    Scanner sc2 = new Scanner(System.in);
                    String empname = sc2.nextLine();
                    System.out.println("Enter the Salary ");
                    Scanner sc3 = new Scanner(System.in);
                    double empsal = sc3.nextDouble();
                    e1.setEmpid(empid);
                    e1.setEmpname(empname);
                    e1.setSalary(empsal);
                    empOperations.insertEmployee(e1);
                    break;
                case 2:
                     empOperations.findAllEmployees();
                    break;
            }
        } while (choice != 3);
    }
}
When you execute the insert method, table named “HBEMPLOYEEDETAILS” is created both in Oracle and in Derby. Find below the sample output screen.



Conclusion

This is very simple example on how to configure the multiple databases using Hibernate configuration files. In the next weeks I will be writing few more examples on configuring the databases and fetching the data. In the following section you can find the interesting articles related to Hibernate framework.


Speed Up Your Hibernate Applications with Second-Level Caching

igh-volume database traffic is a frequent cause of performance problems in Web applications. Hibernate is a high-performance, object/relational persistence and query service, but it won't solve all your performance issues without a little help. In many cases, second-level caching can be just what Hibernate needs to realize its full performance-handling potential. This article examines Hibernate's caching functionalities and shows how you can use them to significantly boost application performance.

An Introduction to Caching

Caching is widely used for optimizing database applications. A cache is designed to reduce traffic between your application and the database by conserving data already loaded from the database. Database access is necessary only when retrieving data that is not currently available in the cache. The application may need to empty (invalidate) the cache from time to time if the database is updated or modified in some way, because it has no way of knowing whether the cache is up to date.

Hibernate Caching

Hibernate uses two different caches for objects: first-level cache and second-level cache. First-level cache is associated with the Session object, while second-level cache is associated with the Session Factory object. By default, Hibernate uses first-level cache on a per-transaction basis. Hibernate uses this cache mainly to reduce the number of SQL queries it needs to generate within a given transaction. For example, if an object is modified several times within the same transaction, Hibernate will generate only one SQL UPDATE statement at the end of the transaction, containing all the modifications. This article focuses on second-level cache. To reduce database traffic, second-level cache keeps loaded objects at the Session Factory level between transactions. These objects are available to the whole application, not just to the user running the query. This way, each time a query returns an object that is already loaded in the cache, one or more database transactions potentially are avoided. In addition, you can use a query-level cache if you need to cache actual query results, rather than just persistent objects.

Cache Implementations
Caches are complicated pieces of software, and the market offers quite a number of choices, both open source and commercial. Hibernate supports the following open-source cache implementations out-of-the-box:
  • EHCache (org.hibernate.cache.EhCacheProvider)
  • OSCache (org.hibernate.cache.OSCacheProvider)
  • SwarmCache (org.hibernate.cache.SwarmCacheProvider)
  • JBoss TreeCache (org.hibernate.cache.TreeCacheProvider)
Each cache provides different capacities in terms of performance, memory use, and configuration possibilities:
  • EHCache is a fast, lightweight, and easy-to-use in-process cache. It supports read-only and read/write caching, and memory- and disk-based caching. However, it does not support clustering.
  • OSCache is another open-source caching solution. It is part of a larger package, which also provides caching functionalities for JSP pages or arbitrary objects. It is a powerful and flexible package, which, like EHCache, supports read-only and read/write caching, and memory- and disk-based caching. It also provides basic support for clustering via either JavaGroups or JMS.
  • SwarmCache is a simple cluster-based caching solution based on JavaGroups. It supports read-only or nonstrict read/write caching (the next section explains this term). This type of cache is appropriate for applications that typically have many more read operations than write operations.
  • JBoss TreeCache is a powerful replicated (synchronous or asynchronous) and transactional cache. Use this solution if you really need a true transaction-capable caching architecture.
Another cache implementation worth mentioning is the commercial Tangosol Coherence cache.

Caching Strategies
Once you have chosen your cache implementation, you need to specify your access strategies. The following four caching strategies are available:
  • Read-only: This strategy is useful for data that is read frequently but never updated. This is by far the simplest and best-performing cache strategy.
  • Read/write: Read/write caches may be appropriate if your data needs to be updated. They carry more overhead than read-only caches. In non-JTA environments, each transaction should be completed when Session.close() or Session.disconnect() is called.
  • Nonstrict read/write: This strategy does not guarantee that two transactions won't simultaneously modify the same data. Therefore, it may be most appropriate for data that is read often but only occasionally modified.
  • Transactional: This is a fully transactional cache that may be used only in a JTA environment.
Support for these strategies is not identical for every cache implementation. Table 1 shows the options available for the different cache implementations.

Cache Read-only Nonstrict Read/write Read/write Transactional
EHCache Yes Yes Yes No
OSCache Yes Yes Yes No
SwarmCache Yes Yes No No
JBoss TreeCache Yes No No Yes
Table 1. Supported Caching Strategies for Hibernate Out-of-the-Box Cache Implementations
The remainder of the article demonstrates single-JVM caching using EHCache.

Cache Configuration

To activate second-level caching, you need to define the hibernate.cache.provider_class property in the hibernate.cfg.xml file as follows:

<hibernate-configuration>
 <session-factory>
  ...
  <property name="hibernate.cache.provider_class">
   org.hibernate.cache.EHCacheProvider
  </property>
  ...
 </session-factory>
</hibernate-configuration>


For testing purposes in Hibernate 3, you may also want to use the hibernate.cache.use_second_level_cache property, which allows you to activate (and deactivate) the second-level cache. By default, the second-level cache is activated and uses the EHCache provider.

A Practical Application

 
Figure 1. The Employee UML Class Diagram
The sample demo application for this article contains four simple tables: a list of countries, a list of airports, a list of employees, and a list of spoken languages. Each employee is assigned a country, and can speak many languages. Each country can have any number of airports. Figure 1 shows the UML class diagram for the application, and Figure 2 shows the database schema. The sample application source code contains the following SQL scripts, which you need in order to create and instantiate the corresponding database:
  • src/sql/create.sql: The SQL script used to create the database.
  • src/sql/init.sql: Test data

Note on Installing Maven 2
At the time of writing, the Maven 2 repository seemed to be missing some jars. To get around this problem, find the missing jars in the root directory of the application source code. To install them in the Maven 2 repository, go to the app directory and execute the following instructions:

$ mvn install:install-file -DgroupId=javax.security -DartifactId=jacc -Dversion=1.0 
    -Dpackaging=jar -Dfile=jacc-1.0.jar
$ mvn install:install-file -DgroupId=javax.transaction -DartifactId=jta -Dversion=1.0.1B 
    -Dpackaging=jar -Dfile=jta-1.0.1B.jar

 
Figure 2. The Database Schema

Setting Up a Read-Only Cache
To begin with something simple, here's the Hibernate mapping for the Country class:

<hibernate-mapping package="com.wakaleo.articles.caching.businessobjects">
    <class name="Country" table="COUNTRY" dynamic-update="true">
  <meta attribute="implement-equals">true</meta>    
   <cache usage="read-only"/>

        <id name="id" type="long" unsaved-value="null" >
            <column name="cn_id" not-null="true"/>
            <generator class="increment"/>
        </id>

    <property column="cn_code" name="code" type="string"/>
    <property column="cn_name" name="name" type="string"/>

   <set name="airports">
    <key column="cn_id"/>
    <one-to-many class="Airport"/>
   </set>
    </class>
</hibernate-mapping>
Suppose you need to display a list of all countries. You could implement this with a simple method in the CountryDAO class as follows:

public class CountryDAO {
 ... 
 public List getCountries() {
  return SessionManager.currentSession()
        .createQuery(
           "from Country as c order by c.name")
        .list();
 }
}
Because this method is likely to be called often, you need to see how it behaves under pressure. So write a simple unit test that simulates five successive calls:

 public void testGetCountries() {
  CountryDAO dao = new CountryDAO();
  for(int i = 1; i <= 5; i++) {
        Transaction tx = SessionManager.getSession().beginTransaction();
      TestTimer timer = new TestTimer("testGetCountries");
      List countries = dao.getCountries();
      tx.commit();
      SessionManager.closeSession();
      timer.done();
      assertNotNull(countries);
      assertEquals(countries.size(),229);
  }
 }
You can run this test from either your preferred IDE or the command line using Maven 2 (the demo application provides the Maven 2 project files). The demo application was tested using a local MySQL database. When you run this test, you should get something like the following:

$mvn test -Dtest=CountryDAOTest
...
testGetCountries: 521 ms.
testGetCountries: 357 ms.
testGetCountries: 249 ms.
testGetCountries: 257 ms.
testGetCountries: 355 ms.
[surefire] Running com.wakaleo.articles.caching.dao.CountryDAOTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 3,504 sec
So each call takes roughly a quarter of a second, which is a bit sluggish by most standards. The list of countries probably doesn't change very often, so this class would be a good candidate for a read-only cache. So add one.
You can activate second-level caching classes in one of the two following ways:
  1. You activate it on a class-by-class basis in the *.hbm.xml file, using the cache attribute:
    
    <hibernate-mapping package="com.wakaleo.articles.caching.businessobjects">
             <class name="Country" table="COUNTRY" dynamic-update="true">
      <meta attribute="implement-equals">true</meta>
      <cache usage="read-only"/>
                ...           
            </class>
        </hibernate-mapping>
  2. You can store all cache information in the hibernate.cfg.xml file, using the class-cache attribute:
    
    <hibernate-configuration>
     <session-factory>
      ...
      <property name="hibernate.cache.provider_class">
       org.hibernate.cache.EHCacheProvider
      </property>
      ...
      <class-cache 
    class="com.wakaleo.articles.caching.businessobjects.Country"
    usage="read-only"
      />
     </session-factory>
    </hibernate-configuration>
Next, you need to configure the cache rules for this class. These rules determine the nitty-gritty details of how the cache will behave. The examples in this demo use EHCache, but remember that each cache implementation is different.
EHCache needs a configuration file (generally called ehcache.xml) at the classpath root. The EHCache configuration file is well documented on the project Web site. Basically, you define rules for each class you want to store, as well as a defaultCache entry for use when you don't explicitly give any rules for a class.
For the first example, you can use the following simple EHCache configuration file:

<ehcache>

    <diskStore path="java.io.tmpdir"/>

    <defaultCache
        maxElementsInMemory="10000"
        eternal="false"
        timeToIdleSeconds="120"
        timeToLiveSeconds="120"
        overflowToDisk="true"
        diskPersistent="false"
        diskExpiryThreadIntervalSeconds="120"
        memoryStoreEvictionPolicy="LRU"
        />
        
    <cache name="com.wakaleo.articles.caching.businessobjects.Country"
        maxElementsInMemory="300"
        eternal="true"
        overflowToDisk="false"
        />

</ehcache>
This file basically sets up a memory-based cache for Countries with at most 300 elements (the country list contains 229 countries). Note that the cache never expires (the 'eternal=true' property).
Now, rerun the tests to see how the cache performs:

$mvn test -Dtest=CompanyDAOTest
...
testGetCountries: 412 ms.
testGetCountries: 98 ms.
testGetCountries: 92 ms.
testGetCountries: 82 ms.
testGetCountries: 93 ms.
[surefire] Running com.wakaleo.articles.caching.dao.CountryDAOTest
[surefire] Tests run: 1, Failures: 0, Errors: 0, Time elapsed: 2,823 sec
As you would expect, the first query is unchanged since the first time around you have to actually load the data. However, all subsequent queries are several times faster.

Behind the Scenes
Before moving on, it is useful to look at what's going on behind the scenes. One thing you should know is that the Hibernate cache does not store object instances. Instead, it stores objects in their "dehydrated" form (to use Hibernate terminology), that is, as a set of property values. The following is a sample of the contents of the Country cache:

{ 
  30  => [bw,Botswana,30], 
  214 => [uy,Uruguay,214], 
  158 => [pa,Panama,158],
  31  => [by,Belarus,31]
  95  => [in,India,95]
  ...
}
Notice how each ID is mapped to an array of property values. You may also have noticed that only the primitive properties are stored; there is no sign of the airports property. This is because the airports property is actually an association: a set of references to other persistent objects.
By default, Hibernate does not cache associations. It's up to you to decide which associations should be cached, and which associations should be reloaded whenever the cached object is retrieved from the second-level cache.
Association caching is a very powerful functionality. The next section takes a more detailed look at it.


Introduction to Hibernate Caching

1) Introduction

While working with Hibernate web applications we will face so many problems in its performance due to database traffic. That to when the database traffic is very heavy . Actually hibernate is well used just because of its high performance only. So some techniques are necessary to maintain its performance. Caching is the best technique to solve this problem. In this article we will discuss about, how we can improve the performance of Hibernate web applications using caching.
The performance of Hibernate web applications is improved using caching by optimizing the database applications. The cache actually stores the data already loaded from the database, so that the traffic between our application and the database will be reduced when the application want to access that data again. Maximum the application will works with the data in the cache only. Whenever some another data is needed, the database will be accessed. Because the time needed to access the database is more when compared with the time needed to access the cache. So obviously the access time and traffic will be reduced between the application and the database. Here the cache stores only the data related to current running application. In order to do that, the cache must be cleared time to time whenever the applications are changing. Here are the contents.
  • Introduction.
    • First-level cache.
    • Second-level cache.
  • Cache Implementations.
    • EHCache.
    • OSCache.
    • SwarmCache.
    • JBoss TreeCache.
  • Caching Stringategies.
    • Read-only.
    • Read-Write.
    • Nonstriict read-write.
    • Transactional.
  • Configuration.
  • <cache> element.
  • Caching the queries.
  • Custom Cache.
    • Configuration.
    • Implementation :: ExampleCustomCache.
  • Something about Caching.
    • Performance.
    • About Caching.
  • Conclusion.
Hibernate uses two different caches for objects: first-level cache and second-level cache..

1.1) First-level cache

First-level cache always Associates with the Session object. Hibernate uses this cache by default. Here, it processes one transaction after another one, means wont process one transaction many times. Mainly it reduces the number of SQL queries it needs to generate within a given transaction. That is instead of updating after every modification done in the transaction, it updates the transaction only at the end of the transaction.

1.2) Second-level cache

Second-level cache always associates with the Session Factory object. While running the transactions, in between it loads the objects at the Session Factory level, so that those objects will available to the entire application, don’t bounds to single user. Since the objects are already loaded in the cache, whenever an object is returned by the query, at that time no need to go for a database transaction. In this way the second level cache works. Here we can use query level cache also. Later we will discuss about it.

2) Cache Implementations

Hibernate supports four open-source cache implementations named EHCache (Easy Hibernate Cache), OSCache (Open Symphony Cache), Swarm Cache, and JBoss Tree Cache. Each cache has different performance, memory use, and configuration possibilities.

2.1) 2.1 EHCache (Easy Hibernate Cache) (org.hibernate.cache.EhCacheProvider)

  • It is fast.
  • lightweight.
  • Easy-to-use.
  • Supports read-only and read/write caching.
  • Supports memory-based and disk-based caching.
  • Does not support clustering.

2.2)OSCache (Open Symphony Cache) (org.hibernate.cache.OSCacheProvider)

  • It is a powerful .
  • flexible package
  • supports read-only and read/write caching.
  • Supports memory- based and disk-based caching.
  • Provides basic support for clustering via either JavaGroups or JMS.

2.3)SwarmCache (org.hibernate.cache.SwarmCacheProvider)

  • is a cluster-based caching.
  • supports read-only or nonstrict read/write caching .
  • appropriate for applications those have more read operations than write operations.

2.4)JBoss TreeCache (org.hibernate.cache.TreeCacheProvider)

  • is a powerful replicated and transactional cache.
  • useful when we need a true transaction-capable caching architecture .

3) Caching Stringategies

Important thing to remembered while studying this one is none of the cache providers support all of the cache concurrency strategies.

3.1) Read-only

  • Useful for data that is read frequently but never updated.
  • It is Simple .
  • Best performer among the all.
Advantage if this one is, It is safe for using in a cluster. Here is an example for using the read-only cache strategy.
      
<class name="abc.mutable " mutable="true ">
<cache usage="read-only"/>
....
</class> 

3.2) Read-Write

  • Used when our data needs to be updated.
  • It’s having more overhead than read-only caches.
  • When Session.close() or Session.disconnect() is called the transaction should be completed in an environment where JTA is no used.
  • It is never used if serializable transaction isolation level is required.
  • In a JTA environment, for obtaining the JTA TransactionManager we must specify the property hibernate.transaction.manager_lookup_class.
  • To use it in a cluster the cache implementation must support locking.
Here is an example for using the read-write cache stringategy.
      
<class name="abc.xyz" .... >
<cache usage="read-write"/>
….
<set name="yuv" ... >
<cache usage="read-write"/>
….
</set>
</class> 

3.3) Nonstrict read-write

  • Needed if the application needs to update data rarely.
  • we must specify hibernate.transaction.manager_lookup_class to use this in a JTA environment .
  • The transaction is completed when Session.close() or Session.disconnect() is called In other environments (except JTA) .
Here is an example for using the nonstrict read-write cache stringategy.
      
<class name="abc.xyz" .... >
<cache usage=" nonstringict-read-write"/>
….
</class> 

3.4) Transactional

  • It supports only transactional cache providers such as JBoss TreeCache.
  • only used in JTA environment

4) Configuration

For configuring cache the hibernate.cfg.xml file is used. A typical configuration file is shown below.
      
<hibernate-configuration>
 <session-factory>
  ...
  <property name="hibernate.cache.provider_class">
   org.hibernate.cache.EHCacheProvider
  </property>
  ...
 </session-factory>
</hibernate-configuration> 

The name in <property> tag must be hibernate.cache.provider_class for activating second-level cache. We can use hibernate.cache.use_second_level_cache property, which allows you to activate and deactivate the second-level cache. By default, the second-level cache is activated and uses the EHCache.

5) <cache> element

The <cache> element of a class has the following form:
      
<cache 
    usage=" caching stringategy"  
    region="RegionName"                                              
    include="all | non-lazy"/> 

  • usage (mandatory) specifies the caching stringategy: transactional, read-write, nonstringict-read-write or read-only.
  • region (optional) specifies the name of the second level cache region .
  • include (optional) non-lazy specifies that properties of the entity mapped with lazy="true" may not be cached when attribute-level lazy fetching is enabled.
The <cache> element of a class is also called as the collection mapping.

6) Caching the queries

Until now we saw only caching the transactions. Now we are going to study about the caching the queries.Suppose some queries are running frequently with same set of parameters, those queries can be cached. We have to set hibernate.cache.use_query_cache to true by calling Query.setCacheable(true) for enabling the query cache. Actually updates in the queries occur very often. So, for query caching, two cache regions are necessary.
  • For storing the results.( cache identifier values and results of value type only).
  • For storing the most recent updates.
Query cache always used second-level cache only. Queries wont cached by default. Here is an example implementation of query cache.
      
List xyz = abc.createQuery("Query")
    .setEntity("…",….)
    .setMaxResults(some integer)
    .setCacheable(true)
    .setCacheRegion("region name")
    .list(); 

We can cache the exact results of a query by setting the hibernate.cache.use_query_cache property in the hibernate.cfg.xml file to true as follows:
      
<property name="hibernate.cache.use_query_cache">true</property> 

Then, we can use the setCacheable() method on any query we wish to cache.

7) Custom Cache

To understand the relation between cache and the application the cache implementation must generate statistics of cache usage.

7.1) Custom Cache Configuration

In the hibernate.properties file set the property hibernate.cache.provider_class = examples.customCache.customCacheProvider.

7.2) Implementation :: ExampleCustomCache

Here is the implementation of ExampleCustomCache. Here it uses Hashtable for storing the cache statistics.
      
package examples.ExampleCustomCache;

import net.sf.hibernate.cache;
import java.util;
import org.apache.commons.logging;

public class ExampleCustomCache implements Cache
{
  public Log log = LogFactory.getLog(ExapleCustomCache.class);
  public Map table = new Hashtable(100);
int hits, misses, newhits, newmisses, locks, unlocks, remhits, remmisses, clears, destroys; 
  
  public void statCount(StringBuffer input, String string1, int value)
  {
    input.append(string1 + " " + value);
  }

  public String lStats()
  {
    StringBuffer res = new StringBuffer();

    statCount(res, "hits", hits);
    statCount(res, "misses", misses);
    statCount(res, "new hits", newhits);
    statCount(res, "new misses", newmisses);
    statCount(res, "locks", lock);
    statCount(res, "unlocks", unlock);
    statCount(res, "rem hits ", remhits);
    statCount(res, "rem misses", remmisses);
    statCount(res, "clear", clears);
    statCount(res, "destroy", destroys);

    return res.toString();
  }

  public Object get(Object key)
  {
    if (table.get(key) == null)
    {
      log.info("get " + key.toString () + " missed");
      misses++;
    } else
    {
      log.info("get " + key.toString () + " hit");
      hits++;
    }

    return table.get(key);
  }

  public void put(Object key, Object value)      
  {
    log.info("put " + key.toString ());
    if (table.containsKey(key))
    {
      newhits++;
    } else
    {
      newmisses++;
    }
    table.put(key, value);
  }

  public void remove(Object key)
  {
    log.info("remove " + key.toString ());
    if (table.containsKey(key))
    {
      remhits++;
    } else
    {
      remmisses++;
    }
    table.remove(key);
  }

  public void clear()
  {
    log.info("clear");
    clears++;
    table.clear();
  }

  public void destroy()
  {
    log.info("destringoy ");
    destroys++;
  }

  public void lock(Object key)
  {
    log.info("lock " + key.toStringing());
    locks++;
  }
  
  public void unlock(Object key)
  {
    log.info("unlock " + key.toStringing());
    unlocks++;
  }   

Here is the example of Custom Cache.
      
Package examples.ExapleCustomCache;

import java.util;
import net.sf.hibernate.cache;

public class ExampleCustomCacheProvider implements CacheProvider
{

  public Hashtable cacheList = new Hashtable();

  public Hashtable getCacheList()
  {
    return cacheList;
  }

  public Stringing cacheInfo ()
  {
    StringingBuffer aa = new StringingBuffer();
    Enumeration cList = cacheList.keys();

    while (cList.hasMoreElements())
    {
      Stringing cName = cList.nextElement().toStringing();
      aa.append(cName);
      
      ExapleCustomCache myCache = (ExapleCustomCache)cacheList.get(cName);

      aa.append(myCache.lStats());
    }

    return aa.toStringing();
  }

  public ExampleCustomCacheProvider()
  {
  }

  public Cache bCache(String string2, Properties properties)
  {
    ExampleCustomCache nC = new ExapleCustomCache();
    cacheList.put(string2, nC);
    return nC;
  } 

} 

8) Something about Caching

8.1) Performance

Hibernate provides some metrics for measuring the performance of caching, which are all described in the Statistics interface API, in three categories:
  • Metrics related to the general Session usage.
  • Metrics related to the entities, collections, queries, and cache as a whole.
  • Detailed metrics related to a particular entity, collection, query or cache region.

8.2) About Caching

  • All objects those are passed to methods save(), update() or saveOrUpdate() or those you get from load(), get(), list(), iterate() or scroll() will be saved into cache.
  • flush() is used to synchronize the object with database and evict() is used to delete it from cache.
  • contains() used to find whether the object belongs to the cache or not.
  • Session.clear() used to delete all objects from the cache .
  • Suppose the query wants to force a refresh of its query cache region, we should call Query.setCacheMode(CacheMode.REFRESH).

9) Conclusion

Caching is good one and hibernate found a good way to implement it for improving its performance in web applications especially when more database traffic occurs. If we implement it very correctly, we will get our applications to be running at their maximum capacities. I will cover more about the caching implementations in my coming articles. Try to get full coding guidelines before going to implement this.


StringBuilder vs StringBuffer vs String.concat - done right

StringBuilder vs StringBuffer vs String.concat - done right

illustration
How long is a piece of String?

Introduction

Concatenation of Strings is very easy in Java - all you need is a '+'. It can't get any easier than that, right? Unfortunately there are a few pitfalls. One thing you should remember from your first Java lessons is a small albeit important detail: String objects are immutable. Once constructed they cannot be changed anymore.
Whenever you "change" the value of a String you create a new object and make that variable reference this new object. Appending a String to another existing one is the same kind of deal: a new String containing the stuff from both is created and the old one is dropped.
You might wonder why Strings are immutable in first place. There are two very compelling reasons for it:
  1. Immutable basic types makes things easier. If you pass a String to a function you can be sure that its value won't change.
  2. Security. With mutable Strings one could bypass security checks by changing the value right after the check. (Same thing as the first point, really.)

The performance impact of String.concat()

Each time you append something via '+' (String.concat()) a new String is created, the old stuff is copied, the new stuff is appended, and the old String is thrown away. The bigger the String gets the longer it takes - there is more to copy and more garbage is produced.
Creating a String with a length of 65536 (character by character) already takes about 22 seconds on an AMD64 X2 4200+. The following diagram illustrates the exponentially growing amount of required time:
String.concat() - exponential growth
Figure 1: StringBuilder vs StringBuffer vs String.concat
StringBuilder and StringBuffer are also shown, but at this scale they are right onto the x-axis. As you can see String.concat() is slow. Amazingly slow in fact. It's so bad that the guys over at FindBugs added a detector for String.concat inside loops to their static code analysis tool.

When to use '+'

Using the '+' operator for concatenation isn't bad per se though. It's very readable and it doesn't necessarily affect performance. Let's take a look at the kind of situations where you should use '+'.
a) Multi-line Strings:
String text=
    "line 1\n"+
    "line 2\n"+
    "line 3";
Since Java doesn't feature a proper multi-line String construct like other languages, this kind of pattern is often used. If you really have to you can embed massive blocks of text this way and there are no downsides at all. The compiler creates a single String out of this mess and no concatenation happens at runtime.
b) Short messages and the like:
System.out.println("x:"+x+" y:"+y);
The compiler transforms this to:
System.out.println((new StringBuilder()).append("x:").append(x).append(" y:").append(y).toString());
Looks pretty silly, doesn't it? Well, it's great that you don't have to write that kind of code yourself. ;)
If you're interested in byte code generation: Accordingly to Arno Unkrig (the amazing dude behind Janino) the optimal strategy is to use String.concat() for 2 or 3 operands, and StringBuilder for 4 or more operands (if available - otherwise StringBuffer). Sun's compiler always uses StringBuilder/StringBuffer though. Well, the difference is pretty negligible.

When to use StringBuilder and StringBuffer

This one is easy to remember: use 'em whenever you assembe a String in a loop. If it's a short piece of example code, a test program, or something completely unimportant you won't necessarily need that though. Just keep in mind that '+' isn't always a good idea.

StringBuilder and StringBuffer compared

StringBuilder is rather new - it was introduced with 1.5. Unlike StringBuffer it isn't synchronized, which makes it a tad faster:
StringBuilder compared with StringBuffer
Figure 2: StringBuilder vs StringBuffer
As you can see the graphs are sort of straight with a few bumps here and there caused by re-allocation. Also StringBuilder is indeed quite a bit faster. Use that one if you can.

Initial capacity

Both - StringBuilder and StringBuffer - allow you to specify the initial capacity in the constructor. Of course this was also a thing I had to experiment with. Creating a 0.5mb String 50 times with different initial capacities:
different initial capacities compared
Figure 3: StringBuilder and StringBuffer with different initial capacities
The step size was 8 and the default capacity is 16. So, the default is the third dot. 16 chars is pretty small and as you can see it's a very sensible default value.
If you take a closer look you can also see that there is some kind of rhythm: the best initial capacities (local optimum) are always a power of two. And the worst results are always just before the next power of two. The perfect results are of course achieved if the required size is used from the very beginning (shown as dashed lines in the diagram) and no resizing happens at all.

Some insight

That "PoT beat" is of course specific to Sun's implementations of StringBuilder and StringBuffer. Other implementations may show a slightly different behavior. However, if these particular implementations are taken as target one can derive two golden rules from these results:
  1. If you set the capacity use a power of two value.
  2. Do not use the String/CharSequence constructors ever. They set the capacity to the length of the given String/CharSequence + 16, which can be virtually anything.

Benchmarking method

In order to get meaningful results I took care of a few things:
  • VM warmup
  • separate runs for each test
  • each sample is the median of 5 runs
  • inner loops were inside of each bench unit