在学习Hibernate的Cahce时,有两个概念要区分清楚:一个是Cache的有效范围,另一个是Cache并发时使用的策略。
没有Cache的情况下,我们直接从数据库中读取数据。如果存在Cache,在Cache中存有target数据的情况下,我们可以从Cache中获取数据,在没有target数据的情况下,才会向数据库读取数据。
在多线程访问数据库的时候,会多个transaction并发的问题,因此有不同级别的transaction isolation level。
在多线程访问Cache的时候,也会存在并发的问题,因此会有Cache并发时使用的策略。
首先,介绍一些背景知识,包括different caching与identity scope的关系、caching对transaction的影响,这适用于caching in general。接着,会介绍Hibernte的caching system,以及如何开启、管理一级缓存和二级缓存。
We start our exploration of caching with some background information. This includes an explanation of the different caching and identity scopes and the impact of caching on transaction isolation. This information and these rules can be applied to caching in general; they aren’t only valid for Hibernate applications. This discussion gives you the background to understand why the Hibernate caching system is like it is. We’ll then introduce the Hibernate caching system and show you how to enable, tune, and manage the first- and second-level Hibernate cache. We recommend that you carefully study the fundamentals laid out in this section before you start using the cache. Without the basics, you might quickly run into hard-to-debug concurrency problems and risk the integrity of your data.
1、缓存的背景知识
cache是对当前数据库状态的一种表现,它是对数据库中数据的一份copy。cache位于you application和database之间。
A cache keeps a representation of current database state close to the application, either in memory or on disk of the application server machine. The cache is a local copy of the data. The cache sits between your application and the database. The cache may be used to avoid a database hit whenever
■ The application performs a lookup by identifier (primary key)
■ The persistence layer resolves an association lazily
虽然能够对查询的结果进行缓存,但效果甚微,不会经常使用到。
It’s also possible to cache the results of queries. But the performance gain of caching query results is minimal in most cases, so this functionality is used much less often.
在我们学习Hibernate cache如何工作之前,让我们来看一下different caching options以及它们如何与identity和concurrency相关联的。
Before we look at how Hibernate’s cache works, let’s walk through the different caching options and see how they’re related to identity and concurrency.
1.1、Cache的Strategy和Scope
Caching strategies and scopes
注意:这里讲的是Cache的Strategy,而不是Cache concurrency的Strategry。每一个Cache Strategy都有自己的影响范围(scope)。
Caching是一个重要的概念,在去了解其它方面之前,我们首先需要知道cache有哪些strategy,主要有三种类型。
Caching is such a fundamental concept in object/relational persistence that you can’t understand the performance, scalability, or transactional semantics of an ORM implementation without first knowing what kind of caching strategy (or strategies) it uses. There are three main types of cache:
■ Transaction scope—Attached to the current unit of work, which may be an actual database transaction or an application transaction. It’s valid and used as long as the unit of work runs. Every unit of work has its own cache.
■ Process scope—Shared among many (possibly concurrent) units of work or transactions. This means that data in the process scope cache is accessed by concurrently running transactions, obviously with implications on transaction isolation. A process scope cache might store the persistent instances themselves in the cache, or it might store just their persistent state in a disassembled format.
■ Cluster scope—Shared among multiple processes on the same machine or among multiple machines in a cluster. It requires some kind of remote process communication to maintain consistency. Caching information has to be replicated to all nodes in the cluster. For many (not all) applications, cluster scope caching is of dubious value, since reading and updating the cache might be only marginally faster than going straight to the database.
持久层可以提供多个层次的caching。transaction scope-->process scope-->database
Persistence layers might provide multiple levels of caching. For example, a cache miss (a cache lookup for an item that isn’t contained in the cache) at the transaction scope might be followed by a lookup at the process scope. A database request would be the last resort.
持久层使用的cache会影响object identity的范围。这里要注意分清两个概念object identity和database identity。假设有A、B两个对象,object identity表示A==B,而database identity表示A.getId()==B.getId()。
The type of cache used by a persistence layer affects the scope of object identity (the relationship between Java object identity and database identity).
1.2、Cache和object identity
Caching and object identity
先来考虑transaction scope cache,这里的transaction可以是database transaction,也可以是application transaction。transaction scope cache实现了identity处理:两次查询同一个database identifier返回同一个java instance。
Consider a transaction scope cache. It seems natural that this cache is also used as the identity scope of persistent objects. This means the transaction scope cache implements identity handling: two lookups for objects using the same database identifier return the same actual Java instance in a particular unit of work. A transaction scope cache is therefore ideal if a persistence mechanism also provides transaction-scoped object identity.
process scope cache有两种实现方式。第一种实现方式是process scope cache中存储的是persistent instance,这种情况下,object identity和database identity是一致的,也就是说对于同一个database identity,只有一个persistent instance。第二种方式,process cache中存储的是数据的元组(tuples of data),元组中存储的是persistent state,每一个unit of work只是返回its own copy of the state(a tuple),并将这些tuple组装成一个新的persistent instance。
Persistence mechanisms with a process scope cache might choose to implement process-scoped identity. In this case, object identity is equivalent to database identity for the whole process. Two lookups using the same database identifier in two concurrently running units of work result in the same Java instance. Alternatively, objects retrieved from the process scope cache might be returned by value. The cache contains tuples of data, not persistent instances. In this case, each unit of work retrieves its own copy of the state (a tuple) and constructs its own persistent instance. The scope of the cache and the scope of object identity are no longer the same.
这里讲cluster scope cache。
A cluster scope cache always requires remote communication, and in the case of POJO-oriented persistence solutions like Hibernate, objects are always passed remotely by value. A cluster scope cache can’t guarantee identity across a cluster. You have to choose between transaction- or process-scoped object identity.
对于典型的web或企业级应用来说,将object identity的范围限定在a single unit of work中是一种方便的做法。换句话说,在两个并发的线程中,不必有identical object。
For typical web or enterprise application architectures, it’s most convenient that the scope of object identity be limited to a single unit of work. In other words, it’s neither necessary nor desirable to have identical objects in two concurrent threads.
上面刚刚谈到,在process scope范围内的identity是不必要的,真正副面影响是需要同步cache中的persistance instance,这就很容易造成deadlocks。
The real downside to process-scoped identity is the need to synchronize access to persistent instances in the cache, resulting in a high likelihood of deadlocks.
1.3、缓存和并发
Caching and concurrency
如一个ORM允许多个线程访问同一个persistent instance,它必定要提供一些object-level的锁来确保并发访问的同步。通常情况下,object-level的锁是通过read和write lock来实现,并要检测deadlock的发生。对于Hibernate而言,它为每一个线程(或者说transaction-scope identity)维护一组persistent instance,尽量避免并发的问题。
Any ORM implementation that allows multiple units of work to share the same persistent instances must provide some form of object-level locking to ensure synchronization of concurrent access. Usually this is implemented using read and write locks (held in memory) together with deadlock detection. Implementations like Hibernate, which maintain a distinct set of instances for each unit of work (transaction-scoped identity), avoid these issues to a great extent.
我们的观点认为,应该尽量避免在内存当中使用“锁”,也就是尽量避免处理多线程并发的问题。对于web或enterprise应用来说,多用户的扩展性是一个需要考虑的问题。
It’s our opinion that locks held in memory are to be avoided, at least for web and enterprise applications where multiuser scalability is an overriding concern. In these applications, it’s usually not required to compare object identity across concurrent units of work; each user should be completely isolated from other users.
如果要使用transaction scope object identity,就建议使用transaction scope cache,因为transaction scope cache是多用户高并发系统的最佳策略。first-level cache是mandatory(必须的),因为它确保了transaction scope范围内的identical objects。然而,这并不是唯一可以使用的cache。对于一些数据而言,second level cache(process或cluster范围内的cache)是非常有用的。second level cache返回data by value,这句话的言外之意是,first level cache返回data by reference。
Let’s consider the options again. A transaction scope cache is preferred if you also use transaction-scoped object identity and is the best strategy for highly concurrent multiuser systems. This first-level cache would be mandatory, because it also guarantees identical objects. However, this isn’t the only cache you can use. For some data, a second-level cache scoped to the process (or cluster) that returns data by value can be useful. This scenario therefore has two cache layers; you’ll later see that Hibernate uses this approach.
接下来,让我们讨论一下,second-level cache当中应该存储什么样的数据呢?什么时候应该开启second-level cache?
Let’s discuss which data benefits from second-level caching—or, in other words, when to turn on the process (or cluster) scope second-level cache in addition to the mandatory first-level transaction scope cache.
1.4、Cache和transaction isolation
Caching and transaction isolation
process或cluster范围的cache可以在不同的transaction之间共享数据。但这对于transaction isolation有一些负面影响。
A process or cluster scope cache makes data retrieved from the database in one unit of work visible to another unit of work. This may have some very nasty side-effects upon transaction isolation.
首先,如果一个application没有exclusive access访问数据库的权限,process scope caching就不应该使用,除非这些数据很少发生变化,同时通过cache expiry来进行数据的refresh。这种类型的数据常常发生在content management类型的应用中,但却很少出现在financial的application中。
First, if an application has non-exclusive access to the database, process scope caching shouldn’t be used, except for data which changes rarely and may be safely refreshed by a cache expiry. This type of data occurs frequently in content management-type applications but rarely in financial applications.
任何扩展性的application都需要支持cluster operation。对一个process scope cache,它并不会对不同machine上cache进行同步。这种情况下,我们应该选择cluster scope cache,而不应该使用process scope cache。
Any application that is designed to scale must support clustered operation. A process scope cache doesn’t maintain consistency between the different caches on different machines in the cluster. In this case, you should use a cluster scope (distributed) cache instead of the process scope cache.
许多Java application与遗留的application共用一个数据库。在这种情况下,我们应该只使用transaction scope cache,而不应该使用其它类型的cache。因为a cache system不会知道legacy application什么时候能够更新shared data。虽然这种功能可以实现,但Hibernate并提供支持。
Many Java applications share access to their database with other (legacy) applications. In this case, you shouldn’t use any kind of cache beyond a transaction scope cache. There is no way for a cache system to know when the legacy application updated the shared data. Actually, it’s possible to implement application-level functionality to trigger an invalidation of the process (or cluster) scope cache when changes are made to the database, but we don’t know of any standard or best way to achieve this. Certainly, it will never be a built-in feature of Hibernate. If you implement such a solution, you’ll most likely be on your own, because it’s extremely specific to the environment and products used.
考虑了对数据库访问没有独享的权限,我们应该建立什么样的isolation level呢?并不是每一种cache类型都支持所有的transaction isolation levels。
After considering non-exclusive data access, you should establish what isolation level is required for the application data. Not every cache implementation respects all transaction isolation levels, and it’s critical to find out what is required. Let’s look at data that benefits most from a process (or cluster) scoped cache.
一个完整的ORM解决方案应该让我们能够为单独的class提供second-level cache。这些class应该有这些特征
A full ORM solution will let you configure second-level caching separately for each class. Good candidate classes for caching are classes that represent
■ Data that changes rarely
■ Non-critical data (for example, content-management data)
■ Data that is local to the application and not shared
不适合进行seoncd-level caching的数据
Bad candidates for second-level caching are
■ Data that is updated often
■ Financial data
■ Data that is shared with a legacy application
我们描述一个a dual layer caching system景象:a transaction scope first-level和an optional second-level process or cluster scope cache。这与Hibernate caching system很相近。
We’ve shaped a picture of a dual layer caching system in the previous sections, with a transaction scope first-level and an optional second-level process or cluster scope cache. This is close to the Hibernate caching system.
2、Hibernate的缓存架构
The Hibernate cache architecture
Hibernate有一个two-level cache architecture。
As we said earlier, Hibernate has a two-level cache architecture. The various elements of this system can be seen in the figure.
对于Hibernate来说,first-level cache是Session。一个session的生命可以跨越database transaction或application transaction。first-level cache是mandatory的,是不能关闭的。
The first-level cache is the Session itself. A session lifespan corresponds to either a database transaction or an application transaction. We consider the cache associated with the Session to be a transaction scope cache. The first-level cache is mandatory and can’t be turned off; it also guarantees object identity inside a transaction.
Hibernate的second-level cache是pluggable的。second-level cache的范围可以是process scope或者是cluster scope。在second level cache中,存储的不是persistent instances,而是persistent state(returned by value)。cache的并发策略,也为特定的数据定义了transaction isolation,其中cache provider代表了实际的cache实现。是否使用second-level cache,这是可以选择的,它存储的可以是per-class,也可以是per-association。
The second-level cache in Hibernate is pluggable and might be scoped to the process or cluster. This is a cache of state (returned by value), not of persistent instances. A cache concurrency strategy defines the transaction isolation details for a particular item of data, whereas the cache provider represents the physical, actual cache implementation. Use of the second-level cache is optional and can be configured on a per-class and per-association basis.
Hibernate也可以实现query result的cache,这属于second-level cache,是一个可选的feature。
Hibernate also implements a cache for query result sets that integrates closely with the second-level cache. This is an optional feature.
首先,我们来讨论first-level cache,也称为session cache。
Let’s start with using the first-level cache, also called the session cache.
2.1、使用first-level cache
Using the first-level cache
The session cache ensures that when the application requests the same persistent object twice in a particular session, it gets back the same (identical) Java instance. This sometimes helps avoid unnecessary database traffic. More important, it ensures the following:
■ The persistence layer isn’t vulnerable to stack overflows in the case of circular references in a graph of objects.
■ There can never be conflicting representations of the same database row at the end of a database transaction. There is at most a single object representing any database row. All changes made to that object may be safely written to the database (flushed).
■ Changes made in a particular unit of work are always immediately visible to all other code executed inside that unit of work.
You don’t have to do anything special to enable the session cache. It’s always on and, for the reasons shown, can’t be turned off.
Hibernate的first-level cache与Session API的关系:save, update, saveOrUpdate,load, find,list, iterate, filter。
Whenever you pass an object to save(), update(), or saveOrUpdate(), and whenever you retrieve an object using load(), find(), list(), iterate(), or filter(), that object is added to the session cache. When flush() is subsequently called, the state of that object will be synchronized with the database.
If you don’t want this synchronization to occur, or if you’re processing a huge number of objects and need to manage memory efficiently, you can use the evict() method of the Session to remove the object and its collections from the first-level cache. There are several scenarios where this can be useful.
To completely evict all objects from the session cache, call Session.clear(). We aren’t trying to convince you that evicting objects from the first-level cache is a bad thing in general, but that good use cases are rare.
2.2、Hibernate的second-level cache
The Hibernate second-level cache
Hibernate的second-level cache可以是process scope,也可以是cluster scope。所有的session都共享同一个second-level cache。second-level cache实际上和SessionFactory的范围一样(不太理解这句话)。
The Hibernate second-level cache has process or cluster scope; all sessions share the same second-level cache. The second-level cache actually has the scope of a SessionFactory.
在second-level cache当中,存储的并不是persistent instance,而是以desassembled form的形式存在。disassembly可以类比于serialization,但disassembly效率比较高。
Persistent instances are stored in the second-level cache in a disassembled form. Think of disassembly as a process a bit like serialization (the algorithm is much, much faster than Java serialization, however).
对于process scope或者是cluster scope范围的cache,我们并不关心它们是怎么实现的。但更重要的是,正确使用cache的policy。
The internal implementation of this process/cluster scope cache isn’t of much interest; more important is the correct usage of the cache policies—that is, caching strategies and physical cache providers.
不同类型的data需要不同cache policy:读操作和写操作的比率是变化的、数据库表的数量是变化的、有些数据表要在多个应用之间共享。由于存在变数,因此second-level cache是可以配置来适应这种变化,它配置的对象可以是an individual class,也可以是collection。例如,我们可以将“参考的数据”加入到cache当中,也可以禁用代表financial records的class。
Different kinds of data require different cache policies: the ratio of reads to writes varies, the size of the database tables varies, and some tables are shared with other external applications. So the second-level cache is configurable at the granularity of an individual class or collection role. This lets you, for example, enable the second-level cache for reference data classes and disable it for classes that represent financial records.
cache policy包含以下设置
The cache policy involves setting the following:
■ Whether the second-level cache is enabled (是否开启second-level cache)
■ The Hibernate concurrency strategy(second-level cache的并发strategy)
■ The cache expiration policies (such as timeout, LRU, memory-sensitive)(second-level cache的expiration policy)
■ The physical format of the cache (memory, indexed files, cluster-replicated)(second-level cache的物理存储形式:内存、磁盘文件)
在这里我们在讨论cache,但并不代表所有class都适合cache,因此能够禁用second-level cache也是非常重要的。再重申一次,cache只是适用于read-mostly classes。如果有更多的update操作,就不应该开启second-level cache。
Not all classes benefit from caching, so it’s extremely important to be able to disable the second-level cache. To repeat, the cache is usually useful only for read-mostly classes. If you have data that is updated more often than it’s read, don’t enable the second-level cache, even if all other conditions for caching are true! Furthermore, the second-level cache can be dangerous in systems that share the database with other writing applications. As we explained in earlier sections, you must exercise careful judgment here.
要使用Hibernate的second-level cache需要注意两方面:第一,应该使用哪一种concurrency strategy,第二,使用cache provider来配置cache expiration和physical cache attributes。
The Hibernate second-level cache is set up in two steps. First, you have to decide which concurrency strategy to use. After that, you configure cache expiration and physical cache attributes using the cache provider.
2.2.1、内置的并发策略
Built-in concurrency strategies
注意:如果是first-level Cache(Session)是不会存在并发的问题。
concurrency strategy是一个协调者,它负责将数据存储到cache当中、从数据将cache当中取出来。同时concurrency policy也定义了transaction isolation语义。如果我们想要开启second-level cache,我们需要决定应该为persistent class使用哪一种cache concurrency strategy。
A concurrency strategy is a mediator; it’s responsible for storing items of data in the cache and retrieving them from the cache. This is an important role, because it also defines the transaction isolation semantics for that particular item. You’ll have to decide, for each persistent class, which cache concurrency strategy to use, if you want to enable the second-level cache.
有4种内置的concurrency strategy,这四种严格性等级逐渐下降。
There are four built-in concurrency strategies, representing decreasing levels of strictness in terms of transaction isolation:
■ transactional—Available in a managed environment only. It guarantees full transactional isolation up to repeatable read, if required. Use this strategy for read-mostly data where it’s critical to prevent stale data in concurrent transactions, in the rare case of an update. |
transactional,它的隔离级别相当于repeatable read isolation。这种策略适用于read-mostly data,这样会避免在并发中产生stale data。 |
■ read-write—Maintains read committed isolation, using a timestamping mechanism. It’s available only in non-clustered environments. Again, use this strategy for read-mostly data where it’s critical to prevent stale data in concurrent transactions, in the rare case of an update. |
read-write,它的隔离级别相当于read committed isolation,同时它也使用了timestamp的机制。这只在non-cluster的环境下使用。对于read-mostly data,使用这种策略可以防止并发中的stale data。 |
■ nonstrict-read-write—Makes no guarantee of consistency between the cache and the database. If there is a possibility of concurrent access to the same entity, you should configure a sufficiently short expiry timeout. Otherwise, you may read stale data in the cache. Use this strategy if data rarely changes (many hours, days or even a week) and a small likelihood of stale data isn’t of critical concern. Hibernate invalidates the cached element if a modified object is flushed, but this is an asynchronous operation, without any cache locking or guarantee that the retrieved data is the latest version. |
nonstrict-read-write对于cache和database之间的一致性没有保证。使用这种策略,如果在并发中访问同一个entity,就需要设置足够短的expiry timeout;否则,就可能读取到cache中的stale data。如果数据很少发生变化(几个小时、几天或者是一个星期),就可以使用这种策略。 |
■ read-only—A concurrency strategy suitable for data which never changes. Use it for reference data only. |
read-only只适合于从不发生变化的数据。 |
注意:随着严格性的下降,也带来了性能的提升。在cluster cache中使用full transaction isolation之前,我们必须评估一下性能,很可能会得不偿失。如果现有的application,不能容忍stale data,就不应该使用second-level cache。在实际操作中,首先我们应该禁用second-level cache,接着,对每一个good candidate classess,逐渐添加到second-level cache中,并评估它的concurrency strategy。
Note that with decreasing strictness comes increasing performance. You have to carefully evaluate the performance of a clustered cache with full transaction isolation before using it in production. In many cases, you might be better off disabling the second-level cache for a particular class if stale data isn’t an option. First benchmark your application with the second-level cache disabled. Then enable it for good candidate classes, one at a time, while continuously testing the performance of your system and evaluating concurrency strategies.
虽然我们可以定义自己concurrency strategy,但会很少用。
It’s possible to define your own concurrency strategy by implementing net.sf.hibernate.cache.CacheConcurrencyStrategy, but this is a relatively difficult task and only appropriate for extremely rare cases of optimization.
介绍完second-level cache的concurrency strategy后,接下来是cache provider。cache provider是一个plugin,是cache system的physical implementation。
Your next step after considering the concurrency strategies you’ll use for your cache candidate classes is to pick a cache provider. The provider is a plugin, the physical implementation of a cache system.
2.2.2、选择一个cache provider
Choosing a cache provider
Hibernate强制要求开发者为整个application提供a single cache provider。
For now, Hibernate forces you to choose a single cache provider for the whole application. Providers for the following products are built into Hibernate:
■ EHCache is intended for a simple process scope cache in a single JVM. It can cache in memory or on disk, and it supports the optional Hibernate query result cache. |
EHCache的范围是process scope,它存储的数据可以放在memory或disk当中,同时它也支持Hibernate query result cache。 |
■ OpenSymphony OSCache is a library that supports caching to memory and disk in a single JVM, with a rich set of expiration policies and query cache support. |
■ SwarmCache is a cluster cache based on JGroups. It uses clustered invalidation but doesn’t support the Hibernate query cache. |
■ JBossCache is a fully transactional replicated clustered cache also based on the JGroups multicast library. The Hibernate query cache is supported, assuming that clocks are synchronized in the cluster. |
It’s easy to write an adaptor for other products by implementing net.sf.hibernate.cache.CacheProvider.
并不是所有的cache provider都支持每一个concurrency strategy
Not every cache provider is compatible with every concurrency strategy.
set up second-level cache包含2个步骤
Setting up caching therefore involves two steps:
1 Look at the mapping files for your persistent classes and decide which cache concurrency strategy you’d like to use for each class and each association.
在映射文件(mapping file)中,查看persistent classes,并决定为每一个类和association采用哪一种concurrency strategy。
2 Enable your preferred cache provider in the global Hibernate configuration and customize the provider-specific settings.
在Hibernate.cfg.xml中,使用你所偏爱的cache provider,并自定义provider-secific settings。
For example, if you’re using OSCache, you should edit oscache.properties, or for EHCache, ehcache.xml in your classpath.
对于collection来说,cache只是保存了associated item instance的identifiers。所以,我们如果需要instance本身进行cache,我们必须将item class本身也进行存储。
Now, a collection cache holds only the identifiers of the associated item instances. So, if we require the instances themselves to be cached, we must enable caching of the Item class.
接下来,我们来设置cache provider、expiration polices、physical properties of our cache。我们使用cache regions来单独配置class和collection。
Let’s set the cache provider, expiration policies, and physical properties of our cache. We use cache regions to configure class and collection caching individually.
2.2.3、理解cache region
Understanding cache regions
在Hibernate的second-level cache当中,Hibernate会将不同的classes/collections放置到不同的cache regions。一个cache region就是一个named cache。
Hibernate keeps different classes/collections in different cache regions. A region is a named cache: a handle by which you can reference classes and collections in the cache provider configuration and set the expiration policies applicable to that region.
在存储class的cache region中,region的名字就是class的名字;或者在存储collection的cache region中,region的名字就是class的类名和property属性名一起使用。
The name of the region is the class name, in the case of a class cache; or the class name together with the property name, in the case of a collection cache. Category instances are cached in a region named org.hibernate.auction.Category, and the items collection is cached in a region named org.hibernate.auction.Category.items.
我们可以使用Hibernate配置的property(hibernate.cache.region_prefix)为特定的SessionFactory来指定一个root region name。这种设置,对于多个SessionFactory instance的application是非常有用的。
You can use the Hibernate configuration property hibernate.cache.region_prefix to specify a root region name for a particular SessionFactory. For example, if the prefix was set to node1, Category would be cached in a region named node1.org.hibernate.auction.Category. This setting is useful if your application includes multiple SessionFactory instances.
现在,我们知道了cache regions,接下来配置expiry policies。首先,我们选一个cache provider。
Now that you know about cache regions, let’s configure the expiry policies for the Category cache. First we’ll choose a cache provider. Assume that we’re running our auction application in a single JVM, so we don’t need a cluster-safe implementation (which would limit our options).
2.2.4、设置local cache provider
Setting up a local cache provider
We need to set the property that selects a cache provider:
hibernate.cache.provider_class=net.sf.ehcache.hibernate.Provider
We’ve chosen EHCache as our second-level cache.
现在,我们需要指定cache region的expiry policies。EHCache有自己的配置文件ehcache.xml,该配置文件需要放在application的classpath当中。在Hibernate的distribution(分发包)当中,带有内置cache provider配置的示例。
Now, we need to specify the expiry policies for the cache regions. EHCache has its own configuration file, ehcache.xml, in the classpath of the application. The Hibernate distribution comes bundled with example configuration files for all built-in cache providers, so we recommend the usage comments in those files for detailed configuration and assume the defaults for all options we don’t mention explicitly.
A cache configuration in ehcache.xml for the Category class might look like this: