índice
A primeira seção Mybatis cache
1.1 Compreensão do cache Mybatis
- O cache do Mybatis é semelhante ao cache do hibernate, incluindo o cache de primeiro nível e o cache de segundo nível.O cache de primeiro nível é usado por padrão, e o cache de segundo nível precisa ser ativado manualmente.
- O cache de primeiro nível refere-se a sqlsession. Há uma área de dados em sqlsession, que é uma estrutura de mapa. Esta área é a área de cache de primeiro nível. A chave no cache de primeiro nível é um valor exclusivo composto de informações como instruções, condições e instruções SQL. O valor no cache de primeiro nível é o objeto de resultado da consulta.
- O cache de segundo nível se refere ao mapeador sob o mesmo namespace. No cache de segundo nível, há também uma estrutura de mapa. Esta área é a área de cache de primeiro nível.
Obtenha alguns dados em sqlSession1 e poderá obter os mesmos dados em sqlSession2 sem usar SQL. Neste momento, você precisa usar o cache secundário.
O cache secundário é compartilhado por todas as sqlSessions
1.2 Cache de nível 1
princípio
- A primeira consulta para um usuário cujo id é 1 executará sql, e o cache de primeiro nível será executado por padrão, e os dados serão armazenados no cache de primeiro nível Map. Quando a modificação, adição e exclusão de usuários forem enviadas, o cache de primeiro nível será limpo. , Consulte o usuário cujo id é 1 novamente e precisa executar o sql novamente
Use e teste
- Métodos save e findUserById anteriores
- Observe que a classe a ser configurada para implementar a interface de serialização (ou seja, um sinalizador serializável), caso contrário, um erro será relatado
@Test
public void test1() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//4.通过会话获取dao接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//第二次不会执行sql
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
- Quando envolve salvar, atualizar, excluir, etc., o cache de primeiro nível é automaticamente limpo
@Test
public void test2() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
User user1 = userMapper.findUserById(1);
System.out.println(user1);
//保存一个新用户
userMapper.save(new User("shu1","男",new Date(),"北京市"));
//若要保存到数据库记得提交事务,否则不影响数据库,这里只做演示一级缓存可不提交
sqlSession.commit();
//此时第二次会执行sql
User user2 = userMapper.findUserById(1);
System.out.println(user2);
sqlSession.close();
}
1.3 cache secundário
princípio
Use e teste
- Ligue a chave geral do cache secundário (configurado no arquivo de configuração global) (mais configurações são definidas no dia01)
- Configure o cache secundário em UserMapper.xml
- teste
- Observe que a classe a ser configurada para implementar a interface de serialização (ou seja, um sinalizador serializável), caso contrário, um erro será relatado
//二级缓存
@Test
public void test3() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//session关闭了,数据才会写入二级缓存
sqlSession1.close();
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
- Se operações como inserir, atualizar, excluir, etc. forem realizadas, o cache secundário será limpo
@Test
public void test4() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
SqlSession sqlSession3 = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
UserMapper userMapper3 = sqlSession3.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
sqlSession1.close();
//保存用户,二级缓存也会清空
userMapper3.save(new User("shu2","男",new Date(),"上海市"));
sqlSession3.commit();
sqlSession3.close();
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
Desativa o cache de segundo nível do método especificado
- O cache de segundo nível do método especificado é desabilitado, o cache de segundo nível deste método não tem efeito e outros métodos não afetam
Atualizar cache
- O cache de segundo nível do método especificado está desativado acima. Este método é usado para refletir o cache de segundo nível. Lembre-se de remover a desativação, caso contrário, o cache não será atualizado.
Resumindo
O ponto comum entre o cache de primeiro nível e o cache de segundo nível: quando operações como inserir, atualizar e excluir são realizadas, o cache é limpo.
1.4 Integrar ehcache
- Pergunta: Por que não usar o cache que vem com o Mybatis, mas integrar o cache ehcache?
- Resposta: Mybatis em si é uma estrutura de camada de persistência, não é uma estrutura de cache dedicada, então sua implementação de cache não é boa o suficiente para suportar distribuído, enquanto Ehcache é uma estrutura de cache distribuída.
O que é distribuído
- A fim de melhorar o desempenho, o sistema geralmente adota implantação distribuída (implantação de cluster)
Pensamento integrado
- O cache possui uma interface padronizada Cache (para quem deseja utilizá-la basta implementá-la e escrever o método correspondente), e sua implementação padrão é PerpetualCache de mybatis. Se você deseja integrar o cache secundário de mybatis, implemente a interface do Cache.
- Mybatis vem com cache de implementação
Etapas de integração
Etapa 1: importe o pacote jar
- Você pode ver o cache implementado pelo ehcache
Etapa 2: configurar a tag de cache no arquivo de mapeamento
<!--配置缓存
type不写,默认使用的就是mybatis自带的缓存技术,perpetualCache永久缓存
-->
<cache type="org.mybatis.caches.ehcache.EhcacheCache"></cache>
Etapa 3: adicionar o arquivo de configuração ehcache em src
-
Copie-o para o diretório src e renomeie-o para ehcache.xml (após excluir o comentário)
-
maxElementsInMemory: Defina o número máximo de objetos que podem ser armazenados no cache baseado em memória.
-
eterno: Defina se o objeto é permanente, verdadeiro significa nunca expirar; se for falso, deve ser julgado de acordo com timeToIdleSeconds e timeToLiveSeconds.
-
timeToIdleSeconds: Defina o tempo máximo para o objeto ficar ocioso, em segundos. Após este tempo, o objeto expira. Quando o objeto expira, o EHCache o remove do cache. Se este valor for 0, significa que o objeto pode ficar inativo indefinidamente. (A unidade é segundos)
-
timeToLiveSeconds: Defina o tempo máximo de vida do objeto. Após esse tempo, o objeto expira. Se este valor for 0, significa que o objeto pode existir no cache indefinidamente. O valor do atributo deve ser maior ou igual ao valor do atributo timeToIdleSeconds (em segundos)
-
overflowToDisk: Defina se deseja gravar objetos de estouro no cache baseado em disco rígido depois que o número de objetos no cache interno atingir o limite superior
-
diskPersistent: se deve persistir o objeto (armazenado no disco rígido) quando o jvm termina, verdadeiro ou falso é opcional, o padrão é falso
-
diskExpiryThreadIntervalSeconds: Especifica o tempo de polling do thread de escuta dedicado à limpeza de objetos expirados. (A unidade é segundos)
-
memoryStoreEvictionPolicy: Quando o cache de memória atinge o máximo e um novo elemento é adicionado, a política quando o elemento no cache é removido para o disco. O padrão é LRU (menos usado recentemente), as opções são LFU (menos usado, menos usado) e FIFO (primeiro a entrar, primeiro a sair)
-
LRU (menos usado recentemente): o elemento em cache tem um carimbo de data / hora. Quando a capacidade do cache estiver cheia e você precisar criar espaço para armazenar novos elementos em cache, o elemento no elemento de cache existente cujo carimbo de data / hora é o mais distante da hora atual Será apagado do cache.
-
LFU (usado com menos frequência): o elemento armazenado em cache tem um atributo de ocorrência e aquele com o menor valor de ocorrência será limpo do cache.
Etapa 4: teste
- Use o cache secundário de teste anterior
//二级缓存
@Test
public void test3() throws IOException {
//1.读取配置文件
InputStream inputStream = Resources.getResourceAsStream("SqlMapConfig.xml");
//2.通过SqlSessionFactoryBuilder创建SqlSessionFactory会话工厂
SqlSessionFactory sessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//3.通过SqlSessionFactory创建SqlSession
SqlSession sqlSession1 = sessionFactory.openSession();
SqlSession sqlSession2 = sessionFactory.openSession();
//默认情况下的一级缓存是开启的
//保存、删除、更新后,一级缓存会自动清空,下次查询会再次执行sql
//4.通过会话获取dao接口
UserMapper userMapper1 = sqlSession1.getMapper(UserMapper.class);
UserMapper userMapper2 = sqlSession2.getMapper(UserMapper.class);
User user1 = userMapper1.findUserById(1);
System.out.println(user1);
//session关闭了,数据才会写入二级缓存
sqlSession1.close();
User user2 = userMapper2.findUserById(1);
System.out.println(user2);
sqlSession2.close();
}
- Execute SQL uma vez e busque-o do cache de segundo nível pela segunda vez
1.5 Cenários de uso de cache secundário
- Para consultas que requerem alta velocidade de resposta de acesso, mas baixo desempenho em tempo real, a tecnologia de cache secundário pode ser usada .
Observação: ao usar o cache de segundo nível, você deve definir um intervalo de atualização (há um atributo flashInterval na tag de cache) para atualizar o cache de segundo nível regularmente. Este intervalo de atualização é definido de acordo com necessidades específicas, como 30 minutos, 60 minutos, etc., unidade São milissegundos. - Por exemplo: defina o intervalo de atualização do cache para 60 minutos (limpe o cache a cada 60 minutos)
1.6 Limitações do cache de segundo nível
-
O cache de segundo nível Mybatis não é bem implementado para dados de baixa granularidade.
-
Por exemplo: Cache de informações do produto. Devido à grande quantidade de visitas de consulta de informações do produto, os usuários devem consultar as informações mais recentes do produto todas as vezes. Neste momento, se o cache secundário for usado, é impossível atualizar apenas as informações do produto em cache quando um produto muda. Ele não atualiza outras informações do cache do produto, porque o cache secundário está no nível do mapeador. Quando as informações de um produto são atualizadas, os dados do cache de informações de todos os produtos serão apagados.
-
Para resolver esses problemas, os dados precisam ser armazenados em cache de maneira direcionada na camada de negócios, conforme necessário.
-
Por exemplo, as operações de alteração frequente de dados podem ser colocadas separadamente no mapeador de outro namespace.