У меня есть приложение Spring Boot, которое получает (и сохраняет) данные через Hibernate. Hibernate подключен к базе данных MySQL. Я немного оптимизировал запросы к базе данных с помощью некоторых графов сущностей, чтобы объединить несколько таблиц перед извлечением их из базы данных. Теперь я хочу, чтобы наиболее распространенные объекты (которые не изменялись слишком часто) были сохранены в кеше.
Я пробовал кэшировать через Infinispan и Hazelcast. Я изменил конфигурации здесь и там, но каким-то образом сущности ВСЕГДА извлекаются из базы данных.
Для Halzelcast я добавил следующие три зависимости в свой pom.xml
. Несмотря на то, что hazelcast-hibernate
кажется интегрированным в hazelcast-spring
, мне нужна третья зависимость, потому что в противном случае фабрика региона была бы недоступна.
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast</artifactId>
<version>3.12.2</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-spring</artifactId>
<version>3.12.2</version>
</dependency>
<dependency>
<groupId>com.hazelcast</groupId>
<artifactId>hazelcast-hibernate53</artifactId>
<version>1.3.2</version>
</dependency>
Следующих настроек должно быть достаточно для использования Hazelcast в качестве спящего режимакэш. Но это не работает. Я все еще вижу те же SQL-запросы в журналах, что и раньше.
spring.jpa.properties.hibernate.cache.use_second_level_cache=true
spring.jpa.properties.hibernate.cache.region.factory_class=com.hazelcast.hibernate.HazelcastLocalCacheRegionFactory
HazelcastLocalCacheRegionFactory
следует использовать, потому что производительность должна быть немного лучше, а ram (в настоящее время) не такая уж большая проблема. Тем не менее, я также приветствую различные подходы.
Соответствующие сущности получают обе аннотации (@Cacheable
и @Cache
).
@Entity(name = "business_units")
@Getter @Setter
@Cacheable
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class BusinessUnit extends Auditable<String> implements Serializable {
private static final long serialVersionUID = -6994142588281279518L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator = "native")
@GenericGenerator(name = "native", strategy = "native")
@Column(nullable = false, name = "id")
private Integer id;
@ManyToOne(fetch = FetchType.EAGER)
@JoinColumn(name = "allocated_responsibility_id", referencedColumnName = "id")
@org.hibernate.annotations.Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
private ProductManager allocatedResponsibility;
// Some other attributes, getters and setters...
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof BusinessUnit)) return false;
BusinessUnit that = (BusinessUnit) o;
return id != null && id.equals(that.id);
}
@Override
public int hashCode() {
return 31;
}
}
То же самое было также опробовано в Infinispan (разные зависимости, нотот же несуществующий результат).
Я собираюсь использовать внешнего поставщика, потому что приложение должно быть масштабируемым. Не обращая на это внимания, кеш больше не будет правильно отражать базу данных.
Следует использовать встроенный кеш, поскольку дополнительный сервер для Hazelcast или Infinispan будет слишком сложен для обслуживания.
Iпонятия не имею, почему ничего не меняется (хорошо, я вижу, что Hazelcast запускается). У меня была еще одна идея - использовать кеш запросов вместо кеша Hibernate. Но это потребует большего внимания для обеспечения синхронности базы данных и кеша. Кроме того, приложение может извлечь из этого меньше пользы.
Не могли бы вы сказать, почему оно не работает и что изменить, чтобы оно работало?
Обновление: добавить статистику
Я попробовал следующие предложения и добавил статистику, как предложил @Nicolas.
spring.jpa.properties.hibernate.generate_statistics=true
Когда я впервые загружаю такую страницу, данные запрашиваются из базы данных и помещаются в кеш (L2C). ).
1519200 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
1759800 nanoseconds spent preparing 1 JDBC statements;
4144000 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
161900 nanoseconds spent performing 3 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
Но когда я снова получаю доступ к сайту (или выполняю любое другое действие, которое должно попасть в кэш), данные снова запрашиваются из базы данных (и помещаются в кэш).
Журналы при повторном доступе к странице:
2019-10-08 12:51:38.399 INFO 17028 --- [nio-8080-exec-8] i.StatisticalLoggingSessionEventListener : Session Metrics {
0 nanoseconds spent acquiring 0 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
0 nanoseconds spent preparing 0 JDBC statements;
0 nanoseconds spent executing 0 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
0 nanoseconds spent performing 0 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
2019-10-08 12:51:38.404 DEBUG 17028 --- [nio-8080-exec-8] org.hibernate.SQL :
select
businessun0_.id as id1_0_0_,
productman1_.id as id2_9_1_,
employee2_.id as id1_4_2_,
businessun0_.created_by as created_2_0_0_,
businessun0_.created_date as created_3_0_0_,
businessun0_.last_modified_by as last_mod4_0_0_,
businessun0_.last_modified_date_time as last_mod5_0_0_,
businessun0_.allocated_responsibility_id as allocate7_0_0_,
businessun0_.name as name6_0_0_,
productman1_.employee_id as employee3_9_1_,
employee2_.created_by as created_2_4_2_,
employee2_.created_date as created_3_4_2_,
employee2_.last_modified_by as last_mod4_4_2_,
employee2_.last_modified_date_time as last_mod5_4_2_,
employee2_.email_address as email_ad6_4_2_,
employee2_.location as location7_4_2_,
employee2_.name as name8_4_2_,
employee2_.team as team9_4_2_
from
business_units businessun0_
left outer join
responsibilities productman1_
on businessun0_.allocated_responsibility_id=productman1_.id
left outer join
employees employee2_
on productman1_.employee_id=employee2_.id
2019-10-08 12:51:38.412 INFO 17028 --- [nio-8080-exec-8] i.StatisticalLoggingSessionEventListener : Session Metrics {
901000 nanoseconds spent acquiring 1 JDBC connections;
0 nanoseconds spent releasing 0 JDBC connections;
1075000 nanoseconds spent preparing 1 JDBC statements;
1766400 nanoseconds spent executing 1 JDBC statements;
0 nanoseconds spent executing 0 JDBC batches;
166800 nanoseconds spent performing 3 L2C puts;
0 nanoseconds spent performing 0 L2C hits;
0 nanoseconds spent performing 0 L2C misses;
0 nanoseconds spent executing 0 flushes (flushing a total of 0 entities and 0 collections);
0 nanoseconds spent executing 0 partial-flushes (flushing a total of 0 entities and 0 collections)
}
Обновление: подключение к Management Center
Я изменил фабрику региона Hazelcast на ту, которая не является локальной для возможностиподключиться к центру управления.
spring.jpa.properties.hibernate.cache.region.factory_class=com.hazelcast.hibernate.HazelcastCacheRegionFactory
Теперь два члена подключаются к центру управления (хотя я запускаю только одно приложение).
Статистика отображается в журналах. Я показываю толчки. Тем не менее, центр управления показывает мне, что некоторые данные были получены из кэша. Иногда в статистике я мог видеть одно попадание в кеш вместо оператора JDBC.