Artigo Diretório
- Prefácio
- endereço do projeto
- 1. Problemas tradicionais de JDBC e soluções de estrutura customizada
- 2. Idéias de design de estrutura de camada de persistência personalizadas
-
- 2.1. Lado do usuário (projeto): apresentar o pacote jar da estrutura de camada de persistência personalizada
- 2.2. A própria estrutura de camada de persistência personalizada (engenharia): a essência é encapsular JDBC
-
- 2.2.1. Leia o arquivo de configuração:
- 2.2.2. Analisando o arquivo de configuração: Eu uso dom4j aqui, mas você também pode usar outros
- 2.2.3 Crie a interface SqlSessionFactory e a classe de implementação DefaultSqlSessionFactory.
- 2.2.4 Criar interface Executor e classe de implementação SimpleExecutor classe de implementação, criar um método de consulta para executar o código JDBC.
- 3.genericTokenParserzheg classe do analisador de tags
- 4. Sobre sqlessionFactoyBuilder, sqlessionFactoy, sqlession.
- 5. Sobre o valor de retorno resultType e parâmetro de entrada paramterType
- 6. Especificação de desenvolvimento de interface em mybatis
- 7. Sobre o conteúdo do código-fonte mybatis
- 8.Mybatis lazy loading, qual é o seu princípio de implementação
- 9. Os três tipos de executor Mybatis, a diferença entre eles
- 10. Caches primário e secundário de Mybatis (cache distribuído não pode ser implementado, uma estrutura de cache de terceiros é necessária)
- 11. Princípio de operação do plug-in Mybatis e como escrever um plug-in
Prefácio
A fonte de saída do conteúdo do artigo: Lagou Education Java High Salary Training Camp. Curso P7
Este artigo faz parte das notas pós-aula no curso de aprendizagem.
endereço do projeto
Código do projeto:
Link: https://pan.baidu.com/s/1pdtE7NkQb1SHQo9RnfSOTw
Código de extração: sc4m
Endereço de nuvem de código: https://gitee.com/nie_jian_ming/njm_all_homework/tree/master/%E7%AC%AC%E4%B8%80%E9%98%B6%E6%AE%B5.%E6%A8% A1% E5% 9D% 97% E4% B8% 80.mybatis% E4% BD% 9C% E4% B8% 9A
1. Problemas tradicionais de JDBC e soluções de estrutura customizada
Perguntas:
1. A criação e liberação frequente de conexões de banco de dados causa desperdício de recursos do sistema e, portanto, afeta o desempenho do sistema.
2. A instrução sql, a passagem de parâmetros e o conjunto de resultados da análise são todos codificados permanentemente.As alterações SQL requerem a alteração do código java, o que torna o código difícil de manter.
Solução:
1. Use o pool de conexão do banco de dados para inicializar os recursos de conexão para resolver o problema de criar e liberar conexões de banco de dados com frequência.
2. Extraia instruções sql em arquivos de configuração xml, use reflexão, introspecção e outras tecnologias subjacentes para mapear automaticamente entidades e tabelas em atributos e campos, reflexão para definir parâmetros e introspecção para retornar resultados Definir pacote.
Padrões de design envolvidos:
padrão de design do construtor, padrão manual (fábrica de sessão), modo proxy (proxy dinâmico JDK para gerar objetos proxy para interface Dao)
2. Idéias de design de estrutura de camada de persistência personalizadas
2.1. Lado do usuário (projeto): apresentar o pacote jar da estrutura de camada de persistência personalizada
- Fornece duas partes das informações de configuração: informações de configuração do banco de dados, informações de configuração sql (instrução sql, tipo de parâmetro, tipo de valor de retorno)
- Use o arquivo de configuração para fornecer essas duas partes das informações de configuração:
1.sqlMapConfig.xml: armazenar informações de configuração do banco de dados, importar mapper.xml.
2.mapper.xml: armazena informações de configuração do sql.
2.2. A própria estrutura de camada de persistência personalizada (engenharia): a essência é encapsular JDBC
2.2.1. Leia o arquivo de configuração:
- Crie uma classe para carregar o arquivo de configuração em um fluxo de entrada de bytes de acordo com o caminho do arquivo de configuração e armazene-o na memória.
Etapas de implementação : Criar uma classe Recursos, método de carregamento: InputSteam getResourceAsSteam (String path)
As informações de configuração lidas são armazenadas na memória na forma de um fluxo, que não é fácil de operar. Aqui, dois javaBeans (objetos contêiner) são criados para o pensamento orientado a objetos: Armazene o conteúdo analisado do arquivo de configuração, que também é conveniente para acesso posterior.
Etapas de implementação : Crie duas classes de configuração
Configuração : Classe de configuração principal: armazene o conteúdo analisado por sqlMapConfig.xml, armazene informações básicas do banco de dados, Map <only ID, Mapper> ID exclusivo: namespace + "." + Id
MappedStatement : mapeamento Configuração classe: armazena o conteúdo analisado por mapper.xml, armazena instrução sql, tipo de instrução, parâmetro de entrada tipo java, parâmetro de saída tipo java
2.2.2. Analisando o arquivo de configuração: Eu uso dom4j aqui, mas você também pode usar outros
Etapas de implementação:
Crie a classe SqlSessionFactoryBuilder e, em seguida, crie um método: build (InputSteam em) para construir a fábrica de sessão.
Duas coisas são implementadas no método de construção:
1. Use dom4j para analisar o arquivo de configuração e encapsular o conteúdo analisado em um objeto recipiente.
2. Crie o objeto SqlSessionFactory (modo de fábrica); produza o objeto de sessão sqlSession
2.2.3 Crie a interface SqlSessionFactory e a classe de implementação DefaultSqlSessionFactory.
Em seguida, crie a interface SqlSessionFactory e a classe de implementação DefaultSqlSessionFactory com base no princípio de abertura e fechamento. Escreva um método para produzir sqlSession.
Método: openSession () // Obter o objeto de instância da classe de implementação da
interface sqlSession Lembre-se de criar a interface sqlSession e a classe de implementação DefaultSqlSession para encapsular o método CRUD do JDBC.
2.2.4 Criar interface Executor e classe de implementação SimpleExecutor classe de implementação, criar um método de consulta para executar o código JDBC.
Método: consulta (Configuration, MappedStatement, Object ... params);
Configuração : Ao usar dom4j para analisar sqlMapConfig.xml, o conteúdo analisado será encapsulado no objeto de configuração em diferentes formas, e as informações na configuração do banco de dados são armazenadas dentro .
MappedStatement : Ao usar dom4j para analisar mapper.xml, o conteúdo de cada tag corresponde a um objeto mappedStatement, que armazena a informação SQL
Object ... params : Este é o parâmetro passado pelo usuário, porque não tem certeza de quantos será usado. Então, objeto ... Parâmetros variáveis
3.genericTokenParserzheg classe do analisador de tags
- Esta classe só pode ser criada por meio de construção parametrizada
- genericTokenParser é uma classe de analisador de token genérico
- Quando genericTokenParser analisa # {} marcadores de posição, ele deve cooperar com tokenHandler
- Os três parâmetros de construção de genericTokenParser são tag de início, tag final e processador de tag
4. Sobre sqlessionFactoyBuilder, sqlessionFactoy, sqlession.
- O melhor escopo de sqlessionFactoyBuilder é o escopo do método, que pode ser definido como uma variável de método local
- A melhor gama de sqlessionFactoy é a gama de aplicação
- O melhor escopo de sqlession é o escopo do método ou o escopo da solicitação
5. Sobre o valor de retorno resultType e parâmetro de entrada paramterType
- O tipo de valor de retorno de resultType é: nome completo da classe ou alias, tipos de dados básicos são permitidos, String, int, etc.
- A estrutura de dados de resultType e resultMap é a mesma, ambos são estruturas de mapa
- Em mybatis, além de usar a anotação @param para implementar a entrada de vários parâmetros, você também pode usar o objeto Map para implementar a transferência de vários parâmetros
6. Especificação de desenvolvimento de interface em mybatis
- O namespace em mapper.xml é o mesmo que o classpath da interface do mapeador
- O nome do método da interface do mapeador é o mesmo que a id de cada instrução definida em mapper.xml
- O tipo de parâmetro de entrada do método de interface do mapeador é o mesmo que o tipo parameterType de cada SQL definido em mapper.xml
- O tipo de parâmetro de saída do método de interface do mapeador é igual ao tipo resultType de cada sql definido em mapper.xml
7. Sobre o conteúdo do código-fonte mybatis
- Os padrões de design envolvidos são: modelo de agente, modelo de construtor (construtor / construtor), modelo de fábrica, modelo de iterador
- A arquitetura funcional pode ser dividida em três camadas: camada de interface, camada de processamento de dados, camada de suporte de estrutura
- Suporta plug-ins para interceptar objetos principais, como statementHandler, paramterHandle e resultsHandler
- Executor é o executor, responsável pela geração de sql e manutenção de cache de consulta
- statementtHandler encapsula operações de instrução jdbc (a interface para executar banco de dados sql) e é responsável pela operação da instrução jdbc
- typeHandler é responsável pelo mapeamento e conversão entre os tipos de dados java e jdbc
- sqlSource é responsável por produzir dinamicamente instruções SQL de acordo com o parâmetroObject passado pelo usuário e encapsular as informações no objeto boundsql ()
8.Mybatis lazy loading, qual é o seu princípio de implementação
Mybatis suporta o carregamento lento e
só suporta o carregamento lento de objetos de associação e objetos de coleção;
associação se refere a um-para-um e coleção se refere a uma consulta um-para-muitos.
No arquivo de configuração, você pode definir se deseja ativar o carregamento lento lazyLoadingEnabled = true | false.
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载,即延迟加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
Princípio de implementação
Use CGLIB para criar o objeto proxy do objeto alvo.Quando o método alvo é chamado, ele entra no
métodointerceptor, e quando os dados são necessários, ele chama SQL para consultar o BD.
Por exemplo: quando a.getB (). GetName () é chamado, o método invoke () do interceptor descobre que a.getB () é um
valor nulo, então ele enviará separadamente o sql salvo antecipadamente para consultar o objeto B associado e consulte B. Em seguida, chame a.setB (b), de modo que o atributo do objeto b de a tenha um valor e, em seguida, conclua a chamada do método a.getB (). getName ().
9. Os três tipos de executor Mybatis, a diferença entre eles
O padrão é SimplExcutor
SimpleExecutor: toda vez que uma atualização ou seleção é executada, um objeto Statement é aberto e o objeto Statement é fechado imediatamente após o uso.
ReuseExecutor: Execute update ou select, use sql como a chave para encontrar o objeto Statement, use-o se ele existir e crie-o se ele não existir. Após o uso, o objeto Statement não é fechado, mas colocado no Mapa para o próximo uso.
Resumindo, é reutilizar o objeto Statement.
BatchExecutor: executa atualização (sem seleção, processamento em lote JDBC não suporta seleção), adiciona todos os sql ao lote addBatch (), aguarda a execução unificada de executeBatch (), ele armazena em cache vários objetos de Instrução, cada objeto de Instrução é Após addBatch ( ) for concluído, aguarde o processamento em lote executeBatch (), um por um.
Igual ao processamento em lote JDBC.
Escopo de ação: essas características do Executor são estritamente limitadas ao escopo do ciclo de vida do SqlSession.
No arquivo de configuração Mybatis, você pode especificar o tipo de atuador ExecutorType padrão ou pode passar manualmente o parâmetro de tipo ExecutorType para o método de criação de SqlSession de DefaultSqlSessionFactory.
10. Caches primário e secundário de Mybatis (cache distribuído não pode ser implementado, uma estrutura de cache de terceiros é necessária)
1. Estrutura de armazenamento: o cache de primeiro nível e o cache de segundo nível são todos armazenados em cache na estrutura HashMap.
2. Escopo: O
cache de primeiro nível está no nível SqlSession e o escopo é SqlSession. Mybatis ativa o cache de primeiro nível por padrão. Na mesma SqlSession, quando o mesmo Sql é consultado, a primeira consulta será tirada do cache Se não houver dados, consulte-os no banco de dados e armazene-os em cache no HashMap. A segunda consulta é buscada diretamente no cache e, se houver dados, eles são retornados diretamente, sem verificar o banco de dados.
O cache de segundo nível está no nível do mapeador. Várias SqlSessions operam na mesma instrução SQL do mapeador. Várias SqlSessions podem compartilhar o cache de segundo nível. O cache de segundo nível está entre SqlSessions.
Quando o sql under mapper é chamado pela primeira vez, as informações são consultadas. As informações consultadas serão armazenadas na área de cache secundária correspondente ao mapeador. Na segunda vez, o arquivo de mapeamento do mapeador sob o namespace é chamado, o mesmo SQL é usado para consultar diretamente. Busque o resultado no cache secundário.
3. Cenário de invalidação:
Quando o cache de primeiro nível é adicionado, excluído ou modificado, o cache será invalidado.
No gerenciamento de container Spring, cada consulta cria uma nova sqlSession, portanto, não haverá inconsistência de dados em um ambiente distribuído.
Ao usar o cache de segundo nível, você precisa abrir a tag de cache, adicionar o atributo useCache para true na seleção e habilitar manualmente flushCache para atualizar o cache ao atualizar e excluir. Se useCache = false for definido, o cache de segundo nível será desativado.
11. Princípio de operação do plug-in Mybatis e como escrever um plug-in
Os métodos de interceptação permitidos por MyBatis são os seguintes:
Executor: ( métodos de atualização, consulta, confirmação, reversão, etc.);
construtor de sintaxe SQL StatementHandler: ( métodos de preparação, parametrização, lote, consulta de atualizações, etc.);
processador de parâmetros ParameterHandler : (getParameterObject, método setParameters);
ResultSetHandler: (métodos handleResultSets, handleOutputParameters, etc.);
1. Princípio operacional:
Mybatis pode escrever plug-ins para as quatro interfaces de Executor, StatementHandler, ParameterHandler e ResultSetHandler. Mybatis usa o proxy dinâmico de JDK para gerar objetos de proxy para as interfaces que precisam ser interceptadas e, em seguida, implementa a interceptação método da interface, então quando a execução precisa ser interceptada Quando o método da interface, ele entrará no método de interceptação (pensamento AOP).
2. Como escrever:
1. Escreva a classe de implementação da interface do Intercepror
2. Defina a assinatura do plug-in, diga ao mybatis qual método de qual objeto interceptar
3. Finalmente, registre o plug-in no arquivo de configuração global
Exemplo:
package com.njm.plugin;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;
//插件签名,告诉mybatis当前插件拦截哪个对象的哪个方法
@Intercepts({ //这是个⼤花括号,也就这说这⾥可以定义多个@Signature,对多个地⽅拦截,都⽤这个拦截器
/*
type:表示要拦截的核心(目标)对象,拦截哪个接⼝,StatementHandler是一个sql语句构建器,用来完成sql语句预处理
method:表示要要拦截的方法,prepare是StatementHandler里的sql预编译方法
args:表示要拦截方法的参数,按方法里的参数顺序写,可能方法有重载,所以要通过⽅法名和⼊参来确定唯⼀。
*/
@Signature(type = StatementHandler.class,
method = "prepare",
args = {Connection.class,Integer.class})
})
public class MyPlugin implements Interceptor {
//截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
/*
* 插件的主要功能:在执行目标方法之前,可以对sql进行修改已完成特定的功能
* 例如增加分页功能,实际就是给sql语句添加limit;还有其他等等操作都可以
* */
System.out.println("对方法进行了增强。。。。。。。");
return invocation.proceed(); //invocation.proceed():原方法执行并返回值
}
//主要为了把当前的拦截器生成代理存到拦截器链中,包装目标对象,为目标对象创建代理对象
@Override
public Object plugin(Object target) {
//target:被拦截的目标对象,this:表示当前自定义的插件实现类,当前拦截器,也就是现在这个类,
//wrap方法利用mybatis封装的方法为目标对象创建代理对象(没有拦截的对象会直接返回,不会创建代理对象)
Object wrap = Plugin.wrap(target, this);
return wrap;
}
//获取配置文件的参数,就是获取插件在配置文件中配置的参数值
//插件初始化的时候调⽤,也只调⽤⼀次,插件配置的属性从这⾥设置进来
@Override
public void setProperties(Properties properties) {
System.out.println("获取到的配置文件的参数是:"+properties);
}
}
O plugin está registrado no arquivo de configuração global
<!--配置自定义插件类
interceptor:配置类的路径
property:配置的参数-->
<plugins>
<!--这个是我自定义的插件-->
<plugin interceptor="com.njm.plugin.MyPlugin">
<property name="name" value="tom"/>
</plugin>
<!--这是分页插件,上面的是我自定义的插件-->
<!-- <plugin interceptor="com.github.pagehelper.PageHelper">-->
<!--指定方言-->
<!-- <property name="dialect" value="mysql"/>-->
<!-- </plugin>-->
</plugins>