One: MyBatis parses the global configuration file

table of Contents

The disadvantages of traditional JDBC compared with Mybatis

Traditional JDBC

The problems of traditional JDBC are as follows:

Mybatis's solution to traditional JDBC

A brief introduction to MyBatis

Mybaits overall system diagram

MyBatis source code compilation

Startup process analysis

Brief summary


The disadvantages of traditional JDBC compared with Mybatis

Traditional JDBC

@Testpublic  void test() throws SQLException {    Connection conn=null;    PreparedStatement pstmt=null;    try {        // 1.加载驱动        Class.forName("com.mysql.jdbc.Driver");         // 2.创建连接        conn= DriverManager.                getConnection("jdbc:mysql://localhost:3306/mybatis_example", "root", "123456");          // SQL语句        String sql="select id,user_name,create_time from t_user where id=?";         // 获得sql执行者        pstmt=conn.prepareStatement(sql);        pstmt.setInt(1,1);         // 执行查询        //ResultSet rs= pstmt.executeQuery();        pstmt.execute();        ResultSet rs= pstmt.getResultSet();         rs.next();        User user =new User();        user.setId(rs.getLong("id"));        user.setUserName(rs.getString("user_name"));        user.setCreateTime(rs.getDate("create_time"));        System.out.println(user.toString());    } catch (Exception e) {        e.printStackTrace();    }    finally{        // 关闭资源        try {            if(conn!=null){                conn.close();            }            if(pstmt!=null){                pstmt.close();            }        } catch (SQLException e) {            e.printStackTrace();        }    }}

The problems of traditional JDBC are as follows:

1. Database connection creation and release frequently cause waste of Xirong resources, thereby affecting system performance. The use of database connection pool can solve the problem.

2. The sql statement is hard-coded in the code, causing the code to be unmaintained. In actual applications, the sql may change a lot, and the sql code and the java code are not separated, which is inconvenient to maintain.

3. The use of preparedStatement to pass parameters to placeholders has a hard-coded problem. Because the conditions of the where clause in sql are uncertain, it is also inconvenient to modify/

4. There is a hard-coded problem in the centralized analysis of the results. The change of sql leads to the change of the parsing code, and the system maintenance is inconvenient.

Mybatis's solution to traditional JDBC

1. Frequent database connection creation and release cause waste of system resources and affect system performance. If you use a database connection pool, you can solve this problem.

Solution: Configure the data connection pool in SqlMapConfig.xml, and use the connection pool to manage database links.

2. Sql statement written in the code makes the code difficult to maintain, and the actual application of sql may change greatly, and sql changes need to change the java code.

Solution: Separate the Sql statement configuration from the java code in the XXXXmapper.xml file.

3. It is troublesome to pass parameters to the sql statement, because the where condition of the sql statement is not necessarily, there may be more or less, and the placeholders need to correspond to the parameters one by one.

Solution: Mybatis automatically maps java objects to sql statements, and defines the type of input parameters through the parameterType in the statement.

4. It is troublesome to parse the result set. SQL changes lead to changes in the parsing code, and it needs to be traversed before parsing. It is more convenient if the database records can be encapsulated into pojo object parsing.

Solution: Mybatis automatically maps the sql execution result to the java object, and defines the type of the output result through the resultType in the statement.

A brief introduction to MyBatis

MyBatis is an ORM framework with a persistence layer, which is simple to use and low in learning costs. You can execute your own handwritten SQL statements, which is more flexible. But MyBatis's degree of automation is not high, and its portability is not high. Sometimes when migrating from one database to another, you need to modify the configuration yourself, so it is only called a semi-automatic ORM framework.

Mybaits overall system diagram

0
0

An example of the simplest use of Mybatis is as follows:

public class App {    public static void main(String[] args) {        String resource = "mybatis-config.xml";        Reader reader;        try {            //将XML配置文件构建为Configuration配置类            reader = Resources.getResourceAsReader(resource);            // 通过加载配置文件流构建一个SqlSessionFactory  DefaultSqlSessionFactory            SqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);            // 数据源 执行器  DefaultSqlSession            SqlSession session = sqlMapper.openSession();            try {                // 执行查询 底层执行jdbc                //User user = (User)session.selectOne("com.tuling.mapper.selectById", 1);                 UserMapper mapper = session.getMapper(UserMapper.class);                System.out.println(mapper.getClass());                User user = mapper.selectById(1L);                System.out.println(user.getUserName());            } catch (Exception e) {                e.printStackTrace();            }finally {                session.close();            }        } catch (IOException e) {            e.printStackTrace();        }    }}

The summary is divided into the following four steps:

  • Get the SessionFactory from the configuration file (usually an XML file);
  • Get SqlSession from SessionFactory;
  • CRUD and transaction operations through SqlSession;
  • After performing related operations, close the Session.

MyBatis source code compilation

The source code compilation of MyBatis is relatively simple, just find a blog on the Internet, not much to say here

https://www.cnblogs.com/mokingone/p/9108999.html

Startup process analysis

String resource = "mybatis-config.xml";//将XML配置文件构建为Configuration配置类reader = Resources.getResourceAsReader(resource);// 通过加载配置文件流构建一个SqlSessionFactory  DefaultSqlSessionFactorySqlSessionFactory sqlMapper = new SqlSessionFactoryBuilder().build(reader);

Through the above code, it is found that the code for creating SqlSessionFactory is in SqlSessionFactoryBuilder. Go in and find out:

//整个过程就是将配置文件解析成Configration对象,然后创建SqlSessionFactory的过程//Configuration是SqlSessionFactory的一个内部属性public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {    try {      XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);      return build(parser.parse());    } catch (Exception e) {      throw ExceptionFactory.wrapException("Error building SqlSession.", e);    } finally {      ErrorContext.instance().reset();      try {        inputStream.close();      } catch (IOException e) {        // Intentionally ignore. Prefer previous error.      }    }  }      public SqlSessionFactory build(Configuration config) {    return new DefaultSqlSessionFactory(config);  }

Let's look at some details in the process of parsing the configuration file.

First give an example of a configuration file:

<?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE configuration        PUBLIC "-//mybatis.org//DTD Config 3.0//EN"        "http://mybatis.org/dtd/mybatis-3-config.dtd"><configuration>    <!--SqlSessionFactoryBuilder中配置的配置文件的优先级最高;config.properties配置文件的优先级次之;properties标签中的配置优先级最低 -->    <properties resource="org/mybatis/example/config.properties">      <property name="username" value="dev_user"/>      <property name="password" value="F2Fa3!33TYyg"/>    </properties>     <!--一些重要的全局配置-->    <settings>    <setting name="cacheEnabled" value="true"/>    <!--<setting name="lazyLoadingEnabled" value="true"/>-->    <!--<setting name="multipleResultSetsEnabled" value="true"/>-->    <!--<setting name="useColumnLabel" value="true"/>-->    <!--<setting name="useGeneratedKeys" value="false"/>-->    <!--<setting name="autoMappingBehavior" value="PARTIAL"/>-->    <!--<setting name="autoMappingUnknownColumnBehavior" value="WARNING"/>-->    <!--<setting name="defaultExecutorType" value="SIMPLE"/>-->    <!--<setting name="defaultStatementTimeout" value="25"/>-->    <!--<setting name="defaultFetchSize" value="100"/>-->    <!--<setting name="safeRowBoundsEnabled" value="false"/>-->    <!--<setting name="mapUnderscoreToCamelCase" value="false"/>-->    <!--<setting name="localCacheScope" value="STATEMENT"/>-->    <!--<setting name="jdbcTypeForNull" value="OTHER"/>-->    <!--<setting name="lazyLoadTriggerMethods" value="equals,clone,hashCode,toString"/>-->    <!--<setting name="logImpl" value="STDOUT_LOGGING" />-->    </settings>     <typeAliases>     </typeAliases>     <plugins>        <plugin interceptor="com.github.pagehelper.PageInterceptor">            <!--默认值为 false,当该参数设置为 true 时,如果 pageSize=0 或者 RowBounds.limit = 0 就会查询出全部的结果-->            <!--如果某些查询数据量非常大,不应该允许查出所有数据-->            <property name="pageSizeZero" value="true"/>        </plugin>    </plugins>     <environments default="development">        <environment id="development">            <transactionManager type="JDBC"/>            <dataSource type="POOLED">                <property name="driver" value="com.mysql.jdbc.Driver"/>                <property name="url" value="jdbc:mysql://10.59.97.10:3308/windty"/>                <property name="username" value="windty_opr"/>                <property name="password" value="windty!234"/>            </dataSource>        </environment>    </environments>     <databaseIdProvider type="DB_VENDOR">        <property name="MySQL" value="mysql" />        <property name="Oracle" value="oracle" />    </databaseIdProvider>     <mappers>        <!--这边可以使用package和resource两种方式加载mapper-->        <!--<package name="包名"/>-->        <!--<mapper resource="./mappers/SysUserMapper.xml"/>-->        <mapper resource="./mappers/CbondissuerMapper.xml"/>    </mappers> </configuration>

The following is the core method of parsing configuration files:

private void parseConfiguration(XNode root) {    try {      //issue #117 read properties first      //解析properties标签,并set到Configration对象中      //在properties配置属性后,在Mybatis的配置文件中就可以使用${key}的形式使用了。      propertiesElement(root.evalNode("properties"));            //解析setting标签的配置      Properties settings = settingsAsProperties(root.evalNode("settings"));      //添加vfs的自定义实现,这个功能不怎么用      loadCustomVfs(settings);              //配置类的别名,配置后就可以用别名来替代全限定名      //mybatis默认设置了很多别名,参考附录部分      typeAliasesElement(root.evalNode("typeAliases"));              //解析拦截器和拦截器的属性,set到Configration的interceptorChain中      //MyBatis 允许你在已映射语句执行过程中的某一点进行拦截调用。默认情况下,MyBatis 允许使用插件来拦截的方法调用包括:      //Executor (update, query, flushStatements, commit, rollback, getTransaction, close, isClosed)        //ParameterHandler (getParameterObject, setParameters)        //ResultSetHandler (handleResultSets, handleOutputParameters)        //StatementHandler (prepare, parameterize, batch, update, query)      pluginElement(root.evalNode("plugins"));            //Mybatis创建对象是会使用objectFactory来创建对象,一般情况下不会自己配置这个objectFactory,使用系统默认的objectFactory就好了      objectFactoryElement(root.evalNode("objectFactory"));      objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));      reflectorFactoryElement(root.evalNode("reflectorFactory"));             //设置在setting标签中配置的配置      settingsElement(settings);         //解析环境信息,包括事物管理器和数据源,SqlSessionFactoryBuilder在解析时需要指定环境id,如果不指定的话,会选择默认的环境;      //最后将这些信息set到Configration的Environment属性里面      environmentsElement(root.evalNode("environments"));              //      databaseIdProviderElement(root.evalNode("databaseIdProvider"));              //无论是 MyBatis 在预处理语句(PreparedStatement)中设置一个参数时,还是从结果集中取出一个值时, 都会用类型处理器将获取的值以合适的方式转换成 Java 类型。解析typeHandler。      typeHandlerElement(root.evalNode("typeHandlers"));      //解析Mapper      mapperElement(root.evalNode("mappers"));    } catch (Exception e) {      throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);    }}
0

After the above analysis process is over, a Configration object will be generated, which contains all configuration information, and then a SqlSessionFactory object will be created, which contains the Configration object.

Brief summary

Here is a brief summary of the process started by MyBatis (the process of obtaining SqlSession):

  • SqlSessionFactoryBuilder parses configuration files, including attribute configuration, alias configuration, interceptor configuration, environment (data source and transaction manager), Mapper configuration, etc.; after parsing these configurations, a Configration object will be generated, which contains all the MyBatis needs Configure, and then use this Configration object to create a SqlSessionFactory object, which contains the Configration object;

There are many things to be parsed here, general overview: all the information will be parsed into the Configration object, which is relatively simple and not much introduction.