1. What is caching?
Database caching refers to data between applications and physical data sources. That is to copy the data from the physical data source to the cache. With caching, applications can reduce the frequency of access to physical data sources, thereby improving efficiency. Cached media are usually memory or hard disk.
Hibernate has three types of caches: first-level caches, second-level caches and query caches.
2. Level 1 cache
The first level cache, Session cache, is managed automatically by Session without the need for program intervention. The first level cache is loaded and cached according to the ID of the object. The following code:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); }
Operation results:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:Computer Principle
Name:Computer Principle
The first query generates the SQL statement, and puts the queried object in the first level cache. The second query finds the object directly in the first level cache, so there is no need to generate the SQL statement again.
Look at another example:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); session = sessionFactory.openSession(); tx = session.beginTransaction(); c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); }
Since the first level cache is the Session level cache, the first level cache does not exist after the Session is closed, and the second query also generates SQL statements:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:Computer Principle
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:Computer Principle
3. Level 2 cache
The second level cache, SessionFactory cache, is similar to the first level cache. It also loads and caches according to the ID of the object. The difference is that the first level cache is only valid in SessionFactory, while the second level cache is valid in SessionFactory. When accessing an ID object, first go to the first level cache to find, if not to find the second level cache to find. Secondary cache includes EHCache, OSCache, Swarm Cache and JBoss Cache. Here we take EHCache as an example.
Secondary caching requires program management. First, configure Maven to download the relevant Jar and add it to the pom file:
<dependency> <groupId>org.hibernate</groupId> <artifactId>hibernate-ehcache</artifactId> <version>4.1.0.Final</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache</artifactId> <version>2.8.3</version> </dependency>
Create the EHCache configuration file ehcache.xml:
<ehcache> <diskStore path="E:\Eclipse\MyWorkspace\Cache"/> <defaultCache maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="120" timeToLiveSeconds="120" overflowToDisk="true" /> <cache name="com.hzhi.course.entity.Course" maxElementsInMemory="10000" eternal="true" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> </ehcache>
defaultCache is the default setting. The following cache specifies which class to cache. It sets the maximum number of cached objects, whether permanently valid, the maximum number of idle seconds, the maximum number of surviving seconds, whether to write to the hard disk when the memory is full, the path to the hard disk, and so on.
Modify the hbm file of the class that needs to be cached:
<class name="com.hzhi.course.entity.Course" table="clas"> <cache usage="read-only"/> ...... </class>
usage sets concurrent access policy, which is generally set to read-only.
Modify the configuration of SessionFactory in applicationContext.xml to add some properties of the secondary cache:
<!-- SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="dataSource" > <ref local="dataSource"/> </property> <!-- To configure Hibernate Attribute --> <property name="hibernateProperties"> <props> <prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop> <prop key="hibernate.show_sql">true</prop> <prop key="hibernate.format_sql">true</prop> <prop key="hibernate.connection.isolation">8</prop> <!-- Two level cache --> <prop key="hibernate.cache.use_second_level_cache">false</prop> <prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop> <prop key="hibernate.cache.provider_configuration_file_resource_path">WEB-INF/ehcache.xml</prop> </props> </property>
......
</bean>
Run the following example:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Course c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); session = sessionFactory.openSession(); tx = session.beginTransaction(); c = (Course) session.get(Course.class, 1); System.out.println("Name:" + c.getName()); tx.commit(); session.close(); }
Result:
Hibernate:
select
course0_.ID as ID0_0_,
course0_.NAME as NAME0_0_,
course0_.COMMENT as COMMENT0_0_
from
clas course0_
where
course0_.ID=?
Name:Computer Principle
Name:Computer Principle
Although Session is turned off, the secondary cache still exists, so only one SQL statement is generated.
The following example:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("from Course"); Iterator iter = query.iterate(); while(iter.hasNext()){ System.out.println(((Course)iter.next()).getName()); } tx.commit(); session.close(); session = sessionFactory.openSession(); tx = session.beginTransaction(); query = session.createQuery("from Course"); iter = query.iterate(); while(iter.hasNext()){ System.out.println(((Course)iter.next()).getName()); } tx.commit(); session.close(); }
Result:
Hibernate: select course0_.ID as col_0_0_ from clas course0_ Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //Computer Principle Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //computer network Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //Principle of database Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? C language Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //College English A Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Java Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Linux Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //Advanced mathematics Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //Chinese Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //College Physics Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //software engineering Hibernate: select course0_.ID as col_0_0_ from clas course0_ //Computer Principle //computer network //Principle of database C language //College English A Java Linux //Advanced mathematics //Chinese //College Physics //software engineering
It can be seen that the first generated SQL statement caches the ID of each object and generates an SQL statement query based on each ID when attribute values are needed. In the second Session, we first generate an SQL statement, get the ID, and then look up the object according to the ID. Because the second level cache is opened and the object is found in the second level cache, we output it directly, and do not generate the SQL statement according to each ID.
Whether it is a first-level cache or a second-level cache, only objects can be cached, and the values of attributes can not be cached. The following example:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.name from Course c"); List<String> names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); query = session.createQuery("select c.name from Course c"); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); tx.commit(); session.close(); }
Operation results:
Hibernate: select course0_.NAME as col_0_0_ from clas course0_ Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ---------- Hibernate: select course0_.NAME as col_0_0_ from clas course0_ Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ----------
Although the second level cache is opened, the result of the query is not an object, but an attribute, so there is no cache. The second query still generates a query statement. To solve this problem, you need to query the cache.
3. Cache query
On the basis of configuring the secondary cache, you can set up the query cache and add a line to the settings of the Session Factory:
<prop key="hibernate.cache.use_query_cache">true</prop>
That is, the query cache is opened. The query cache is also a Session Factory level cache, which is valid throughout the Session Factory.
Close the secondary cache, run the following example, add setCacheable(true) after Query to open the query cache:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("select c.name from Course c"); query.setCacheable(true); List<String> names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); query = session.createQuery("select c.name from Course c"); query.setCacheable(true); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------"); tx.commit(); session.close(); }
Result:
Hibernate: select course0_.NAME as col_0_0_ from clas course0_ Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ---------- Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ----------
Because the HQL statements of the two queries are identical, only one SQL statement is generated. But if you change the second query:
System.out.println("----------"); query = session.createQuery("select c.name from Course c where c.id > 5"); query.setCacheable(true); names = query.list(); for(Iterator iter = names.iterator(); iter.hasNext();){ String name = (String) iter.next(); System.out.println(name); } System.out.println("----------");
Result:
Hibernate: select course0_.NAME as col_0_0_ from clas course0_ Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ---------- Hibernate: select course0_.NAME as col_0_0_ from clas course0_ where course0_.ID>5 College English A Java Linux Advanced mathematics Chinese College Physics software engineering ----------
Because the HQL statement has changed, the second time the SQL statement has been generated.
Query caching can either cache attributes or objects. When caching objects, only the ID of the objects is cached. The following example:
@Override public void testCache() { // TODO Auto-generated method stub Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); Query query = session.createQuery("from Course"); query.setCacheable(true); List<Course> list = query.list(); for (int i=0; i<list.size(); i++){ System.out.println(list.get(i).getName()); } System.out.println("----------"); tx.commit(); session.close(); session = sessionFactory.openSession(); tx = session.beginTransaction(); query = session.createQuery("from Course"); query.setCacheable(true); list = query.list(); for (int i=0; i<list.size(); i++){ System.out.println(list.get(i).getName()); } System.out.println("----------"); tx.commit(); session.close(); }
Results:
Hibernate: select course0_.ID as ID0_, course0_.NAME as NAME0_, course0_.COMMENT as COMMENT0_ from clas course0_ //Computer Principle //computer network //Principle of database C language //College English A Java Linux //Advanced mathematics //Chinese //College Physics //software engineering ---------- Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? Hibernate: select course0_.ID as ID0_0_, course0_.NAME as NAME0_0_, course0_.COMMENT as COMMENT0_0_ from clas course0_ where course0_.ID=? //Computer Principle //computer network //Principle of database C language //College English A Java Linux //Advanced mathematics //Chinese //College Physics //software engineering ----------
Because the query cache is opened and the second level cache is not opened, the object ID is only cached in the first Session, and the whole object is not cached. So the HQL "from Course" in the second Session does not generate the SQL statement because it is the same as the previous one, but because there is no second level cache, the whole object is not cached, so the SQL statement can only be generated once according to each ID. If both the query cache and the secondary cache are opened at the same time, the second Session will no longer need to generate the SQL statement according to the ID:
Hibernate: select course0_.ID as ID0_, course0_.NAME as NAME0_, course0_.COMMENT as COMMENT0_ from clas course0_ Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ---------- Computer Principle computer network Principle of database C language College English A Java Linux Advanced mathematics Chinese College Physics software engineering ----------