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>