Preparação da análise de código-fonte Mybatis

Preparação da análise de código-fonte Mybatis

dicas: mybatis

1. Crie o ambiente de origem Mybatis

1. Requisitos ambientais:

JDK1.8, Maven, Eclipse ou IntelliJ IDEA

2. Obtenha o código fonte

  • Código fonte do Mybatis:

https://github.com/mybatis/mybatis-3

  • Código fonte integrado Mybatis e Spring:

https://github.com/mybatis/spring

  • Código fonte da classe pai Mybatis:

https://github.com/mybatis/parent

3. Importe o código fonte para o IDE

  • Arquivo => Novo => Projeto… => Projeto vazio => Próximo => 命名 => Concluir

  • Arquivo => Novo => Módulo de fontes existentes… => Selecione três códigos-fonte e um código de teste, respectivamente, e importe-os separadamente

4. Introdução ao HSQLDB

  • O modo de memória do HSQLDB incorporado no Mybatis é usado como um banco de dados para teste de unidade, portanto, não há necessidade de instalar bancos de dados como o Mysql.
  • O nome do usuário e a senha do modo de memória podem ser especificados à vontade, mas se você precisar persistir localmente, precisará especificar o nome do usuário e a senha.
  • Os testes de unidade não se importam, eles podem ser especificados à vontade. O nome de usuário padrão é sa e a senha está em branco.
  • ScriptRunner é usado para executar scripts (XXX.sql) e SqlRunner é usado para executar instruções sql (instruções de adição, exclusão, modificação e consulta).

5. Entrada da análise do código fonte:

public class Example01 {
    private Connection conn = null;
    @Before
    public void initData() {
        try {
            //Example02 example02 = new Example02();//調用方法的時候回提示,引入依賴,但是調用common裡面的文件的時候卻不用。
            // 加载HSQLDB驱动
            Class.forName("org.hsqldb.jdbcDriver");
            // 获取Connection对象,用户名和密码可以随便指定
            conn = DriverManager.getConnection("jdbc:hsqldb:mem:mybatis",
                    "satestlalla", "");
            // 使用Mybatis的ScriptRunner工具类执行数据库脚本
            ScriptRunner scriptRunner = new ScriptRunner(conn);
            scriptRunner.setLogWriter(null);
            //文件都放在mybatis-common module的resource下面
            scriptRunner.runScript(Resources.getResourceAsReader("create-table.sql"));
            scriptRunner.runScript(Resources.getResourceAsReader("init-data.sql"));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @Test
    public void testHsqldbQuery() {
        // SqlRunner是Mybatis封装的操作数据库的工具类
        SqlRunner sqlRunner = new SqlRunner(conn);
        try {
            //调用SqlRunner类的selectAll()方法查询数据
            List<Map<String, Object>> results = sqlRunner.selectAll("select * from user");
            results.forEach(System.out::println);//jdk8之后新特性
            sqlRunner.closeConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

Segundo, a especificação JDBC

1. documento de especificação do jdbc

  • Endereço de download do documento de especificação JDBC4.2: https://download.oracle.com/otndocs/jcp/jdbc-4_2-mrel2-spec/index.html

2. Etapas para operar o banco de dados

  • Estabelecer uma conexão de dados
  • Executar instrução SQL
  • Recuperar resultados de execução SQL
  • Fechar conexão

3. Estabeleça uma conexão com o banco de dados

Três maneiras:

  • DriverManager - fornecido por JDBC1.0

    Precisa mostrar a classe do driver de carregamento:

    Class.forName("org.hsqldb.jdbcDriver");

  • DataSource - fornecido por JDBC2.0 (configuração mais recomendada e flexível)

    • DataSource: a classe mais básica
    • DataSourceFactory: classe de fábrica
    • ConnectionPoolDataSource: suporta armazenamento em cache e reutilização de objetos Connection
    • XADataSource: suporta transações distribuídas

O código fonte é o seguinte:

//第一种方式
// 加载驱动 到JDBC4之后不需要直接声明驱动,可以在META-INF.services目录下面创建一个跟驱动同名的文件即可,参考chapter02.SPIExample
/*原理如下
ServiceLoader<Driver> drivers = ServiceLoader.load(java.sql.Driver.class);
        for (Driver driver : drivers ) {
            System.out.println(driver.getClass().getName());
        }
*/
Class.forName("org.hsqldb.jdbcDriver");
// 获取Connection对象
Connection connection = DriverManager.getConnection("jdbc:hsqldb:mem:mybatis",
                    "sa", "");

//第二种方式
// 创建DataSource实例
DataSource dataSource = new UnpooledDataSource("org.hsqldb.jdbcDriver","jdbc:hsqldb:mem:mybatis", "sa", "");
// 获取Connection对象
Connection connection = dataSource.getConnection();

//第三种方式
// 创建DataSource实例
DataSourceFactory dsf = new UnpooledDataSourceFactory();
Properties properties = new Properties();
InputStream configStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("database.properties");
properties.load(configStream);
dsf.setProperties(properties);
DataSource dataSource = dsf.getDataSource();
// 获取Connection对象
Connection connection = dataSource.getConnection();

//插入操作
Statement statement = connection.createStatement();
statement.addBatch("insert into  " +
                    "user(create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30', 'User1', 'test', '18700001111', 'User1');");
            statement.addBatch("insert into " +
                    "user (create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30', 'User2', 'test', '18700002222', 'User2');");
            statement.executeBatch();

//PreparedStatement可配置参数方式操作数据库
PreparedStatement stmt = connection.prepareStatement("insert into  " +
                    "user(create_time, name, password, phone, nick_name) " +
                    "values(?,?,?,?,?);");
            stmt.setString(1,"2010-10-24 10:20:30");
            stmt.setString(2,"User1");
            stmt.setString(3,"test");
            stmt.setString(4,"18700001111");
            stmt.setString(5,"User1");
            ParameterMetaData pmd = stmt.getParameterMetaData();
            for(int i = 1; i <= pmd.getParameterCount(); i++) {
                String typeName = pmd.getParameterTypeName(i);
                String className = pmd.getParameterClassName(i);
                System.out.println("第" + i + "个参数," + "typeName:" + typeName + ", className:" + className);
            }
            stmt.execute();

//自增长主键按,可以获取数据库里面自增长的当前值
Statement stmt = conn.createStatement();
            String sql = "insert into user(create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30','User1','test','18700001111','User1');";
            ResultSet genKeys = stmt.getGeneratedKeys();
            stmt.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
            genKeys = stmt.getGeneratedKeys();
            if(genKeys.next()) {
                System.out.println("自增长主键:" + genKeys.getInt(1));
            }

//数据库配置信息
DatabaseMetaData dmd = conn.getMetaData();
            System.out.println("数据库URL:" + dmd.getURL());
            System.out.println("数据库用户名:" + dmd.getUserName());
            System.out.println("数据库产品名:" + dmd.getDatabaseProductName());
            System.out.println("数据库产品版本:" + dmd.getDatabaseProductVersion());
            System.out.println("驱动主版本:" + dmd.getDriverMajorVersion());
            System.out.println("驱动副版本:" + dmd.getDriverMinorVersion());
            System.out.println("数据库供应商用于schema的首选术语:" + dmd.getSchemaTerm());
            System.out.println("数据库供应商用于catalog的首选术语:" + dmd.getCatalogTerm());
            System.out.println("数据库供应商用于procedure的首选术语:" + dmd.getProcedureTerm());
            System.out.println("null值是否高排序:" + dmd.nullsAreSortedHigh());
            System.out.println("null值是否低排序:" + dmd.nullsAreSortedLow());
            System.out.println("数据库是否将表存储在本地文件中:" + dmd.usesLocalFiles());
            System.out.println("数据库是否为每个表使用一个文件:" + dmd.usesLocalFilePerTable());
            System.out.println("数据库SQL关键字:" + dmd.getSQLKeywords());

//保存节点savepoint,可以回滚使用。
String sql1 = "insert into user(create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30','User1','test','18700001111','User1')";
            String sql2 = "insert into user(create_time, name, password, phone, nick_name) " +
                    "values('2010-10-24 10:20:30','User2','test','18700001111','User2')";
            conn.setAutoCommit(false);
            Statement stmt = conn.createStatement();
            stmt.executeUpdate(sql1);
            // 创建保存点
            Savepoint savepoint = conn.setSavepoint("SP1");
            stmt.executeUpdate(sql2);
            // 回滚到保存点
            conn.rollback(savepoint);
            conn.commit();

//后续打印统一代码
			ResultSet rs  = conn.createStatement().executeQuery("select * from user ");
			//上面是下面的简单缩写
			//Statement statement = connection.createStatement();
            //ResultSet resultSet = statement.executeQuery("select * from user");
            // 遍历ResultSet
            ResultSetMetaData metaData = resultSet.getMetaData();
            int columCount = metaData.getColumnCount();
            while (resultSet.next()) {
                for (int i = 1; i <= columCount; i++) {
                    String columName = metaData.getColumnName(i);
                    String columVal = resultSet.getString(columName);
                    System.out.println(columName + ":" + columVal);
                }
                System.out.println("--------------------------------------");
            }
            // 关闭连接
            IOUtils.closeQuietly(statement);
            IOUtils.closeQuietly(connection);

Três, Mybatis ferramentas comumente usadas

1. Use a classe SQL para gerar instruções:

Tradicionalmente, a concatenação de strings requer atenção a detalhes como espaços, o que é muito problemático.Este problema pode ser resolvido pelo encapsulamento de SQL.

Duas maneiras de implementação:

  • new SQL().SELECT().SELECT().FROM()....

  • new SQL(){{SELECT();SELECT();FROM();....}}

O código específico é o seguinte:

String insertSql = new SQL().
            INSERT_INTO("PERSON").
            VALUES("ID, FIRST_NAME", "#{id}, #{firstName}").
            VALUES("LAST_NAME", "#{lastName}").toString();
/*结果是:
INSERT INTO PERSON
 (ID, FIRST_NAME, LAST_NAME)
VALUES (#{id}, #{firstName}, #{lastName})
*/
String sql_area = new SQL()
            {
                {
                    SELECT("P.ID, P.USERNAME, P.PASSWORD");
                    SELECT("P.FIRST_NAME, P.LAST_NAME");
                    FROM("PERSON P");
                    WHERE("P.ID = #{id}");
                    WHERE("P.FIRST_NAME = ${first_name}");
                }
            }.toString();
/*结果是:
SELECT P.ID, P.USERNAME, P.PASSWORD, P.FIRST_NAME, P.LAST_NAME
FROM PERSON P
WHERE (P.ID = #{id} AND P.FIRST_NAME = ${first_name})
*/

2. Use o ScriptRunner para executar scripts

Lógica de origem:

  • Chame o método setAuoCommit () para definir se a transação é confirmada automaticamente com base no valor do atributo autoCommit .
  • Determine o valor do atributo sendFullScript.Se for verdadeiro, chame o método executeFullScript () para ler o conteúdo do arquivo de uma só vez e, em seguida, chame o método execute () do objeto Statement para executar todas as instruções SQL de uma só vez.
  • Se o valor da propriedade sendFullScript for falso, o método executeLineByLine () será chamado para ler o SQ L linha por linha, e a instrução SQL será executada linha por linha como o final de uma instrução SQL.

3. Use o SqlRunner para executar scripts

  • Resumo dos métodos da classe:

  • closeConnection: Feche a conexão conexão.

  • selectOne, selectAll: encontre um registro (retorne um), encontre todos os registros (retorne vários).

  • inserir, atualizar, excluir: inserir, atualizar, excluir operações

  • executar: executar uma instrução sql, de preferência DDL

  • Lógica de origem:

  • Depois de chamar o método PrepareStatement () do objeto Connection para obter o objeto PreparedStatement, chame o método setParameters () para atribuir valores aos espaços reservados de parâmetros no SQL e para determinar o tipo de cada parâmetro .

  • Chame o método executeQuery () de PreparedStatement para executar a operação de consulta

  • Chame o método getResult () para converter o objeto ResultSet em um objeto de lista , onde cada objeto de mapa da lista corresponde a um registro.

Quarto, envolvendo padrões de design

  1. Construtor: SqlSessionFactoryBuilder, XMLConfigBuilder, XMLMapperBuilder, XMLStatementBuilder, CacheBuilder.

  2. Modo de fábrica: por exemplo, SqlSessionFactory, ObjectFactory, MapperProxyFactory;

  3. Modo Singleton: como ErrorContext e LogFactory;

  4. Modo proxy: o núcleo da implementação do Mybatis, como MapperProxy, ConnectionLogger, proxy dinâmico jdk e o pacote executor.loader usa cglib ou javassist para obter o efeito de carregamento lento;

  5. Modo de combinação: por exemplo, SqlNode e várias subclasses ChooseSqlNode, etc;

  6. Padrão do método de modelo: como BaseExecutor e SimpleExecutor, assim como BaseTypeHandler e todas as subclasses como IntegerTypeHandler;

  7. Modo do adaptador: Por exemplo, a interface Mybatis do Log e sua adaptação a várias estruturas de log, como jdbc e log4j;

  8. Modo Decorador: Por exemplo, a implementação de vários decoradores no subpacote cache.decorators no pacote Cache;

  9. Modo iterador: por exemplo, modo iterador PropertyTokenizer;

Cinco, lógica do código fonte

Análise XML = "Get Configuration =" Contém fontes de dados DateSource, statementId e MappedStatement correspondentes variáveis ​​de mapa = "MappedStatement contém sqlSource, parâmetros e tipos de valor de retorno e outras informações de análise XML =" A interface sqlSouce implementa uma variedade de classes, incluindo a classe da interface SqlNode ( O XML analisa o SQL original. Somente quando executado, ele conhecerá o SQL específico, porque há julgamentos e valores de atributos específicos) e obterá o método BoundSql (o resultado do SQL original após a análise é encapsulado apenas em uma classe) => Implementação do Sqlnode A classe é uma lista.Os elementos da lista são uma estrutura em árvore, que armazena os loops de texto e rótulo sob o rótulo sql. Ao mesmo tempo, a classe de implementação SqlSouce possui um valor de atributo BoundSql, que é obtido após a análise do XML obtido e o boundSql é analisado após o resultado da análise de XML obtido durante a execução. = "Executar sql de acordo com o resultado da análise
Insira a descrição da imagem aqui

Publicado 10 artigos originais · Curtidas2 · Visitas 1924

Acho que você gosta

Origin blog.csdn.net/yuhao22/article/details/105619630
Recomendado
Clasificación