Como o cache é implementado
-
Cache de nível 1
- Cache secundário
Prática de caso
1. Cache de nível 1
Cache local HashMap baseado em PerpetualCache (mybatis implementa internamente a interface de cache), e seu escopo de armazenamento é Sessão. Após a liberação ou fechamento da Sessão, todos os Caches na Sessão serão esvaziados;
2. Cache secundário
O mecanismo do cache de primeiro nível é o mesmo, o padrão também é o armazenamento HashMap do PerpetualCache, a diferença é que seu escopo de armazenamento é Mapper (Namespace), e a fonte de armazenamento pode ser customizada, como Ehcache;
Para o mecanismo de atualização de dados de cache, quando uma operação C / R / U / D é realizada em um determinado escopo (Sessão de cache de primeiro nível / Namespaces de cache de segundo nível), todos os caches selecionados sob este escopo serão limpos por padrão.
Se o segundo cache estiver habilitado, primeiro consulte os dados do segundo cache, se o segundo cache os tiver, obtenha os dados do segundo cache, se o segundo cache não tiver, verifique se há dados de cache do primeiro cache, se o primeiro cache não tiver, consulte Banco de dados .
3. Limitações do cache secundário
O cache de segundo nível Mybatis não é bom para o cache de nível de dados refinado. Para armazenar mais dados em cache ao mesmo tempo, como os seguintes requisitos: armazenar em cache informações do produto, devido ao grande número de visitas a consultas de informações do produto, mas os usuários são obrigados a Pode consultar as informações mais recentes do produto. Neste momento, se você usar o cache secundário de mybatis, não será possível atualizar apenas as informações de cache deste produto e não as informações de outros produtos quando um produto muda, porque a área de cache secundária de mybaits é baseada no mapeador. Dividido, quando as informações de um produto são alteradas, todos os dados em cache das informações do produto serão apagados
4. Cache de nível 1 (ativado por padrão)
Mybatis fornece cache de primeiro nível por padrão, e o escopo do cache é sqlSession. Na mesma SqlSession, execute a mesma consulta sql duas vezes e não faça mais consultas no banco de dados pela segunda vez.
Princípio: O cache de primeiro nível usa armazenamento Hashmap.Quando mybatis executa uma consulta, ele fará uma consulta do cache, se não houver nenhuma consulta do banco de dados no cache. Se o SqlSession executar clearCache () commit ou adicionar operação de modificação de exclusão, limpe o cache.
Existe por padrão, basta entender o resultado da observação
a. Existência de cache (sessão não enviada)
@Test
public void test01() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
accountDao.queryAccountById(1);
}
O log só imprime um sql
b. Atualize o cache
Os dados em cache são atualizados quando a sessão é enviada
@Test
public void test02() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
sqlSession.clearCache();
accountDao.queryAccountById(1);
}
efeito:
5. Cache secundário
O cache de primeiro nível está no mesmo sqlSession e o cache de segundo nível está no mesmo namespace, portanto, diferentes sqlsessions com o mesmo namespace podem usar o cache de segundo nível.
cenas a serem usadas
- Para dados com alta frequência de consulta e baixa frequência de alteração, é recomendável usar o cache secundário.
- Para pedidos de consulta que são acessados com frequência e os usuários não têm grandes requisitos para resultados de consulta em tempo real, a tecnologia de cache secundário mybatis pode ser usada para reduzir o acesso ao banco de dados e aumentar a velocidade de acesso. Cenários de negócios como: análise estatística demorada sql, contas de telefone Consultar sql etc.
Configuração de arquivo global (mybatis.xml)
<setting name="cacheEnabled" value="true"/>
Mapper.xml 中加入 :打开该 mapper 的二级缓存
<!-- 开启该 mapper 的二级缓存 -->
<cache/>
Atributos comuns da tag de cache
<cache
eviction="FIFO" <!--回收策略为先进先出-->
flushInterval="60000" <!--自动刷新时间 60s-->
size="512" <!--最多缓存 512 个引用对象-->
readOnly="true"/> <!--只读-->
Descrição:
- Todas as instruções de seleção no arquivo de instrução de mapeamento serão armazenadas em cache.
- Todas as instruções de inserção, atualização e exclusão no arquivo de instrução mapeada irão atualizar o cache.
- O cache usará o algoritmo menos usado recentemente (LRU, usado menos recentemente) para recuperar.
- O cache será atualizado de acordo com o intervalo de tempo especificado.
- O cache irá armazenar 1024 objetos
O objeto PO deve suportar serialização
public class User implements Serializable {
}
Desligue o cache de instrução específica no Mapper
Use useCache: o padrão é verdadeiro
<select id="findUserByid" parameterType="int" resultType="User"
useCache="false">
SELECT * FROM user WHERE id=#{id}
</select>
Atualize o cache secundário
Ao operar a instrução CUD, o cache de segundo nível será forçado a atualizar, ou seja, o flushCache padrão = "true". Se você quiser desligar a configuração para flushCache = "false", não é recomendado desligar a atualização, porque a atualização da operação exclui a modificação e é fácil sujar após o fechamento dados.
Teste de cache secundário:
@Test
public void test03() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
sqlSession.close();
SqlSession sqlSession2=sqlSessionFactory.openSession();
AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);
accountDao2.queryAccountById(1);
sqlSession.close();
}
efeito:
Expandir
Cache distribuído ehcache
Se houver vários servidores, o cache distribuído não será usado e os dados em cache serão armazenados separadamente em cada servidor, o que não é conveniente para o desenvolvimento do sistema. Portanto, um cache distribuído deve ser usado para gerenciar centralmente os dados em cache. Portanto, use o ehcache memcached redis
O Mybatis em si não pode alcançar o cache distribuído, então ele precisa ser integrado com o framework de cache distribuído. EhCache é uma estrutura de cache em processo Java pura, que é rápida e capaz; Ehcache é um cache distribuído Java de código aberto amplamente usado. Principalmente para cache de uso geral, Java EE e contêineres leves. Ele possui recursos como memória e armazenamento em disco, carregador de cache, extensão de cache, manipulador de exceção de cache, filtro de servlet de cache gzip e suporta REST e SOAP api.
Dependência de Jar
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache-core</artifactId>
<version>2.4.4</version>
</dependency>
<dependency>
<groupId>org.mybatis.caches</groupId>
<artifactId>mybatis-ehcache</artifactId>
<version>1.0.3</version>
</dependency>
Configuração de interface de cache
<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>
Adicione ehcache.xml sob src (não é necessário, nenhuma configuração padrão é usada)
<?xml version="1.0" encoding="UTF-8"?>
<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="../bin/ehcache.xsd">
<!--
name:Cache 的唯一标识
maxElementsInMemory:内存中最大缓存对象数
maxElementsOnDisk:磁盘中最大缓存对象数,若是 0 表示无穷大
eternal:Element 是否永远不过期,如果为 true,则缓存的数据始终有效,如果为 false
那么还要根据 timeToIdleSeconds,timeToLiveSeconds 判断
overflowToDisk:配置此属性,当内存中 Element 数量达到 maxElementsInMemory 时,
Ehcache 将会 Element 写到磁盘中
timeToIdleSeconds:设置 Element 在失效前的允许闲置时间。仅当 element 不是永久有效
时使用,可选属性,默认值是 0,也就是可闲置时间无穷大
timeToLiveSeconds:设置 Element 在失效前允许存活时间。最大时间介于创建时间和失效
时间之间。仅当 element 不是永久有效时使用,默认是 0.,也就是 element 存活时间无穷
大
diskPersistent:是否缓存虚拟机重启期数据
diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是 120 秒
diskSpoolBufferSizeMB:这个参数设置 DiskStore(磁盘缓存)的缓存区大小。默认是
30MB。每个 Cache 都应该有自己的一个缓冲区
memoryStoreEvictionPolicy:当达到 maxElementsInMemory 限制时,Ehcache 将会根据
指定的策略去清理内存。默认策略是 LRU(最近最少使用)。你可以设置为 FIFO(先进先
出)或是 LFU(较少使用)
-->
<defaultCache overflowToDisk="true" eternal="false"/>
<diskStore path="D:/cache" />
<!--
<cache name="sxtcache" overflowToDisk="true" eternal="false"
timeToIdleSeconds="300" timeToLiveSeconds="600" maxElementsInMemory="1000"
maxElementsOnDisk="10" diskPersistent="true"
diskExpiryThreadIntervalSeconds="300"
diskSpoolBufferSizeMB="100" memoryStoreEvictionPolicy="LRU" />
-->
teste:
@Test
public void test04() {
SqlSession sqlSession=sqlSessionFactory.openSession();
AccountDao accountDao=sqlSession.getMapper(AccountDao.class);
Account account=accountDao.queryAccountById(1);
System.out.println(account);
sqlSession.close();
SqlSession sqlSession2=sqlSessionFactory.openSession();
AccountDao accountDao2=sqlSession2.getMapper(AccountDao.class);
accountDao2.queryAccountById(1);
sqlSession.close();
}
Efeito:
Taxa de acertos do cache [com.xxx.dao.AccountDao]: 0,5