Estratégias de simultaneidade

Depois de ativar o cache de segundo nível no Hibernate, você precisa explicar ao Hibernate quais objetos Entity queremos armazenar em cache e como.

Para fazer isso, o Hibernate possui uma anotação especial para classes Entity - @Cache . Exemplo:

@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)

Essa anotação precisa ser escrita para cada entidade Entidade para a qual queremos usar o cache de segundo nível. Exemplo:

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;
    private Set<Task> tasks;
}

O Hibernate tem 4 estratégias de acesso possíveis para uma entidade em cache se for acessada por diferentes threads:

  • somente leitura
  • ler escrever
  • leitura-gravação não estrita
  • transacional

Somente leitura . Uma estratégia de simultaneidade apropriada aos dados que nunca muda. O Hibernate simplesmente armazenará esses objetos em sua memória. Use-o apenas para dados de referência.

Os bancos de dados armazenam muitas informações que nunca mudam. Por exemplo, uma tabela mantém uma lista de eventos que são apenas adicionados, mas nunca alterados ou removidos. Se você precisar trabalhar com esta tabela por meio do Hibernate, a estratégia de cache somente leitura será adequada para você.

Ler-escrever (ler-escrever). Use esta estratégia para dados que são principalmente legíveis. No entanto, o Hibernate rastreará as tentativas de alterar esses dados, embora espere que sejam muito pouco frequentes.

Você precisa armazenar em cache principalmente aqueles objetos que raramente mudam e são frequentemente lidos/solicitados. Se você tiver esses objetos, precisará usar a estratégia de leitura e gravação para eles.

Nonstrict-read-write . Essa estratégia não garante consistência entre o cache e o banco de dados. Use esta estratégia se os dados quase nunca mudarem e uma pequena chance de dados obsoletos não for um problema crítico.

Ao contrário da estratégia de leitura/gravação, essa estratégia assume que os dados mutáveis ​​não estão bloqueados para leitura. Isso pode fazer com que o objeto seja alterado em um local, enquanto em outro alguém está lendo a versão antiga dele.

Por exemplo, um usuário mudou seu comentário, mas outros usuários ainda veem sua versão antiga por algum tempo. Se isso não for um problema para você, use a estratégia nonstrict-read-write.

Transacional . Use esta estratégia principalmente para dados somente leitura, onde é importante evitar dados obsoletos em transações simultâneas nas raras ocasiões de uma atualização.

Armazenando dados em um cache

Outro detalhe importante sobre o cache de segundo nível que você deve lembrar é que o Hibernate não armazena os objetos de suas classes em si. Ele armazena informações como matrizes de strings, números, etc.

E o identificador de objeto atua como um ponteiro para essas informações. Conceitualmente, é algo como um Map, no qual o id do objeto é a chave e os arrays de dados são o valor. Você pode imaginar assim:

1 -> { "Ivanov", 1, null , {1,2,5} }
2 -> { "Petrov", 2, null , {1,2,5} }
3 -> { "Sidorov", 3, null , {1,2,5} }

O que é bastante razoável, considerando quanta memória extra cada objeto ocupa.

Além do acima, você deve se lembrar que as dependências de sua classe Entity também não são armazenadas em cache por padrão. Por exemplo, se considerarmos a classe acima, Employee , então, ao buscar, a coleção de tarefas será recuperada do banco de dados , e não do cache de segundo nível .

Se você também deseja armazenar em cache as dependências, a classe deve ficar assim:

@Entity
@Table(name = "employee")
@Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
public class Employee {
    @Id
    private Integer id;

   @Cache(usage = CacheConcurrencyStrategy.READ_WRITE)
   private Set<Task> tasks;
}

E o último detalhe - a leitura do cache de segundo nível ocorre apenas se o objeto desejado não foi encontrado no cache de primeiro nível.

CacheMode

O Hibernate permite um gerenciamento de cache muito flexível. Você pode definir o modo de cache para cada sessão individual ou mesmo para cada solicitação de banco de dados.

Existem cinco desses modos:

  • PEGAR
  • IGNORAR
  • NORMAL
  • COLOCAR
  • ATUALIZAR

A tabela abaixo descreve seu trabalho:

CacheMode Descrição
PEGAR Os dados são lidos do cache, mas não adicionados a ele.
IGNORAR A sessão não interage com o cache.
NORMAL Os dados são lidos do cache e adicionados a ele.
COLOCAR Os dados nunca são retirados do cache, mas adicionados a ele.
ATUALIZAR Os dados nunca são retirados do cache, mas adicionados a ele. Nesse modo, a configuração hibernate.cache.use_minimal_puts é usada adicionalmente.

Um exemplo de configuração do modo de cache para uma sessão:

session.setCacheMode(CacheMode.GET);
Employee director = session.createQuery("from Employee where id = 4").uniqueResult();

E também um exemplo de configuração do modo para a sessão e a solicitação:

session.setCacheMode(CacheMode.GET);
Query query = session.createQuery("from Employee where id = 4");
query.setCacheMode(CacheMode.IGNORE); // Ignore cache work for this request
Employee director = query.uniqueResult();