Preparación del análisis del código fuente de Mybatis

Preparación del análisis del código fuente de Mybatis

consejos : mybatis

1. Cree el entorno de origen de Mybatis

1. Requisitos ambientales:

JDK1.8, Maven, Eclipse o IntelliJ IDEA

2. Obtenga el código fuente

  • Código fuente de Mybatis:

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

  • Código fuente integrado Mybatis y Spring:

https://github.com/mybatis/spring

  • Código fuente de la clase principal de Mybatis:

https://github.com/mybatis/parent

3. Importe el código fuente al IDE

  • Archivo => Nuevo => Proyecto ... => Proyecto vacío => Siguiente => 命名 => Finalizar

  • Archivo => Nuevo => Módulo de fuentes existentes ... => Seleccione tres códigos fuente y un código de prueba respectivamente e impórtelos por separado

4. Introducción a HSQLDB

  • El modo de memoria de HSQLDB incorporado en Mybatis se utiliza como base de datos para pruebas unitarias, por lo que no es necesario instalar bases de datos como Mysql.
  • El nombre de usuario y la contraseña del modo de memoria se pueden especificar a voluntad, pero si necesita conservarlo localmente, debe especificar el nombre de usuario y la contraseña.
  • A las pruebas unitarias no les importa, se pueden especificar a voluntad. El nombre de usuario predeterminado es sa y la contraseña está en blanco.
  • ScriptRunner se usa para ejecutar scripts (XXX.sql), y SqlRunner se usa para ejecutar declaraciones sql (declaraciones de adición, eliminación, modificación y consulta).

5. Entrada de análisis de código fuente:

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();
        }
    }
}

En segundo lugar, la especificación JDBC

1. documento de especificación jdbc

  • Dirección de descarga del documento de especificación JDBC4.2: https://download.oracle.com/otndocs/jcp/jdbc-4_2-mrel2-spec/index.html

2. Pasos para operar la base de datos

  • Establecer una conexión de datos
  • Ejecutar sentencia SQL
  • Recuperar resultados de ejecución SQL
  • Conexión cercana

3. Establecer una conexión a la base de datos

Tres formas:

  • DriverManager —— proporcionado por JDBC1.0

    Necesita mostrar la clase de controlador de carga:

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

  • DataSource —— proporcionado por JDBC2.0 (configuración recomendada, más flexible)

    • DataSource: la clase más básica
    • DataSourceFactory: clase de fábrica
    • ConnectionPoolDataSource: admite el almacenamiento en caché y la reutilización de objetos Connection
    • XADataSource: admite transacciones distribuidas

El código fuente es el siguiente:

//第一种方式
// 加载驱动 到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);

Tres, Mybatis herramientas de uso común

1. Use la clase SQL para generar declaraciones:

Tradicionalmente, la concatenación de cadenas requiere atención a detalles como espacios, lo cual es muy problemático. Este problema puede resolverse mediante encapsulación SQL.

Dos formas de implementación:

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

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

El código específico es el siguiente:

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 ScriptRunner para ejecutar scripts

Lógica de origen:

  • Llame al método setAuoCommit () para establecer si la transacción se confirma automáticamente en función del valor del atributo autoCommit .
  • Determine el valor del atributo sendFullScript . Si es verdadero, llame al método executeFullScript () para leer el contenido del archivo a la vez , y luego llame al método execute () del objeto Statement para ejecutar todas las declaraciones SQL a la vez.
  • Si el valor de la propiedad sendFullScript es falso, se llama al método executeLineByLine () para leer el SQ L línea por línea, y la declaración SQL se ejecuta línea por línea como el final de una declaración SQL.

3. Use SqlRunner para ejecutar scripts

  • Resumen de los métodos de clase:

  • closeConnection: cierra la conexión de conexión.

  • selectOne, selectAll: encuentre un registro (devuelva uno), encuentre todos los registros (devuelva múltiples).

  • insertar, actualizar, eliminar: insertar, actualizar, eliminar operaciones

  • ejecutar: ejecutar una instrucción sql, preferiblemente DDL

  • Lógica de origen:

  • Después de llamar al método PrepareStatement () del objeto Connection para obtener el objeto PreparedStatement, llame al método setParameters () para asignar valores a los marcadores de posición de parámetros en SQL y determinar el tipo de cada parámetro .

  • Llame al método executeQuery () de PreparedStatement para ejecutar la operación de consulta

  • Llame al método getResult () para convertir el objeto ResultSet en un objeto List , donde cada objeto Map de List corresponde a un registro.

Cuarto, involucrando patrones de diseño

  1. Builder 模式 : 例如 SqlSessionFactoryBuilder 、 XMLConfigBuilder 、 XMLMapperBuilder 、 XMLStatementBuilder 、 CacheBuilder ;

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

  3. Modo Singleton: como ErrorContext y LogFactory;

  4. Modo proxy: el núcleo de la implementación de Mybatis, como MapperProxy, ConnectionLogger, jdk dynamic proxy; y el paquete executeor.loader usa cglib o javassist para lograr el efecto de carga lenta;

  5. Modo de combinación: por ejemplo, SqlNode y varias subclases ChooseSqlNode, etc.

  6. Patrón de método de plantilla: como BaseExecutor y SimpleExecutor, así como BaseTypeHandler y todas las subclases como IntegerTypeHandler;

  7. Modo de adaptador: por ejemplo, la interfaz Mybatis de Log y su adaptación a varios marcos de registro como jdbc y log4j;

  8. Modo de decorador: por ejemplo, la implementación de varios decoradores en el subpaquete cache.decorators en el paquete Cache;

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

Cinco, código fuente lógico

XML parsing = "Get Configuration =" Contiene el origen de datos DateSource, StatementId y MappedStatement Variables de mapa correspondientes = "MappedStatement contiene sqlSource, parámetros y tipos de valores de retorno y otra información de análisis XML =" La interfaz sqlSouce implementa una variedad de clases, incluida la clase de interfaz SqlNode ( XML analiza el SQL original. Solo cuando se ejecute, sabrá el SQL específico, porque hay juicios y valores de atributos específicos) y obtendrá el método BoundSql (el resultado del SQL original después del análisis solo se encapsula en una clase) => Implementación de Sqlnode La clase es una lista. Los elementos en la lista son una estructura de árbol, que almacena el texto y los bucles de etiquetas bajo la etiqueta sql. Al mismo tiempo, la clase de implementación SqlSouce tiene un valor de atributo BoundSql. Sqlsouce se obtiene después de analizar el XML obtenido, y boundSql se analiza después del resultado de análisis XML obtenido durante la ejecución. = "Ejecutar sql de acuerdo con el resultado del análisis
Inserte la descripción de la imagen aquí

10 artículos originales publicados · Me gusta2 · Visitas 1924

Supongo que te gusta

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