Hibernate cache второго уровня.
В одной из прошлых статей я расказывал про hibernate cache первого уровня, настало время расказать и про cache второго уровня. И так в крации напомню что кеш первого уровня встроен в hibernate, он всегда включен, его не возможно выключить. Область действия, в течении одной транзакции в сессии hibernate, т.е. между вызовами session.beginTransaction() и session.getTransaction().commit(). И так, зачем нам нужен hibernate cache второго уровня, прежде всего он уменьшает количество sql-запросов к базе данных, увеличивая при этом время отклика программы, что отражается на её быстродействии. Один раз попав в cache второго уровня объект-сущность используется на всем протяжении жизни объекта sessionFactory, т. е. облать действия кеша - вся наша программа, а если быть точнее, то как вы настроете свой кеш, так он себя и поведет. В отличии от кеша первого уровня кеш второго уровня нужно включать непосредственно в настройках Hibernate, и он реализуется second-level cache провайдером - сторонней библиотекой кешем. Выбор провайдера зависит от стратегии которые он поддерживает, под стратегией понимается что можно делать над объектом кеша: изменять, удалять, вставлять, читать, давайте рассмотрим их:- read-only - самая простая стратегия, кеш может только читаться, операции обновления (update) и удаления (delete) не разрешены, однако можно вставлять новые данные (insert) отлично подходит к кешированию различных справочников - наименование регионов, городов, улиц ... и т. д.
- nonstrict read-write - данные этого кеша могут меняться, возможен конкурентный доступ к одному и тому же объекту. Может произойти ситуация когда в кеше содержатся не последняя измененная сущность, т. е. данные сущности в кеше могут быть не равны данным в базе данных. Отсуда следует что нужно избегать конкурентного доступа, точнее одни и те же записи не должны редактировать 2 пользователя. Преведу пример: идеальный случаи это когда кадровики редактируют только свои данные по работникам: 1-й кадровик с 1 по 200 таб. номер, 2-й кадровик с 201 по 400 таб. номер и т. д.
- read-write - в целом похож на nonstrict read-write, позволяет более гибко настроить конкурентный доступ, поведение кеша зависит от настройки transaction isolation уровня базы данных, т. е. поведение изменения данных в кеше копирует поведение транзакции. Максимум, чего можно выжать - это "repeatable read transaction isolation" уровень базы данных.
- transactional - изменения в кеше и изменения в БД, полностью записываются в одной транзакции. У предыдущих двух стратегий была отложенная запись кеша, т. е. при изменении сущности, с начала происходит блокировка в кеше(soft locked), после применения транзакции с некоторым опазданием выполняется замена старого значения в кеше, новым. Уровнь этого кеша - это "serializable transaction isolation" уровень базы данных.
- Включим кеш второго уровня в настройках Hibernate и подключим ehcache:
<!-- Enable the second-level cache --> <property name="cache.use_second_level_cache">true</property> <property name="cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</property>
- Включим кеш запросов:
<!-- Enable the query cache --> <property name="cache.use_query_cache">true</property>
- Опищем сначала наши сущности (1), а потом какие сущности (2) должны, у нас кешироваться в кеше второго уровня, какую стратегию при этом применять, поведение с lazy объектами, имя региона кеша:
<!-- (1) Names the annotated entity class --> <mapping class="org.hibernate.tutorial.annotations.Event"/> <mapping class="org.hibernate.tutorial.annotations.Person"/> <!-- (2) Entity class the second-level cache --> <class-cache class="org.hibernate.tutorial.annotations.Person" usage="read-write" include="non-lazy" region="org.hibernate.tutorial.annotations.Person1"/> <class-cache class="org.hibernate.tutorial.annotations.Event" usage="read-write" include="non-lazy" region="org.hibernate.tutorial.annotations.Event1"/> - Переходим к тонкой настройке сущностей кеша, конечно все можно настроить через аннотации но мне ближе старинный метод настройки через файл ehcache.xml:
<?xml version="1.0" encoding="UTF-8"?> <ehcache name="Foo" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="ehcache.xsd"> <!-- где будут у нас храниться данные на диске, в случае выгрузки кеша на диск --> <diskStore path="java.io.tmpdir"/> <!-- если вы не указали имя региона то по умолчанию используются параметры default кеша --> <defaultCache maxElementsInMemory="1000" eternal="false" timeToIdleSeconds="1200" timeToLiveSeconds="1200" overflowToDisk="true"> </defaultCache> <!-- настраиваем наши регионы описанные раннее --> <cache name="org.hibernate.tutorial.annotations.Person1" maxElementsInMemory="1" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> <cache name="org.hibernate.tutorial.annotations.Event1" maxElementsInMemory="1" eternal="false" timeToIdleSeconds="300" timeToLiveSeconds="600" overflowToDisk="true" /> </ehcache> - задействуем кеш запросов, его просто включить, вызовите метод setCacheable(true) и все сущности запроса попадут в кеш запросов:
List result2 = session1.createQuery("from Person as p join fetch p.events"). setCacheable(true).list();
ну вот и все приведу на последок свой pom.xml с зависимостями:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.hibernate.tutorials</groupId>
<artifactId>hibernate-tutorials</artifactId>
<version>4.1.7.Final</version>
<packaging>pom</packaging>
<name>Hibernate Getting Started Guide Tutorials</name>
<description>Aggregator for the Hibernate tutorials presented in the Getting Started Guide</description>
<properties>
<!-- Skip artifact deployment -->
<maven.deploy.skip>true</maven.deploy.skip>
</properties>
<modules>
<module>annotations</module>
<module>annotations0</module>
<module>annotations1</module>
<module>annotations2</module>
<module>annotations3</module>
<module>annotations4</module>
<module>annotations5</module>
<module>annotations6</module>
<module>annotations7</module>
<module>annotations8</module>
</modules>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
<version>4.1.7.Final</version>
</dependency>
<!-- Hibernate uses jboss-logging for logging, for the tutorials we will use the sl4fj-simple backend -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.6.1</version>
</dependency>
<!-- The tutorials use JUnit test cases to illustrate usage -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.10</version>
</dependency>
<!-- The tutorials use the H2 in-memory database -->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<version>1.2.145</version>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>4.1.7.Final</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-jdk14</artifactId>
<version>1.6.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>0.11.0</version>
<scope>provided</scope>
</dependency>
<!-- Hibernate c3p0 connection pool -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.1.7.Final</version>
</dependency>
<!-- Hibernate jbosscache-core -->
<dependency>
<groupId>org.jboss.cache</groupId>
<artifactId>jbosscache-core</artifactId>
<version>3.2.5.GA</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.6</source>
<target>1.6</target>
</configuration>
</plugin>
</plugins>
<testResources>
<testResource>
<filtering>false</filtering>
<directory>src/test/java</directory>
<includes>
<include>**/*.xml</include>
</includes>
</testResource>
<testResource>
<directory>src/test/resources</directory>
</testResource>
</testResources>
</build>
<repositories>
<repository>
<id>sourceforge</id>
<url>http://oss.sonatype.org/content/groups/sourceforge/</url>
<releases>
<enabled>true</enabled>
</releases>
</repository>
<repository>
<id>terracotta-releases1</id>
<url>http://www.terracotta.org/download/reflector/releases</url>
</repository>
<repository>
<id>terracotta-releases</id>
<url>http://www.terracotta.org/download/reflector/releases</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
<repository>
<id>jboss-public-repository-group</id>
<name>JBoss Public Maven Repository Group</name>
<url>http://repository.jboss.org/nexus/content/groups/public-jboss/</url>
<releases>
<enabled>true</enabled>
</releases>
<snapshots>
<enabled>true</enabled>
</snapshots>
</repository>
</repositories>
</project>