Показаны сообщения с ярлыком cache. Показать все сообщения
Показаны сообщения с ярлыком cache. Показать все сообщения

пятница, 25 мая 2012 г.

Проект Hibernate Dynamic SQL Cache

Выложил на github проект Hibernate Dynamic SQL Cache.

Описание

Данный проект успешно используется мной в нескольких проектах и показал хорошую эффективность. Причиной для создания проекта послужил неэффективный механизм кэширования в Hibernate, впрочем сами разработчики открыто пишут об этом в документации.

  • HQL-кэш, а также кэш коллекций entity-объектов будут сбрасываться при каждом обновлении данных в хотя бы в одной из таблиц, участвующих в запросе. При очень частых обновлениях таблиц польза от такого рода кэшей сводится к 0.
  • SQL-кэш держит в памяти лишь результат первого вызова запроса и не сбрасывается.

Поэтому возникла идея создания динамически обновляемого кэша. Результат запроса обновляется при INSERT или DELETE объекта в базе. Для использования данного решения следует немного изменить подход к построению запросов, а также использованию различных коллекций внутри entity-объектов.

  • Запрос должен возвращать только id объекта. По этому id вы можете легко загрузить объект из кэша. (Таким образом получается два обращения к кэшу, что всегда быстрее выполнения запросов к базе)
  • Запрос должен быть только по неизменяемым полям объекта.
  • Вместо использования коллекций в entity-объекте использовать соответствующий SQL-запрос c динамическим обновлением.

Cache provider может использоваться абсолютно любой (Infinispan, Hazelcast, EHCache ...)

Проект опубликован под Apache License 2.0

Пример использования

Для наглядности примера используется Spring, хотя сам проект не привязан к нему, можно использовать любой другой контейнер.

Конфигурация hibernate. Здесь важно отметить использование собственного hibernate.cache.query_cache_factory через который и осуществляется вся логика управления обновлениями кэшей:

Регистрируем com.corundumstudio.hibernate.dsc.QueryCacheEntityListener который будет отслеживать основные операции по всем entity.

Пример DAO-сервиса. com.corundumstudio.hibernate.dsc.CacheCallback - callback через который будет обслуживать операции "insert" или "delete" на объекте (в данном примере SimpleEntity), чтобы результаты запроса были всегда "свежими".

Теперь при вызове SimpleEntityDao.getEntityByPhone, первый раз будет произведено обращение к БД. Последующие вызовы метода будут возвращать значение из кэша, причем если объект SimpleEntity с искомым значением phone будет добавлен в базу он также появится и в результате данного запроса. И наоборот, если объект с таким значением phone будет удален, то результат запроса будет возвращать null

Если результат запроса возвращает список объектов, то в этом случае, при удалении/создании объекта, в списке будет удаляться/добавляться его id

среда, 12 ноября 2008 г.

Отключение кэширования html-страницы. Часть 2

Использование meta-тэгов, описываемых в первой части помогает нам избавиться от кэширования в браузере. Однако, помимо кэша браузера существует кэш прокси-сервера, который проводит анализ лишь HTTP-заголовков. К тому же может появится необходимость отключить кэширование не только самой html-страницы, но и ресурсов, находящихся на ней (jpg, swf ...). Данную проблему можно решить таким вот servlet-фильтром:

package ru.someone;

import java.io.IOException;
import java.util.*;
import javax.servlet.*;
import org.slf4j.*;

public class ResponseHeaderFilter implements Filter {

private final Logger log = LoggerFactory.getLogger(getClass());
private final Map httpParams = new HashMap();

public void init(FilterConfig filterConfig) throws ServletException {
Enumeration enums = filterConfig.getInitParameterNames();
while(enums.hasMoreElements()) {
final String name = enums.nextElement();
final String value = filterConfig.getInitParameter(name);
log.debug("HTTP-header registred - {}:{}", name, value);
httpParams.put(name, value);
}
}

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletResponse httpResponse = (HttpServletResponse) response;
for (Entry entry : httpParams.entrySet()) {
httpResponse.setHeader(entry.getKey(), entry.getValue());
}
chain.doFilter(request, response);
}

public void destroy() {
}

}

Этот фильтр выставляет HTTP-заголовки, объекту javax.servlet.HttpServletResponse, которые берет из конфигурации фильтра. Соответственно в самом web.xml нужно написать:

<filter>
<filter-name>responseHeaderFilter</filter-name>
<filter-class>ru.someone.ResponseHeaderFilter</filter-class>
<init-param>
<param-name>Cache-Control</param-name>
<param-value>no-store, max-age=0, must-revalidate</param-value>
</init-param>
<init-param>
<param-name>Pragma</param-name>
<param-value>no-cache</param-value>
</init-param>
<init-param>
<param-name>Expires</param-name>
<param-value>Fri, 01 Jan 1990 00:00:00 GMT</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>responseHeaderFilter</filter-name>
<url-pattern>*.jpg</url-pattern>
</filter-mapping>
<filter-mapping>
<filter-name>responseHeaderFilter</filter-name>
<url-pattern>*.swf</url-pattern>
</filter-mapping>

понедельник, 27 октября 2008 г.

Отключение кэширования html-страницы. Часть 1

Старая проблема - как отключить кэширование страницы в браузере, но лишний раз напомнить о ней не помешает. Итак, в html странице, нужно использовать следующие meta-тэги:

<html>
<head>
<meta http-equiv="Cache-Control" content="no-cache, no-store, max-age=0, must-revalidate"/>
<meta http-equiv="Pragma" content="no-cache"/>
<meta http-equiv="Expires" content="Fri, 01 Jan 1990 00:00:00 GMT"/>
</head>
<body>
...
</body>
<html>

Значение параметера http-equiv должно быть названием параметра используемого непосредственно в http-заголовке. В content указываем само значение параметра. Однако это вовсе не означает, что вы увидите их в самом http-заголовке, хотя есть серваки, которые автоматически встраивают такого рода meta-тэги в http-заголовок.

Кратко об используемых параметрах:

  • Cache-Control - параметер управления кешированием страниц. Введен в HTTP 1.1.
  • Pragma - отключение кэширования страницы. Имеет единственное значение no-cache. Введен в HTTP 1.0.
  • Expires - устанавливает дату и время, после которого документ считается устаревшим. Дата должна указываться в следующем формате (на английском языке): День недели (сокр.) число (2 цифры) Месяц (сокр.) год часы:минуты:секунды GMT. Введен в HTTP 0.9

Т.к. не известно заранее какая версия HTTP-протокола будет использоваться на стороне клиента, то лучше использовать все три параметра.