Prefácio
O que é o cache Mybatis Nível 2?
O cache secundário é compartilhado por múltiplas sqlsessions e seu escopo é o mesmo espaço para nome do mapeador.
Ou seja, em diferentes sqlSessions, no mesmo espaço de nome, a mesma instrução SQL e os parâmetros no modelo SQL também são os mesmos, e o cache será atingido.
Após a primeira execução, os dados consultados no banco de dados serão gravados no cache, e os dados serão recuperados do cache não serão mais consultados no banco de dados, melhorando assim a eficiência da consulta.
Mybatis não habilita o cache secundário por padrão, e é necessário ativar o cache secundário na configuração global (mybatis-config.xml).
Este artigo descreve o método de usar o Redis como um cache para se integrar ao Springboot e Mybatis.
1. Dependência do POM
Use o pacote de integração Redis Redis para facilitar o acesso ao Redis. Jedis é usado no cliente Redis.
Além disso, os caches de leitura e gravação de KV serão serializados, para que um pacote de serialização seja introduzido.
<Depencency> <PuerpId> org.springframework.boot </frugiD> <stifactId> primavera-boot-starter-redis </starfactid> </dependency> <pendence> <purifactid> Redis.clients </Groupid> <TarifactId> jedis </Artifactid> <ersipers> 2./Version> </grupo> <PuerpId> com.alibaba </frugiD> <ArtifactId> fastjson </sutifactId> <versão> 1.2.19 </versão> </dependency>
Após a conclusão da dependência, a próxima etapa é ajustar o cliente Redis.
2. Beans usados pelo Redis Access
Adicione a configuração, configure o feijão JedisconnectionFactory e deixe -o usar posteriormente.
De um modo geral, um feijão Redistemplate também será gerado, mas não será usado no próximo cenário.
@ConfigurationPublic Class Redisconfig {@Value ("$ {spring.redis.host}") host private string; // O espaço é limitado, @Bean Public JedispoolConfig GetRredisconfig () {JedispoolConfig config = new JedispoolConfig (); config.setmaxidle (maxidle); config.setmaxtotal (maxtotal); config.setmaxwaitmillis (maxwaitmillis); config.setminidle (minidle); return config; } @Bean (name = "JedisconnectionFactory") public JedisconnectionFactory getConnectionFactory () {JedisconnectionFactory Factory = new JedisconnectionFactory (); JedispoolConfig config = getredisconfig (); Factory.SetPoolConfig (config); Factory.SethostName (host); Factory.SetPort (porta); Factory.SetDatabase (banco de dados); Factory.SetPassword (senha); Factory.SetTimeout (Timeout); fábrica de retorno; } @Bean (name = "Redistemplate") public redistemplate <?,?> Getredistemplate () {redistemplate <? ,?> model = new StringReDistemplate (getConnectionFactory ()); modelo de retorno; }}Aqui, o @Value é usado para ler a configuração relacionada ao Redis e existe um método de leitura de configuração mais simples (@ConfigurationProperties (prefix = ...)), que você pode tentar.
As configurações relacionadas a Redis são as seguintes
#redisspring.redis.host = 10.93.84.53spring.redis.port = 6379spring.redis.password = bigdata123spring.redis.database = 15spring.redis. timeout = 0spring.redis.pool.maxtotal = 8spring.redis.pool.maxwaitmillis = 1000spring.redis.pool.maxidle = 8spring.redis.pool.minidle = 0
O significado de configuração do cliente Redis não será explicado aqui. Relacionados à piscina geralmente estão relacionados ao desempenho e eles precisam ser definidos com base na quantidade de concorrência de alças, memória e outros recursos.
O cliente Redis foi configurado e começamos a configurar o Redis como o cache para Mybatis.
3. Cache mybatis
Esta etapa é a etapa mais crítica. O método de implementação é implementar um interface org.apache.ibatis.cache.cache de mybatis.
Esta interface designs grava cache, leia o cache, destrua o cache e o controle de acesso de controle e escreva bloqueios.
A classe que implementamos para implementar a interface do cache é o MyBatisRediscAche.
Mybatisrediscache.java
classe pública mybatisrediscache implementa cache {private estático jedisconnectionfactory jedisconnectionFactory; ID de string final privado; Private final ReadWritelock ReadWritelock = new ReentrantreadWritelock (); public myBatisRediscAche (Final String ID) {if (id == null) {lança nova ilegalargumentException ("instâncias de cache requerem um id"); } this.id = id; } @Override public void clear () {Redisconnection Connection = null; tente {conexão = jedisconnectionFactory.getConnection (); conexão.flushdb (); Connection.flushall (); } catch (jedisconnectionException e) {e.printStackTrace (); } finalmente {if (conexão! = null) {conexão.close (); }}} @Override public String getId () {return this.id; } @Override Public Object getObject (chave do objeto) {objeto resultado = null; Conexão de redisconnection = null; tente {conexão = jedisconnectionFactory.getConnection (); Redisserializer <ject> serializador = new jdkserializationRedisSerializer (); resultado = serializer.Deserialize (Connection.get (serializer.Serialize (Key))); } catch (jedisconnectionException e) {e.printStackTrace (); } finalmente {if (conexão! = null) {conexão.close (); }} Retornar resultado; } @Override public readWritelock getReadWritelock () {return this.readWritelock; } @Override public int getSize () {int resultado = 0; Conexão de redisconnection = null; tente {conexão = jedisconnectionFactory.getConnection (); resultado = integer.valueof (conexão.dbsize (). tostring ()); } catch (jedisconnectionException e) {e.printStackTrace (); } finalmente {if (conexão! = null) {conexão.close (); }} Retornar resultado; } @Override public void putObject (chave do objeto, valor do objeto) {Redisconnection Connection = null; tente {conexão = jedisconnectionFactory.getConnection (); Redisserializer <ject> serializador = new jdkserializationRedisSerializer (); Connection.set (serializer.serialize (key), serializer.serialize (valor)); } catch (jedisconnectionException e) {e.printStackTrace (); } finalmente {if (conexão! = null) {conexão.close (); }}} @Override Public Object RemepObject (chave do objeto) {Redisconnection Connection = null; Resultado do objeto = nulo; tente {conexão = jedisconnectionFactory.getConnection (); Redisserializer <ject> serializador = new jdkserializationRedisSerializer (); resultado = conexão.Expire (serializer.Serialize (chave), 0); } catch (jedisconnectionException e) {e.printStackTrace (); } finalmente {if (conexão! = null) {conexão.close (); }} Retornar resultado; } public static void setjedisconnectionFactory (JedisconnectionFactory JedisconnectionFactory) {mybatisRediscache.jedisconnectionFactory = JedisconnectionFactory; }}Perceber:
Como você pode ver, esta classe não é uma classe gerenciada pela Spring Virtual Machine, mas existe uma propriedade estática que o JedisconnectionFactory requer injeção de um feijão de mola, ou seja, o feijão gerado no Redisconfig.
Em uma aula normal, o Spring Contextware é geralmente usado para usar o SpringContextaware introspectivo de troca de troca.
Outro método é usado aqui, injeção estática. Este método é implementado por meio de rediscachetransfer.
4. Injeção estática
RediscacheTransfer.java
@ComPonentPublic Classe RediscacheTransfer {@AUTOWIRED Public void SetjedisconnectionFactory (JedisconnectionFactory JedisconnectionFactory) {myBatisRediscache.setjedisconnectionFactory (JedisconnectionFactory); }}Você pode ver que o RediscacheTransfer é um feijão de trampolim. Ao inicializar o contêiner no início da criação, o feijão JedisconnectionFactory será injetado na passagem do parâmetro do método SetJedisconnectionFactory.
O setjedisconnectionFactory define a propriedade estática da classe MyBatisRediscache chamando um método estático.
Isso injeta o JedisconnectionFactory gerenciado pelo recipiente de mola no domínio estático.
Nesse ponto, o código foi basicamente concluído e a seguir estão algumas configurações. Os principais são (1) o interruptor global; (2) interruptor de escopo de espaço para nome; (3) serialização da instância do modelo.
5. A mudança global do cache Mybatis Nível 2
Como mencionado anteriormente, o cache de nível 2 padrão não está ativado e precisa ser definido como true. Esta é a chave para o cache global de nível 2.
Configuração global mybatis.
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration> <!-- Global Parameters--> <settings> <!-- Make the Mapper global Ative ou desative o cache. -> <Configuração name = "Cacheenabled" value = "true"/> </fastings> </figuration>
O carregamento de configurações globais no DataSource pode ser assim.
bean.setMapperLocations (novo PathMatchingResourcePatternResolver (). GetResources ("ClassPath: Mybatis-Mapper/*. Xml"));
Especifica o caminho de armazenamento do mapper.xml. Sob o caminho Mybatis-Mapper, todos os sufixos com .xml serão lidos.
bean.setConfigLocation (new ClassPathResource ("mybatis-config.xml"));
O caminho de armazenamento do mybatis-config.xml é especificado e colocado diretamente no diretório de recursos.
@Bean (name = "MoonlightSqlSessionFactory") @Primary Public SQLSessionFactory MoonlightSqlSessionFactory (@qualifier ("MoonlightData") DataSource DataSource) lança exceção {SQLSessionFactoryBean Bean = New SQLSessionFactoryBean (); bean.setDataSource (DataSource); bean.setMapperLocations (novo PathMatchingResourcePatternResolver (). GetResources ("ClassPath: Mybatis-Mapper/*. Xml")); bean.setConfigLocation (new ClassPathResource ("mybatis-config.xml")); return bean.getObject (); }6. Configurar namespace de escopo do mapeador
Como mencionado anteriormente, o escopo do cache secundário é o espaço para nome do mapeador, então essa configuração precisa ser escrita no mapeador.
<Mapper namespace = "com.kangaroo.studio.moonlight.dao.mapper.moonlightmapper"> <cache type = "com.kangaroo.studio.moonlight.dao.cache.mybatisrediscache"/> <resultmap id = "geofencelist" type = "com.kangaroo.studio.moonlight.dao.model.geofence"> <construtor> <idarg column = "id" javatype = "java.lang.integer" jdbctype = "integger" /> <argn = "name" javaty = javatpa. java.ntyang ". column = "type" javatype = "java.lang.integer" jdbctype = "intoger" /> <arg column = "group" javatype = "java.lang.string" jdbctype = "var" /> <Arg. Column = "CreateTime" Javatype = "java.lang.string" jdbctype = "varchar" /> <arg column = "updateTime" javatype = "java.lang.string" jdbctype = "varchar" /> < /construtor> < /resultado <leclet> <leclect = "wost =" "varchar" /> < /construtor> < /resultado <letmap> parameterType = "com.kangaroo.studio.moonlight.dao.model.geofenceQueryParam" resultMap = "geofencelist"> selecione <incluir refid = "base_column"/> de geofiance onde 1 = 1 <se test! concat ('%', #{name}, '%') </if> <if test = "group! = null"> e `group` como concat ('%', #{group}, '%') </if> <se test =" starttime! = null "> e createTime> = #{starttime} </se> <se> <ffortTime! </if> </leclect> </palpper>Perceber:
A tag de cache no espaço para nome é a configuração do cache de carregamento, e o uso do cache é oficialmente implementado pelo MyBatisRediscache que acabamos de implementar.
<cache type = "com.kangaroo.studio.moonlight.dao.cache.mybatisrediscache"/>
Apenas uma consulta de consulta é implementada aqui. Você pode ligar ou desligar o cache deste SQL na tag Selecionar. Use o valor da propriedade Usecache = true/false.
7. Mapper e Model
Leia e escreva o modelo de cache precisa ser serializado: ele só precisa implementar a interface da seriaziável quando a classe é declarada.
public class Geofiance implementa serializável {// Setter e getter omitido} classe pública geofenceparam implementa serializável {// setter e getter omitido}O mapeador ainda é o mesmo de antes. Ao usar o mapper.xml, você só precisa definir funções abstratas.
@MapperPublic Interface Moonlightmapper {List <Geofence> QuerygeoFence (GeofenceQueryParam GeofenceQueryParam);}Neste ponto, todo o código e configuração são concluídos, vamos testá -lo abaixo.
8. Teste
Uma postagem de interface é implementada no controlador.
@RequestMapping (Value = "/Fence/Query", Method = requestMethod.Post) @ResponsoBody Public ResponsityEntity <swermE> queryfence (@RequestBody GeofenceQueryparam GeofenceQueryParam) {Try {Integer pagenum = geofenceeryeryParam.getPagenum ()! Inteiro pageSize = geofenceQueryParam.getPagesize ()! = Null? GeofenceQueryParam.getPagesize (): 10; PageHelper.StartPage (Pagenum, Pagesize); Lista <GEOFENCE> LIST = Moonlightmapper.QuerygeoFence (GeofenceQueryParam); retornar nova resposta de resposta <> (nova resposta (resultadocode.success, "consulta geofence sucem", list), httpstatus.ok); } Catch (Exceção e) {Logger.error ("Query Geofence Failed", e); retornar nova resposta de resposta <> (nova resposta (resultadocode.exception, "falha na falha na consulta", null), httpstatus.internal_server_error); }Use Curl para enviar solicitações, nota
1) -H -Tipo de conteúdo: Método Aplicativo/JSON
2) -D - a seguir é o pacote de parâmetros no formato JSON
CURL -H "Tipo de Conteúdo: Application/JSON" -xpost http: //. . . /Moonlight/cerca/consulta -d '{"name": "teste", "grupo": "teste", "tipo": 1, "starttime": "2017-12-06 00:00:00", "finaltime": "2017-12-06 16:00:00", "pagenum": 1, "Pages": 8: 8:Solicitado três vezes, o tronco é impresso da seguinte forma
Como você pode ver, apenas a primeira vez que a consulta do modelo SQL foi executada e o cache foi atingido.
Em nosso ambiente de teste, devido à quantidade relativamente pequena de dados, a otimização do cache da velocidade da consulta não é óbvia. Não vou explicar muito aqui.