(3) MyBatis desde a entrada até o uso detalhado do solo

Este é o terceiro artigo da série mybatis. Se você não leu as sugestões anteriores, primeiro vá para a conta pública do [Java Tsuka Fox] para ver os artigos anteriores, o que é conveniente para compreensão e compreensão.

Explicação detalhada do uso de MyBatis

No último artigo, desenvolvemos manualmente um projeto MyBatis, mas apenas escrevemos o código. Não analisamos e explicamos cuidadosamente como todo o projeto funciona e o significado de cada código. Em seguida, começaremos a analisar o significado de cada código. E como escrever este código

Configurar o arquivo de configuração global MyBatis

Para usar o Mybatis para operar o banco de dados, então é claro que você precisa configurar as informações relacionadas ao banco de dados, o que precisa ser feito no arquivo de configuração global mybatis. Ou seja, o arquivo xml de configuração global, que configura informações como suporte a transações e configuração de banco de dados para todo o MyBatis. Geralmente o colocamos no arquivo principal / de recursos, conforme mostrado abaixo

<configuration>
    <!-- 环境配置,可以配置多个环境 -->
    <environments default="chat01">
        <!--
            environment用来对某个环境进行配置
            id:环境标识,唯一
         -->
        <environment id="chat01">
            <!-- 事务管理器工厂配置 -->
            <transactionManager type="org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory"/>
            <!-- 数据源工厂配置,使用工厂来创建数据源 -->
            <dataSource type="org.apache.ibatis.datasource.pooled.PooledDataSourceFactory">
                <property name="driver" value="com.mysql.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mybatisdemo?characterEncoding=UTF-8"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
</configuration>

elemento de configuração

Este é o elemento raiz do arquivo de configuração global mybatis, cada arquivo de configuração tem apenas um

elemento de ambientes

As informações de ambiente usadas para configurar mybatis são usadas para configurar vários ambientes. Um ambiente específico é configurado usando o elemento de ambiente. O elemento de ambiente tem um id para identificar um ambiente específico.

O elemento de ambientes possui um atributo padrão, que é usado para especificar qual ambiente usar por padrão, por exemplo, chat01 é usado por padrão acima.

elemento de ambiente

Usado para configurar informações ambientais específicas, existem dois subelementos neste elemento: transactionManager e dataSource

  • Elemento transactionManager

Usado para configurar a fábrica de transações, há um atributo de tipo, o valor de tipo deve ser a classe de implementação da interface org.apache.ibatis.transaction.TransactionFactory, usada para criar o objeto do gerenciador de transações, a interface TransactionFactory tem 2 implementações por predefinição:

org.apache.ibatis.transaction.managed.ManagedTransactionFactory
org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory

Em circunstâncias normais, usamos org.apache.ibatis.transaction.jdbc.JdbcTransactionFactory. Mybatis se integra a outras estruturas, como integração com spring, e a transação é controlada por spring.

  • elemento dataSource

Isso é usado para configurar a fonte de dados. O valor do atributo type deve ser a classe de implementação da interface org.apache.ibatis.datasource.DataSourceFactory. DataSourceFactory também é uma fábrica para criar objetos de fonte de dados javax.sql.DataSource. interface em mybatis Existem 3 classes de implementação por padrão:

org.apache.ibatis.datasource.jndi.JndiDataSourceFactory
org.apache.ibatis.datasource.pooled.PooledDataSourceFactory
org.apache.ibatis.datasource.unpooled.UnpooledDataSourceFactory

Usamos o segundo org.apache.ibatis.datasource.pooled.PooledDataSourceFactory, que é usado para criar uma fonte de dados do tipo pool de conexão de banco de dados, que pode realizar o compartilhamento de conexão de banco de dados e reduzir o tempo de criação repetida e destruição de conexões. Para configurar a fonte de dados, você precisa especificar as informações de propriedade da conexão de banco de dados, como o driver, a url do banco de dados de conexão, o nome de usuário e a senha. Isso é configurado na propriedade sob o elemento dataSource. formato do elemento de propriedade:

<property name="属性名称" value="值"/>

Criar arquivo xml mapeador

Em mybatis, geralmente escrevemos todas as operações sql de uma tabela em um mapeador xml, geralmente denominado formato XXXMapper.xml.

O conteúdo é o seguinte:

<?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="zhonghu.mybatis.chat01.UserMapper">
</mapper>

O elemento raiz do mapeador xml é mapeador. Este elemento tem um atributo de namespace. Haverá muitas tabelas no sistema. Cada tabela corresponde a um mapeador xml. Para evitar a duplicação de arquivos mapeadores, precisamos especificar um namespace para cada arquivo xml do mapeador. Por meio dele, cada arquivo xml do mapeador pode ser distinguido. Acima, o designamos como zhonghu.mybatis.chat01.UserMapper.

Vamos escrever o SQL relacionado a todas as operações da tabela do usuário no xml acima.

Introduzir o arquivo xml Mapper no arquivo de configuração global mybatis

Escrevemos user.xml, como permitir que mybatis saiba este arquivo, neste momento precisamos introduzir UserMapper.xml no arquivo de configuração global mybatis-config.xml e adicionar a seguinte configuração em mybatis-config.xml:

<mappers>
        <mapper resource="mapper/user.xml"/>
    </mappers>

Existem vários elementos mapeadores no elemento mappers. O arquivo xml Mapper pode ser importado por meio do atributo resource do elemento mapper. O recurso é o caminho relativo às classes.

Todos os arquivos de configuração mencionados acima estão ok. Agora precisamos executar o mybatis. Neste momento, precisamos usar alguns objetos java no mybatis.

Construir um objeto SqlSessionFactory

//指定mybatis全局配置文件
String resource = "mybatis-config.xml";
//读取全局配置文件
InputStream inputStream = Resources.getResourceAsStream(resource);
//构建SqlSessionFactory对象
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);

SqlSessionFactory é uma interface e um objeto pesado. SqlSessionFactoryBuilder cria um SqlSessionFactory lendo o arquivo de configuração global. A criação deste objeto é demorada, principalmente na análise do arquivo de configuração global mybatis, no arquivo de configuração global Contém muito conteúdo. SqlSessionFactoryBuilder cria um objeto SqlSessionFactory complexo analisando esse conteúdo. O ciclo de vida desse objeto é geralmente igual ao ciclo de vida do aplicativo. Ele é criado quando o aplicativo é iniciado e termina quando o aplicativo é interrompido, portanto, geralmente é um objeto global e, em geral, um banco de dados corresponde a um objeto SqlSessionFactory.

Construir o objeto SqlSession

SqlSession é equivalente ao objeto Connection em jdbc, que é equivalente a uma conexão com o banco de dados. SqlSession pode ser usado para operar o banco de dados: como executar SQL, enviar transações, fechar conexões, etc., você precisa criar objetos SqlSession por meio de SqlSessionFactory . Normalmente usados ​​em SqlSessionFactory são dois métodos para criar um objeto SqlSession são os seguintes:

//创建一个SqlSession,默认不会自动提交事务
SqlSession openSession();
//创建一个SqlSession,autoCommit:指定是否自动提交事务
SqlSession openSession(boolean autoCommit);

Muitos métodos na interface SqlSession são usados ​​diretamente para manipular o banco de dados. A lista de métodos é a seguinte, todos estão familiarizados com:

<T> T selectOne(String statement);
<T> T selectOne(String statement, Object parameter);
<E> List<E> selectList(String statement);
<E> List<E> selectList(String statement, Object parameter);
<E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds);
<K, V> Map<K, V> selectMap(String statement, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey);
<K, V> Map<K, V> selectMap(String statement, Object parameter, String mapKey, RowBounds rowBounds);
<T> Cursor<T> selectCursor(String statement);
<T> Cursor<T> selectCursor(String statement, Object parameter);
<T> Cursor<T> selectCursor(String statement, Object parameter, RowBounds rowBounds);
void select(String statement, Object parameter, ResultHandler handler);
void select(String statement, ResultHandler handler);
void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler);
int insert(String statement);
int insert(String statement, Object parameter);
int update(String statement);
int update(String statement, Object parameter);
int delete(String statement);
int delete(String statement, Object parameter);
void commit();
void commit(boolean force);
void rollback();
void rollback(boolean force);
List<BatchResult> flushStatements();
void close();
void clearCache();
Configuration getConfiguration();
<T> T getMapper(Class<T> type);
Connection getConnection();

O início acima com select pode executar operações de consulta em db, insert related pode executar operações de insert em db e update related pode executar operações de atualização em db.

Introduzir suporte lombok (não obrigatório)

O Lombok pode simplificar o código java na forma de anotações simples e melhorar a eficiência de desenvolvimento dos desenvolvedores. Por exemplo, para JavaBeans que são frequentemente escritos em desenvolvimento, leva tempo para adicionar getter / setters correspondentes, e talvez também para escrever construtores, equals e outros métodos, e eles precisam ser mantidos. Quando há muitas propriedades, um grande número de métodos getter / setter aparecerá. Parece muito prolixo e não tem muito conteúdo técnico. Uma vez que os atributos são modificados, é fácil esquecer de modificar o método correspondente.

O Lombok pode gerar construtores, getter / setter, equals, hashcode e métodos toString automaticamente para propriedades em tempo de compilação por meio de anotações. A mágica que aparece é que não há métodos getter e setter no código-fonte, mas há métodos getter e setter no arquivo de bytecode compilado. Isso evita o trabalho de reconstruir o código manualmente e faz com que o código pareça mais conciso.

Como usar o lombok

  • Primeiro instale o plug-in lombok no idea, abra o idea, clique em Arquivo-> Configurações-> plug-ins, em seguida, pesquise o plug-in Lombok e clique em instalar.
  • Introduzir suporte lombok no maven
<dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.18.10</version>
   <scope>provided</scope>
</dependency>
  • Use funções relacionadas ao lombok no código

Introduzir logback (não obrigatório)

Para visualizar convenientemente os logs gerados durante a execução de mybatis, como: sql executado, parâmetros de sql, resultados de execução de sql e outras informações de depuração, precisamos apresentar o suporte da estrutura de log, logback é uma estrutura de log muito boa, aqui nós apenas usamos isso

Etapas de logback integradas em mybatis

  • Introduzir suporte logback no maven
<dependency>
   <groupId>ch.qos.logback</groupId>
   <artifactId>logback-classic</artifactId>
   <version>1.2.3</version>
</dependency>
  • Crie o arquivo logback.xml em src / main / resources:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
   <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
       <encoder>
           <pattern>%d{mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n</pattern>
       </encoder>
   </appender>
   <logger name="zhonghu" level="debug" additivity="false">
       <appender-ref ref="STDOUT" />
   </logger>
</configuration>

A escrita específica de logback.xml não está no escopo deste artigo. Amigos interessados ​​podem estudar o uso específico de logback.

Escreva um caso de teste

Tendo dito isso acima, vamos escrever uma classe de teste para demonstrar

O conteúdo é o seguinte:

package zhonghu.mybatis.chat01;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;

@Slf4j
public class UserMapperTest {
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before() throws IOException {
        //指定mybatis全局配置文件
        String resource = "mybatis-config.xml";
        //读取全局配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //构建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        this.sqlSessionFactory = sqlSessionFactory;
    }
    @Test
    public void sqlSession() {
        SqlSession sqlSession = this.sqlSessionFactory.openSession();
        log.info("{}", sqlSession);
    }

}

Há uma anotação @ Slf4j no código acima, que é fornecido por lombok, e o código a seguir pode ser gerado nesta classe:

private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(UserTest.class);

Execute o caso de uso acima: método sqlSession, a saída é a seguinte:

37:52.473 [main] INFO  z.mybatis.chat01.UserMapperTest - org.apache.ibatis.session.defaults.DefaultSqlSession@2d127a61

Até agora, construímos um projeto Mybatis mínimo e precisamos escrever nossos arquivos sql conforme necessário mais tarde

Use SqlSesion para executar operações sql

Uso comum de SqlSession

SqlSession é equivalente a uma conexão. Você pode usar este objeto para realizar operações de adição, exclusão, modificação e verificação no banco de dados. Após a operação ser concluída, você precisa fechá-la. Use as etapas:

  • Obtenha o objeto SqlSession: Obtenha o objeto SqlSession por meio do método sqlSessionFactory.openSession
  • Operar no banco de dados: use o objeto SqlSession para operação do banco de dados
  • Feche o objeto SqlSession: sqlSession.close ();

Do seguinte modo

//获取SqlSession
SqlSession sqlSession = this.sqlSessionFactory.openSession();
try {
    //执行业务操作,如:增删改查
} finally {
    //关闭SqlSession
    sqlSession.close();
}

Acima, colocamos o fechamento de SqlSession no bloco finally para garantir que close () seja executado.

Nova operação

Requisitos: Passe o objeto UserModel e, a seguir, insira os dados desse objeto na tabela do usuário.

Crie um UserModel

Classe UserModel, o código é o seguinte:

package zhonghu.mybatis.chat01;

import lombok.*;

@Getter
@Setter
@NoArgsConstructor
@AllArgsConstructor
@Builder
@ToString
public class UserModel {
    private Long id;
    private String name;
    private Integer age;
    private Double salary;
}

Os campos desta classe correspondem à tabela do usuário.

Operação de inserção definida em user.xml

Como dissemos, colocamos todas as operações sql na tabela do usuário em user.xml, adicionamos a seguinte configuração em user.xml e usamos o elemento insert para definir a operação de inserção:

<!-- insert用来定义一个插入操作
     id:操作的具体标识
     parameterType:指定插入操作接受的参数类型
 -->
<insert id="insertUser" parameterType="zhonghu.mybatis.chat01.UserModel">
    <![CDATA[
    INSERT INTO user (id,name,age,salary) VALUES (#{id},#{name},#{age},#{salary})
     ]]>
</insert>
  • O elemento de inserção é usado para definir uma operação de inserção no banco de dados
  • id: É uma identificação desta operação, quando a operação é executada através do mybatis, a operação de inserção será referenciada através deste namespace e id.
  • parameterType: Usado para especificar o tipo de parâmetros aceitos por esta operação de inserção, que podem ser: vários javabean, map, list, tipos de coleção de objetos java, e nossa inserção aceita objetos UserModel.
  • O elemento insert define o sql específico dentro, você pode ver que é um sql insert, inserindo dados na tabela do usuário.

O valor a ser inserido é obtido do objeto UserModel, e o campo do objeto UserModel é obtido, e o valor do campo no UserModel pode ser obtido utilizando o formato de # {Field}.

Chame o método SqlSession.insert para realizar a operação de inserção

O SQL inserido pelo usuário foi escrito no UserMapper, como o chamamos neste momento?

Precisa chamar o método SqlSession.insert:

int insert(String statement, Object parameter)

Este método possui 2 parâmetros:

  • declaração: indica a operação, o valor é o namespace do Mapper xml. O id da operação específica, se você precisar chamar a operação insertUser em UserMapper.xml, este valor é:
zhonghu.mybatis.chat01.UserMapper.insertUser
  • parâmetro: O parâmetro da operação de inserção é consistente com o tipo especificado pelo parameterType na inserção no xml do mapeador.

O valor de retorno é o número de linhas inseridas.

Um novo caso de teste é adicionado à classe UserTest:

  @Test
    public void insertUser() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(false);) {
            //创建UserModel对象
            UserModel userModel = UserModel.builder().id(69L).name("Java冢狐").age(30).salary(50000D).build();
            //执行插入操作
            int result = sqlSession.insert("zhonghu.mybatis.chat01.UserMapper.insertUser", userModel);
            log.info("插入影响行数:{}", result);
            //提交事务
            sqlSession.commit();
        }
    }

A saída em execução é a seguinte:

05:15.831 [main] DEBUG z.m.chat01.UserMapper.insertUser - ==>  Preparing: INSERT INTO user (id,name,age,salary) VALUES (?,?,?,?) 
05:15.853 [main] DEBUG z.m.chat01.UserMapper.insertUser - ==> Parameters: 69(Long), Java冢狐(String), 30(Integer), 50000.0(Double)
05:15.951 [main] DEBUG z.m.chat01.UserMapper.insertUser - <==    Updates: 1
05:15.952 [main] INFO  z.mybatis.chat01.UserMapperTest - 插入影响行数:1

A instrução sql detalhada e as informações de parâmetro sql são impressas na saída. Você pode ver que # {} no Mapper xml foi substituído por?. Isso usa PreparedStatement em jdbc para definir o valor do parâmetro.

A segunda linha na saída detalha o valor do parâmetro e o tipo de cada valor.

A terceira linha produz o resultado da inserção como 1, o que significa que uma linha de registros foi inserida com sucesso.

A SqlSession criada no código acima é criada por sqlSessionFactory.openSession (). Os assuntos internos da SqlSession criada por este método não são enviados automaticamente, portanto, precisamos enviá-la manualmente:

Adicionar, excluir e modificar operações, todas precisam confirmar a transação

sqlSession.commit();

Se você quiser confirmar automaticamente a transação, altere para sqlSessionFactory.openSession (true) ao criar a SqlSession acima e especifique a transação como modo de confirmação automática, portanto, no final, não precisamos confirmar manualmente a transação.

Operação de atualização

Requisitos: Passe o objeto UserModel e, a seguir, atualize os dados por id.

Operação de atualização definida em UserMapper.xml

Use update para definir a operação de atualização:

<!-- update用来定义一个更新操作
     id:操作的具体标识
     parameterType:指定操作接受的参数类型
 -->
    <update id="updateUser" parameterType="zhonghu.mybatis.chat01.UserModel">
    <![CDATA[
    UPDATE user SET name = #{name},age = #{age},salary = #{salary} WHERE id = #{id}
    ]]>
</update>

O método de gravação é semelhante ao da operação de inserção, especificando o identificador de id, parameterType para especificar o tipo de parâmetro da operação e a instrução SQL específica no corpo do elemento.

Chame o método SqlSession.update para executar a operação de atualização

Precisa chamar o método SqlSession.update:

int update(String statement, Object parameter)

Este método possui 2 parâmetros:

  • instrução: indica qual operação, o valor é o namespace do Mapper xml. O id da operação específica, se você precisar chamar a operação updateUser em UserMapper.xml, este valor é:
zhonghu.mybatis.chat01.UserMapper.updateUser
  • parâmetro: O parâmetro da operação de atualização é consistente com o tipo especificado pelo parameterType na atualização no mapeador xml.

O valor de retorno é o número de linhas afetadas pela atualização.

Um novo caso de teste é adicionado à classe UserTest:

    @Test
    public void updateUser() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            //创建UserModel对象
            UserModel userModel = UserModel.builder().id(1L).name("Java冢狐,你好").age(18).salary(5000D).build();
            //执行更新操作
            int result = sqlSession.update("zhonghu.mybatis.chat01.UserMapper.updateUser", userModel);
            log.info("影响行数:{}", result);
        }
    }

Execute a saída:

12:17.143 [main] DEBUG z.m.chat01.UserMapper.updateUser - ==>  Preparing: UPDATE user SET name = ?,age = ?,salary = ? WHERE id = ? 
12:17.163 [main] DEBUG z.m.chat01.UserMapper.updateUser - ==> Parameters: Java冢狐,你好(String), 18(Integer), 5000.0(Double), 1(Long)
12:17.258 [main] DEBUG z.m.chat01.UserMapper.updateUser - <==    Updates: 1
12:17.258 [main] INFO  z.mybatis.chat01.UserMapperTest - 影响行数:1

Excluir operação

Requisito: excluir o registro do usuário correspondente de acordo com a id do usuário

A operação Delete é definida em UserMapper.xml

Use o elemento update para definir a operação de exclusão:

<!-- update用来定义一个删除操作
     id:操作的具体标识
     parameterType:指定操作接受的参数类型
 -->
<update id="deleteUser" parameterType="java.lang.Long">
    <![CDATA[
    DELETE FROM user WHERE id = #{id}
    ]]>
</update>

O método de gravação é semelhante ao método de gravação da operação de atualização. Especifique o identificador de id e o parameterType para especificar o tipo de parâmetro da operação. A id do usuário é do tipo Longo e o corpo do elemento contém a instrução de exclusão específica.

Chame o método SqlSession.update para executar a operação de atualização

Precisa chamar o método SqlSession.delete:

int delete(String statement, Object parameter)

Este método possui 2 parâmetros:

  • instrução: indica qual operação, o valor é o namespace do Mapper xml. O id da operação específica, se você precisar chamar a operação deleteUser em UserMapper.xml, este valor é:
com.javacode2018.chat02.UserMapper.
  • parâmetro: O parâmetro da operação de exclusão, que é consistente com o tipo especificado pelo parameterType na exclusão no xml do mapeador.

O valor de retorno é o número de linhas afetadas pela exclusão.

Um novo caso de teste é adicionado à classe UserTest:

    @Test
    public void deleteUser() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            //定义需要删除的用户id
            Long userId = 1L;
            //执行删除操作
            int result = sqlSession.delete("zhonghu.mybatis.chat01.UserMapper.deleteUser", userId);
            log.info("影响行数:{}", result);
        }
    }

Execute a saída:

14:26.711 [main] DEBUG z.m.chat01.UserMapper.deleteUser - ==>  Preparing: DELETE FROM user WHERE id = ? 
14:26.729 [main] DEBUG z.m.chat01.UserMapper.deleteUser - ==> Parameters: 1(Long)
14:26.811 [main] DEBUG z.m.chat01.UserMapper.deleteUser - <==    Updates: 1
14:26.812 [main] INFO  z.mybatis.chat01.UserMapperTest - 影响行数:1

Executar consulta

A instrução select tem muitos atributos para configurar cada instrução SQL em detalhes

  • Tipo de valor de retorno da instrução SQL [nome completo da classe ou alias]
  • O tipo de parâmetro da instrução SQL de entrada [Recomenda-se usar um mapa universal]
  • Identificador único no namespace
  • O nome do método na interface corresponde ao ID da instrução SQL no arquivo de mapeamento um a um

Requisitos: consultar todas as informações do usuário

Selecione a operação definida em UserMapper.xml

    <!-- select用来定义一个查询操作
     id:操作的具体标识
     resultType:指定查询结果保存的类型
 -->
    <select id="getUserList" resultType="zhonghu.mybatis.chat01.UserModel">
    <![CDATA[
    SELECT * FROM user
    ]]>
</select>

O método de gravação é semelhante ao método de gravação da operação de atualização, especificando o identificador de id, parameterType especificando o tipo de parâmetro da operação, resultType especificando o tipo do resultado da consulta e a instrução select específica no corpo do elemento.

Chame o método SqlSession.select para executar a operação de atualização

UserTest adiciona um caso de uso:

  @Test
    public void getUserList() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            //执行查询操作
            List<UserModel> userModelList = sqlSession.selectList("zhonghu.mybatis.chat01.UserMapper.getUserList");
            log.info("结果:{}", userModelList);
        }
    }

Insira mais algumas linhas e execute o caso de uso acima, a saída é a seguinte:

16:00.798 [main] DEBUG z.m.chat01.UserMapper.getUserList - ==>  Preparing: SELECT * FROM user 
16:00.817 [main] DEBUG z.m.chat01.UserMapper.getUserList - ==> Parameters: 
16:00.829 [main] DEBUG z.m.chat01.UserMapper.getUserList - <==      Total: 16
16:00.829 [main] INFO  z.mybatis.chat01.UserMapperTest - 结果:[UserModel(id=2, name=修改冢狐, age=23, salary=50000.0), UserModel(id=3, name=修改冢狐, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Java冢狐-2, age=25, salary=20000.0), UserModel(id=6, name=Mybatis-2, age=20, salary=20000.0), UserModel(id=7, name=Java冢狐-3, age=26, salary=30000.0), UserModel(id=8, name=Mybatis-3, age=21, salary=30000.0), UserModel(id=9, name=Java冢狐-4, age=27, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=40000.0), UserModel(id=11, name=Java冢狐-5, age=28, salary=50000.0), UserModel(id=12, name=Mybatis-5, age=23, salary=50000.0), UserModel(id=13, name=Java冢狐, age=1, salary=0.0), UserModel(id=14, name=冢狐, age=23, salary=50000.0), UserModel(id=59, name=Java冢狐, age=30, salary=50000.0), UserModel(id=69, name=Java冢狐, age=30, salary=50000.0), UserModel(id=89, name=Java冢狐, age=30, salary=50000.0)]

Uso da interface do Mapper

Por que precisamos da interface do Mapper

Acima explicamos as operações de adição, exclusão, modificação e consulta de uma tabela, todas feitas chamando os métodos em SqlSession. Vamos dar uma olhada nas definições de vários métodos usados ​​apenas na interface SqlSession:

int insert(String statement, Object parameter);
int update(String statement, Object parameter);
int delete(String statement, Object parameter);
<E> List<E> selectList(String statement);

Vamos dar uma olhada nas características desses métodos:

  • Para chamar esses métodos, você precisa saber o valor da instrução claramente, e o valor da instrução é o namespace. O id da operação específica, você precisa abrir o mapeador xml para visualizá-lo antes de conhecê-lo. não é conveniente escrever
  • Os parâmetros dos parâmetros são todos do tipo Object. Não sabemos qual é o tipo específico desta operação. Precisamos verificar o xml do mapeador para descobrir. Passe um valor à vontade. O tipo pode não corresponder, mas só sabemos que há um problema no tempo de execução.
  • O método selectList retorna um tipo genérico. Por meio desse método, não sabemos o tipo específico do resultado retornado. Também precisamos verificar o mapeador xml para saber

Todas essas situações são inconvenientes no processo de uso. Se você quiser usá-lo convenientemente, você precisa usar a interface do Mapper no mybatis. Podemos definir uma interface e associá-la ao Mapper xml. As operações no Mapper xml e na interface do Mapper O método será vinculado. Quando chamamos o método da interface do mapeador, ele chama indiretamente a operação no mapeador xml. O nome completo da classe da interface precisa ser consistente com o namespace no mapeador xml.

Uso da interface do mapeador (três etapas)

Etapa 1: definir a interface do mapeador

Dê uma olhada, o namespace em user.xml é:

<mapper namespace="zhonghu.mybatis.chat01.UserMapper">

O nome completo da interface que criamos precisa ser igual ao valor do namespace acima. Abaixo, criamos uma interface UserMapper, da seguinte maneira:

Existem 4 operações no UserMapper.xml. Precisamos definir 4 operações na interface do UserMapper, correspondendo às 4 operações no UserMapper.xml, como segue:

package zhonghu.mybatis.chat01;
import java.util.List;

public interface UserMapper {
    int insertUser(UserModel model);
    int updateUser(UserModel model);
    int deleteUser(Long userId);
    List<UserModel> getUserList();
}

Existem quatro métodos definidos na interface do UserMapper. O nome do método precisa ser igual ao valor de id da operação específica no UserMapper.xml, de modo que, quando o método na interface do UserMapper for chamado, a operação específica no UserMapper .xml será encontrado em conformidade.

Por exemplo, ao chamar o método insertUser na interface do UserMapper, a regra da pesquisa mybatis é: encontre a operação correspondente no mapeador xml através do nome completo da interface e do nome do método.

Etapa 2: Obtenha o objeto de interface do Mapeador por meio de SqlSession

Há um método getMapper em SqlSession, que pode passar o tipo de interface para obter o objeto de interface do Mapper específico, da seguinte maneira:

/**
   * Retrieves a mapper.
   * @param <T> the mapper type
   * @param type Mapper interface class
   * @return a mapper bound to this SqlSession
   */
  <T> T getMapper(Class<T> type);

Como obter o objeto de interface UserMapper:

UserMapper mapper = sqlSession.getMapper(UserMapper.class);

Etapa 3: chame o método de interface do mapeador para operar o banco de dados

Como chamar a operação de inserção da interface UserMapper:

@Test
public void insertUser() {
    try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
        UserMapper mapper = sqlSession.getMapper(UserMapper.class);
        //创建UserModel对象
        UserModel userModel = UserModel.builder().id(System.currentTimeMillis()).name("Java冢狐").age(30).salary(50000D).build();
        //执行插入操作
        int insert = mapper.insertUser(userModel);
        log.info("影响行数:{}", insert);
    }
}

Caso: use a interface do mapeador para implementar adição, exclusão, modificação e verificação

Crie uma classe de teste, o código é o seguinte:

package zhonghu.mybatis.chat01;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

@Slf4j
public class UserMapperTest {
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before() throws IOException {
        //指定mybatis全局配置文件
        String resource = "mybatis-config.xml";
        //读取全局配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //构建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        this.sqlSessionFactory = sqlSessionFactory;
    }
    @Test
    public void insertUser() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            //创建UserModel对象
            UserModel userModel = UserModel.builder().id(System.currentTimeMillis()).name("Java冢狐").age(30).salary(50000D).build();
            //执行插入操作
            int insert = mapper.insertUser(userModel);
            log.info("影响行数:{}", insert);
        }
    }
    @Test
    public void updateUser() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            //创建UserModel对象
            UserModel userModel = UserModel.builder().id(1L).name("Java冢狐,你好").age(18).salary(5000D).build();
            //执行更新操作
            int result = mapper.updateUser(userModel);
            log.info("影响行数:{}", result);
        }
    }
    @Test
    public void deleteUser() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            //定义需要删除的用户id
            Long userId = 1L;
            //执行删除操作
            int result = mapper.deleteUser(userId);
            log.info("影响行数:{}", result);
        }
    }
    @Test
    public void getUserList() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper mapper = sqlSession.getMapper(UserMapper.class);
            //执行查询操作
            List<UserModel> userModelList = mapper.getUserList();
            userModelList.forEach(item -> {
                log.info("{}", item);
            });
        }
    }
}

Dê uma olhada no código acima com atenção. Desta vez, usamos UserMapper para chamar indiretamente a operação correspondente em UserMapper.xml, e você pode executá-la e sentir o efeito.

Pontos a serem observados ao usar a interface do Mapper

  • O nome completo da classe da interface do mapeador deve ser consistente com o valor do namespace no mapeador xml correspondente
  • O nome do método na interface do mapeador precisa ser consistente com o valor de id da operação específica no xml do mapeador
  • Os parâmetros e valores de retorno dos métodos na interface do mapeador podem não ser consistentes com aqueles no xml do mapeador

O princípio da interface do Mapeador

Isso é implementado usando um proxy dinâmico em java. Quando mybatis for iniciado, ele carregará o arquivo de configuração global mybatis-config.xml e, em seguida, analisará o UserMapper.xml especificado pelo elemento mapeador neste arquivo e o criará com base no valor do namespace de UserMapper.xml Um proxy dinâmico da interface, você pode ver o código-fonte de mybatis. É implementado principalmente usando o Proxy em java. Usando o método newProxyInstance na classe java.lang.reflect.Proxy, nós pode criar um objeto proxy de qualquer interface:

public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)

Usamos Proxy para simular a implementação da interface do Mapeador:

package zhonghu.mybatis.chat01;

import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.io.Resources;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;
import org.junit.Before;
import org.junit.Test;

import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.List;

@Slf4j
public class UserMapperTest {
    public static class UserMapperProxy implements InvocationHandler {
        private SqlSession sqlSession;
        private Class<?> mapperClass;
        public UserMapperProxy(SqlSession sqlSession, Class<?> mapperClass) {
            this.sqlSession = sqlSession;
            this.mapperClass = mapperClass;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            log.debug("invoke start");
            String statement = mapperClass.getName() + "." + method.getName();
            List<Object> result = sqlSession.selectList(statement);
            log.debug("invoke end");
            return result;
        }
    }
    private SqlSessionFactory sqlSessionFactory;
    @Before
    public void before() throws IOException {
        //指定mybatis全局配置文件
        String resource = "mybatis-config.xml";
        //读取全局配置文件
        InputStream inputStream = Resources.getResourceAsStream(resource);
        //构建SqlSessionFactory对象
        SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
        this.sqlSessionFactory = sqlSessionFactory;
    }
    @Test
    public void test1() {
        try (SqlSession sqlSession = this.sqlSessionFactory.openSession(true);) {
            UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(UserMapperTest.class.getClassLoader(), new Class[]{UserMapper.class}, new UserMapperProxy(sqlSession, UserMapper.class));
            log.info("{}", userMapper.getUserList());
        }
    }
}

No código acima: UserMapper não tem classe de implementação. Você pode criar um objeto proxy para a interface UserMapper por meio de Proxy.newProxyInstance. Quando o método da interface UserMapper é chamado, o método invoke do objeto UserMapperProxy será chamado.

Execute o caso de uso test1, a saída é a seguinte:

29:37.847 [main] DEBUG z.m.chat01.UserMapper.getUserList - ==>  Preparing: SELECT * FROM user 
29:37.865 [main] DEBUG z.m.chat01.UserMapper.getUserList - ==> Parameters: 
29:37.878 [main] DEBUG z.m.chat01.UserMapper.getUserList - <==      Total: 16
29:37.878 [main] DEBUG z.mybatis.chat01.UserMapperTest - invoke end
29:37.878 [main] INFO  z.mybatis.chat01.UserMapperTest - [UserModel(id=2, name=修改冢狐, age=23, salary=50000.0), UserModel(id=3, name=修改冢狐, age=24, salary=6666.66), UserModel(id=4, name=Mybatis-1, age=19, salary=10000.0), UserModel(id=5, name=Java冢狐-2, age=25, salary=20000.0), UserModel(id=6, name=Mybatis-2, age=20, salary=20000.0), UserModel(id=7, name=Java冢狐-3, age=26, salary=30000.0), UserModel(id=8, name=Mybatis-3, age=21, salary=30000.0), UserModel(id=9, name=Java冢狐-4, age=27, salary=40000.0), UserModel(id=10, name=Mybatis-4, age=22, salary=40000.0), UserModel(id=11, name=Java冢狐-5, age=28, salary=50000.0), UserModel(id=12, name=Mybatis-5, age=23, salary=50000.0), UserModel(id=13, name=Java冢狐, age=1, salary=0.0), UserModel(id=14, name=冢狐, age=23, salary=50000.0), UserModel(id=59, name=Java冢狐, age=30, salary=50000.0), UserModel(id=69, name=Java冢狐, age=30, salary=50000.0), UserModel(id=89, name=Java冢狐, age=30, salary=50000.0)]

Preste atenção ao início da chamada e saída final da chamada acima, você pode ver que quando chamamos userMapper.getUserList, eles são processados ​​pelo método UserMapperProxy # invoke.

A seguinte classe é usada para criar o objeto proxy da interface do Mapeador em Mybatis. Você pode estudá-lo:

public class MapperProxyFactory<T> {
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
  public MapperProxyFactory(Class<T> mapperInterface) {
    this.mapperInterface = mapperInterface;
  }
  public Class<T> getMapperInterface() {
    return mapperInterface;
  }
  public Map<Method, MapperMethod> getMethodCache() {
    return methodCache;
  }
  @SuppressWarnings("unchecked")
  protected T newInstance(MapperProxy<T> mapperProxy) {
    return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
  }
  public T newInstance(SqlSession sqlSession) {
    final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
    return newInstance(mapperProxy);
  }
}

Finalmente

  • Se você sentir que é recompensado após a leitura, espero prestar atenção a isso. A propósito, dê um sinal de positivo. Essa será a maior motivação para minha atualização. Obrigado pelo seu apoio.
  • Sejam todos bem-vindos, prestem atenção à minha conta pública [Java Fox], com foco no conhecimento básico de java e informática, prometo deixar vocês obterem algo depois de lê-lo, se não acreditam em mim, me bata
  • Procure uma conexão tripla de um clique: curtir, avançar e assistir.
  • Se você tiver opiniões ou sugestões diferentes após a leitura, por favor, comente e compartilhe conosco. Obrigado pelo seu apoio e amor.

——Eu sou Chuhu e adoro programar tanto quanto você.

Bem-vindo a seguir a conta pública "Java Fox" para as últimas notícias

Acho que você gosta

Origin blog.csdn.net/issunmingzhi/article/details/113711961
Recomendado
Clasificación