Introduction to nhib.pdf second-level cache

Source: Internet
Author: User

 

My experience mainly comes from the hibernate2.1 version. The basic principles are the same as those in version 3.0 and 3.1. Please forgive me for being stubborn.

 

The hibernate session provides a level-1 cache. Each session loads the same id twice and does not send two SQL statements to the database. However, when the session is closed, the level-1 cache becomes invalid.

 

The second-level cache is a global cache at the SessionFactory level. Different cache class libraries, such as ehcache and oscache, can be used under it. You need to set hibernate. cache. provider_class. Here we use ehcache. In 2.1, It is hibernate. cache. provider_class = net. sf. hibernate. cache. if EhCacheProvider uses the query cache, add hibernate. cache. use_query_cache = true.

 

The cache can be simply regarded as a Map, and the value is searched in the cache through the key.

 

Class Cache

 

For a record, that is, a PO, It is found based on the ID. The cached key is ID, and the value is POJO. No matter list, load or iterate, as long as an object is read, the cache will be filled. However, the list does not use the cache, while the iterate will first obtain the database select id, and then the load with an id and an id. If there is in the cache, it will be retrieved from the cache, if not, load the database. For read/write cache, you must set the following parameters:

 

<Cache usage = "read-write"/>

 

If the level-2 Cache implementation you are using is ehcache, You need to configure ehcache. xml:

 

<Cache name = "com. xxx. pojo. Foo" maxElementsInMemory = "500"

 

Eternal = "false" timeToLiveSeconds = "7200"

 

TimeToIdleSeconds = "3600" overflowToDisk = "true"/>

 

Eternal indicates whether the cache never times out. timeToLiveSeconds indicates the timeout time of each element in the cache (here it is a POJO). If eternal = "false", it exceeds the specified time, this element is removed. TimeToIdleSeconds is a daze time and optional. When there are more than 500 put elements in the cache, if overflowToDisk = "true", part of the cached data is saved in a temporary file on the hard disk.

 

This configuration is required for each class to be cached. If you do not configure it, hibernate will warn you at startup, and then use the defaultCache configuration, so that multiple classes will share one configuration.

 

When an ID is modified through hibernate, hibernate will know that the cache is removed.

 

In this way, you may think that the same query condition, first list, second iterate, can be used to cache. In fact, this is very difficult, because you cannot determine when it is the first time, and the conditions for each query are usually different. If there are 100 records in the database, the id ranges from 1 to 100, in the first list, the first 50 IDs are displayed, and in the second iterate, the IDS 30 to 70 are queried. Then, the IDS 30 to 50 are obtained from the cache, from 51 to 70, 1 + 20 SQL statements are sent from the database. So I always think that iterate is useless and there will always be 1 + N problems.

 

(Remark: It is said that a large query uses a list to load the entire result set into the memory, which is very slow. iterate is better than a select id, but large queries always need to be checked by page, no one will install the entire result set. If there are 20 results on one page, iterate needs to execute 21 statements. Although list selects several fields, it is slower than the first select id Statement of iterate, however, there is only one statement. If hibernate does not load the entire result set, it will be optimized based on the database dialect. For example, if mysql limit is used, the overall list should be faster .)

 

If you want to cache the list or iterate query results, you need to use the query cache.

 

Query Cache

 

First, you must configure hibernate. cache. use_query_cache = true.

 

If ehcache is used, configure ehcache. xml. Note that hibernate3.0 is not the package name of net. sf in the future:

 

<Cache name = "net. sf. hibernate. cache. StandardQueryCache"
MaxElementsInMemory = "50" eternal = "false" timeToIdleSeconds = "3600"
TimeToLiveSeconds = "7200" overflowToDisk = "true"/>
<Cache name = "net. sf. hibernate. cache. UpdateTimestampsCache"
MaxElementsInMemory = "5000" eternal = "true" overflowToDisk = "true"/>

 

Then

 

Query. setCacheable (true); // activate the query cache.
Query. setCacheRegion ("myCacheRegion"); // specify the cacheRegion to be used. Optional

 

The second row specifies that the cacheRegion to be used is myCacheRegion, that is, you can configure each query cache separately and use setCacheRegion to specify this. You need to configure it in ehcache. xml:

 

<Cache name = "myCacheRegion" maxElementsInMemory = "10" eternal = "false"

 

TimeToIdleSeconds = "3600"

 

TimeToLiveSeconds = "7200" overflowToDisk = "true"/>

 

If the second row is omitted and cacheRegion is not set, the above-mentioned standard query cache configuration will be used, that is, net. sf. hibernate. cache. StandardQueryCache.

 

For the query cache, the cached key is an SQL statement generated based on hql, coupled with parameters and paging information (which can be seen through log output, but its output is not very readable, it is best to change its code ).

 

For example, hql:

 

From Cat c where c. name like?

 

Generate the following SQL statement:

 

Select * from cat c where c. name like?

 

If the parameter is "tiger %", the query cache key * is about * such a string (I wrote it based on memory and it is not accurate, but I should understand it after reading it ):

 

Select * from cat c where c. name like? , Parameter: tiger %

 

In this way, the same key is ensured under the same query and parameters.

 

Now let's talk about the cached value. For the list method, the value here is not the whole result set, but the queried ID. That is to say, whether the list method or the iterate method is used for the first query, the query methods are the same. The list executes an SQL statement and the iterate executes 1 + N statements, the extra behavior is that they fill the cache. However, when the second query with the same conditions is performed in the same way as iterate, the value is found in the cache based on the cached key, and the value is a string of IDs, load the data one by one in the class cache. This is done to save memory.

 

As you can see, the class cache of the related classes must be enabled for the query cache. When the list and iterate methods are executed for the first time, both the query cache and the class cache are filled.

 

Another important problem that is easily overlooked is that after the query cache is enabled, even the list method may encounter a problem of 1 + N! When the same conditions are listed for the first time, because the query cache cannot be found, no matter whether the class cache contains data, an SQL statement is always sent to the database to obtain all the data, and then fill in the query cache and class cache. However, the problem arises during the second execution. If your class cache timeout time is short, the class cache times out, but the query cache is still in progress, after the list method obtains the id string, it will load it to the database one by one! Therefore, the timeout time of the class cache must not be shorter than the timeout time set by the query cache! If you have set a daze time, make sure that the daze time of the class cache is later than the cache time of the query. There are other cases, such as the class cache being forced by the program evict. Please pay attention to this situation.

 

In addition, if the hql query contains the select clause, the value in the query cache is the entire result set.

 

# P #

 

When hibernate updates the database, how does it know which query caches to update?

 

Hibernate maintains the last update time of each table in one place, which is put in the cache configuration specified by net. sf. hibernate. cache. UpdateTimestampsCache above.

 

When updated through hibernate, hibernate will know which tables are affected by this update. Then it updates the last update time of these tables. Each cache has a generated time and the table queried by the cache. When hibernate queries whether a cache exists, if the cache exists, it also retrieves the cache generation time and the table queried by the cache, and then searches for the last update time of these tables. If a table is updated after the generation time, the cache is invalid.

 

It can be seen that as long as a table is updated, the query cache for this table becomes invalid, so the query cache hit rate may be relatively low.

 

Collection Cache

 

You need to set it in the hbm collection:

 

<Cache usage = "read-write"/>

 

If the class is Cat and the collection is children, configure it in ehcache.

 

<Cache name = "com. xxx. pojo. Cat. children"
MaxElementsInMemory = "20" eternal = "false" timeToIdleSeconds = "3600"

 

TimeToLiveSeconds = "7200"
OverflowToDisk = "true"/>

 

The cache of Collection is the same as the list cached in the previous query. It only keeps a string of IDS, but it does not expire because the table has been updated, A collection cache is invalid only when the elements in the collection are added or deleted.

 

In this case, if your collection is sorted by a field, when an element updates the field, the order in the collection cache is not updated.

 

Cache Policy

 

◆ Read-only (read-only): There is nothing to say.
◆ Read/write cache: the data that may be updated by the program.
◆ Nonstrict-read-write: data needs to be updated, but the two transactions are unlikely to update the same record, and the performance is better than the read/write cache.
◆ Transaction cache (transactional): the cache supports transactions. When an exception occurs, the cache can also be rolled back. It only supports the jta environment, which I have not studied yet.

 

The difference between the read/write cache and the non-strict read/write cache is that when the read/write cache updates the cache, it will replace the data in the cache with a lock. If other transactions retrieve the corresponding cached data, if the lock is found, you can directly query the database.

 

In the ehcache Implementation of hibernate2.1, if an exception occurs in some cached transactions that are locked, the cache will remain locked until 60 seconds later.

 

The data in the cache is not strictly read or written. Use the preconditions of level 2 cache.

 

Your hibernate program has exclusive write access to the database. If other processes update the database, it is impossible for hibernate to know.

 

You must directly use hibernate to operate the database. If you call the stored procedure or use jdbc to update the database, hibernate does not know. The batch update and deletion of hibernate3.0 do not update the level-2 cache, But it is said that 3.1 has solved this problem.

 

This restriction is quite tricky. Sometimes hibernate is slow in batch update and deletion, but you cannot write jdbc to optimize it yourself!

 

SessionFactory also provides methods to remove the cache. If you need to write JDBC, you can call these methods to remove the cache:

 

Void evict (Class persistentClass)
Evict all entries from the second-level cache.
Void evict (Class persistentClass, Serializable id)
Evict an entry from the second-level cache.
Void evictCollection (String roleName)
Evict all entries from the second-level cache.
Void evictCollection (String roleName, Serializable id)
Evict an entry from the second-level cache.
Void evictQueries ()
Evict any query result sets cached in the default query cache region.
Void evictQueries (String cacheRegion)
Evict any query result sets cached in the named query cache region.

 

However, I do not recommend this because it is difficult to maintain. For example, if you have updated a table in batches using JDBC, three query caches will use this table and evictQueries (String cacheRegion) will remove Three query caches, then, evict (Class persistentClass) is used to remove the class cache, which seems to be complete. However, when you add a query cache, you may forget to update the removal code here. If your jdbc code is everywhere, when you add a query cache, do you know where else to make the corresponding changes?

 

Summary

 

Don't take it for granted that the cache will certainly improve performance. This is the case only when you can control it and the conditions are appropriate. There are still many restrictions on the second-level cache of hibernate, And the inconvenience of using jdbc may greatly reduce the update performance. 1 + N problems may occur if you do not understand the principle. Improper use may also lead to dirty Data Reading.

 

If you can't stand the limitations of hibernate, You Can cache your own applications!

 

The higher the cache, the better the effect. It seems that even if the disk has a cache, the database still needs to implement its own cache. Even if the database has a cache, our applications still need to be cached. Because the underlying cache does not know what the top layer will do with the data, it can only do more common, while the top layer can implement the cache in a targeted manner, so it can cache at a higher level, better results!

 

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.