Fale sobre o cache primário e o cache secundário de Mybatis

Cache de nível 1

Mybatis suporta cache. Por padrão, o cache de primeiro nível está ativado. O cache de primeiro nível está no nível SqlSession , e o cache é o objeto SqlSession. Quando a instrução SQL e os parâmetros são os mesmos, quando usamos o mesmo objeto SqlSession para chamar o mesmo método Mapper, só precisamos executar SQL uma vez, porque após a primeira execução do método Mapper, Mybatis irá armazená-lo em cache e consultá-lo mais tarde Se os parâmetros e instruções SQL forem iguais, os dados em cache serão buscados diretamente em vez de consultar o banco de dados, o que melhora muito a eficiência da consulta.

Aqui estão os diagramas de cache de outras pessoas, que são claros e claros!

 O ciclo de vida do cache de primeiro nível

  • O cache de primeiro nível MyBatis é baseado em SQLSession.Quando MyBatis abre uma sessão de banco de dados, ele irá criar um novo objeto SqlSession, e haverá um novo objeto Executor no objeto SqlSession. O objeto Executor contém um novo objeto PerpetualCache; quando a sessão termina, o objeto SqlSession e seus objetos Executor internos e objetos PerpetualCache também são liberados.
  • Se SqlSession chamar o método close (), o objeto PerpetualCache do cache de primeiro nível será liberado e o cache de primeiro nível ficará indisponível.
  • Se SqlSession chamar clearCache (), os dados no objeto PerpetualCache serão limpos, mas o objeto ainda pode ser usado.
  • Qualquer operação de atualização (update (), delete (), insert ()) realizada em SqlSession irá limpar os dados do objeto PerpetualCache, mas o objeto pode continuar a ser usado

Condição de disparo de cache de nível 1

  1. O statementId de entrada é o mesmo
  2. O intervalo de resultados no conjunto de resultados necessário para a consulta é o mesmo
  3. A string de instrução SqlPreparedstatement (boundSql.getSql ()) que é finalmente passada para JDBC java.sql. Produzida por esta consulta é a mesma
  4. Os valores dos parâmetros passados ​​para java.sql.Statement a serem definidos são os mesmos

Casos de uso de cache de primeiro nível

Em primeiro lugar, a classe de entidade ( observação: precisa ser serializável, implementei a interface serializável aqui )

public class TtUser implements Serializable{
    private Long id;
    private String loginName;
    private String password;

    // 这里省略get、set方法
}

 método dao

public interface TtUserMapper {
    TtUser selectByPrimaryKey(Long id);
    int updateByPrimaryKeySelective(TtUser record);
}

método mapper.xml

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.xiateng.dao.user.TtUserMapper">

  <!--<cache eviction="LRU" flushInterval="10000" size="1024"  />-->

  <resultMap id="BaseResultMap" type="com.xiateng.entity.TtUser">
    <id column="id" jdbcType="BIGINT" property="id" />
    <result column="login_name" jdbcType="VARCHAR" property="loginName" />
    <result column="password" jdbcType="VARCHAR" property="password" />
  </resultMap>

  <sql id="Base_Column_List">
    id, login_name, password
  </sql>
  <select id="selectByPrimaryKey" parameterType="java.lang.Long" resultMap="BaseResultMap">
    select 
    <include refid="Base_Column_List" />
    from t_user
    where id = #{id,jdbcType=BIGINT}
  </select>
  
  <update id="updateByPrimaryKeySelective" parameterType="com.xiateng.entity.TtUser">
    update t_user
    <set>
      <if test="loginName != null">
        login_name = #{loginName,jdbcType=VARCHAR},
      </if>
      <if test="password != null">
        password = #{password,jdbcType=VARCHAR},
      </if>
      <if test="blong != null">
        blong = #{blong,jdbcType=SMALLINT},
      </if>
    </set>
    where id = #{id,jdbcType=BIGINT}
  </update>
  
</mapper>

Chamada de controlador

@RequestMapping(value = "/a")
    @ResponseBody
    public String a(){
        // 开启一个SqlSession(会话)
        SqlSession sqlSession = sqlSessionFactory.openSession();
        TtUserMapper mapper = sqlSession.getMapper(TtUserMapper.class);
        TtUser ttUser = mapper.selectByPrimaryKey(1L);
        System.out.println("-----------------------------------------"+ttUser);
        System.out.println("-----------------------------------------第二次执行");
        TtUser ttUser2 = mapper.selectByPrimaryKey(1L);
        System.out.println("-----------------------------------------"+ttUser2);
        // 关闭会话
        sqlSession.close();
        return "成功";
    }

 Impressão de console

Veremos que sql só é impresso uma vez, indicando que o banco de dados não foi consultado na segunda vez 

 Cache secundário

O cache de segundo nível é o cache do objeto SqlSessionFactory em Mybatis. A SqlSession criada pelo mesmo objeto SqlSessionFactory compartilha seu cache, mas os dados em cache não são o objeto, então o resultado da segunda consulta do cache de segundo nível é o mesmo que o
primeiro. Os objetos de entrada não são os mesmos. O cache de segundo nível é o cache de nível de namespace ,

Olha a foto

Preste atenção ao uso de cache secundário

  • 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 de mapeamento atualizarão o cache.
  • O cache será recuperado usando o algoritmo menos usado recentemente (LRU) padrão.
  • De acordo com a programação, como Sem intervalo de liberação (CNFI não tem intervalo de atualização), o cache não será liberado em nenhuma ordem cronológica.
  • O cache armazenará 1024 referências para listar coleções ou objetos (não importa o que o método de consulta retorne)
  • O cache será considerado como um cache de leitura / gravação (leitura / gravação), o que significa que a recuperação do objeto não é compartilhada e pode ser modificada com segurança pelo responsável pela chamada, sem interferir com possíveis modificações feitas por outros chamadores ou threads.

Mybatis não habilita o cache de segundo nível por padrão. Se você quiser habilitá-lo, você precisa configurá-lo, e o POJO retornado deve ser serializável (a classe de entidade implementa Serializable). Vamos dar um exemplo:

As entidades e métodos ainda são os anteriores, mas adicione a configuração <cache /> em mapper.xml como segue

<cache eviction="LRU" flushInterval="100000" readOnly="true" size="1024"/>

Significado da propriedade:

  • despejo: Representa a estratégia de recuperação de cache.Atualmente MyBatis fornece as seguintes estratégias.
  1. LRU, o menos usado recentemente, um objeto que não é usado há mais tempo
  2. FIFO, primeiro a entrar, primeiro a sair, remove os objetos na ordem em que entram no cache
  3. SOFT, referência flexível, remove objetos com base no status do coletor de lixo e regras de referência flexível
  4. FRACA, referência fraca, remove objetos mais ativamente com base no status do coletor de lixo e regras de referência fraca. LRU é usado aqui para remover a imagem do par que não é usada por mais tempo. FlushInterval: tempo de intervalo de atualização, em milissegundos, aqui está configurado para atualizar em 100 segundos, se você não configurar, ele será atualizado quando SQL é executado o Cache.
  • size: O número de referências, um número inteiro positivo, que representa o número máximo de objetos que o cache pode armazenar e não deve ser definido muito grande. Muita configuração causará estouro de memória. 1.024 objetos são configurados aqui
  • readOnly: somente leitura, o que significa que os dados em cache só podem ser lidos, mas não modificados. A vantagem dessa configuração é que podemos ler o cache rapidamente. A desvantagem é que não temos como modificar o cache. Seu valor padrão é falso, o que não nos permite modificá-lo.

Em seguida, configure Mybatis para ativar o cache secundário, porque sou um projeto SpringBoot, então adicionei a seguinte configuração ao arquivo application.yml:

Finalmente teste o código do controlador

    @RequestMapping(value = "/b")
    @ResponseBody
    public Map<String, Object> b(){
        Map map = new HashMap();
        TtUser ttUser = ttUserMapper.selectByPrimaryKey(1L);
        map.put("ttUser",ttUser);
        System.out.println("-----------------------------------------"+ttUser);
        System.out.println("-----------------------------------------第二次执行");
        TtUser ttUser2 = ttUserMapper.selectByPrimaryKey(1L);
        map.put("ttUser2",ttUser2);
        System.out.println("-----------------------------------------"+ttUser2);
        System.out.println("-----------------------------------------第三次执行");
        TtUser ttUser3 = ttUserMapper.selectByPrimaryKey(2L);
        System.out.println("-----------------------------------------"+ttUser3);
        map.put("ttUser3",ttUser3);
        return map;
    }

Resultado de impressão

A partir dos resultados de impressão, descobriremos que a primeira consulta imprimiu a instrução sql, ela consultou diretamente o banco de dados, a segunda consulta não imprimiu a instrução sql, porque os parâmetros da segunda vez, statementId, sql são os mesmos, atinge diretamente o cache secundário. Não há consulta de banco de dados e na terceira vez os parâmetros são diferentes, a instrução sql é impressa e o banco de dados é consultado diretamente

A diferença entre o cache de primeiro nível e o cache de segundo nível

Cache de nível 1 : habilitado por padrão, baseado em SQLSession, o objeto SQLSession precisa ser construído ao operar o banco de dados, há um HashMap no objeto para armazenar dados em cache e diferentes SQLSessions não são afetados diretamente. Adições, exclusões e alterações são executadas em uma SQLSession e enviadas ao banco de dados.O cache de primeiro nível será esvaziado para evitar leituras sujas.

Quando uma sqlsession é fechada, o cache de primeiro nível também desaparece.

Cache secundário : desativado por padrão. Com base no namespace, várias SQLSessions no mesmo namespace compartilharão um cache. O cache secundário também usa HashMap para armazenamento de dados. Comparado com o cache primário, o cache secundário tem um escopo maior e pode abranger vários SQLSessions.

Acho que você gosta

Origin blog.csdn.net/qq_43037478/article/details/112311351
Recomendado
Clasificación