Home > Java > javaTutorial > After learning the MyBatis source code in one week, I got a 10,000-word summary

After learning the MyBatis source code in one week, I got a 10,000-word summary

Release: 2023-08-23 14:51:14
forward
1230 people have browsed it

As we all know, MyBatis is a product that encapsulates JDBC, so , before talking about MyBatis source code, we must first understand JDBC.

JDCB

JDBC Case:

public class JdbcDemo {
    public static final String URL = "jdbc:mysql://localhost:3306/mblog";
    public static final String USER = "root";
    public static final String PASSWORD = "123456";

    public static void main(String[] args) throws Exception { 
        Class.forName("com.mysql.jdbc.Driver"); 
        Connection conn = DriverManager.getConnection(URL, USER, PASSWORD); 
        Statement stmt = conn.createStatement(); 
        ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1"); 
        while(rs.next()){
            System.out.println("name: "+rs.getString("name")+" 年龄:"+rs.getInt("age"));
        }
    }
}
Copy after login

Description:

Database driver:

Class.forName("com.mysql.jdbc.Driver");
Copy after login

Get connection:

Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
Copy after login

Create Statement or PreparedStatement object:

Statement stmt = conn.createStatement();
Copy after login

执行sql数据库查询:

ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1");
Copy after login

解析结果集:

System.out.println("name: "+rs.getString("name")+" 年龄:"+rs.getInt("age"));
Copy after login

在使用的时候,业务处理完成后记得关闭相关资源

使用过JDCB的朋友都知道,JDBC如果用到我们项目中基本上都会存在以下几个问题:

传统JDBC的问题

  • 创建数据库的连接存在大量的硬编码,
  • 执行statement时存在硬编码.
  • 频繁的开启和关闭数据库连接,会严重影响数据库的性能,浪费数据库的资源.
  • 存在大量的重复性编码

针对上面这些问题,于是一大堆持久化框架应运而生。

持久化框

做持久层的框架有很多,有orm系和utils系列。

Representatives of the
  • orm series include: hibernate, eclipseLink, topLink;
    ## Representatives of the
  • #utils series include: MyBatis, dbUtils, jdbcTemplate, etc.;
The following is a brief overview of these frameworks:

As for jpa, it is only a specification standard, not a specific framework, and is not equivalent to spring-data-jpa; at the same time, spring-data-jpa is also It is not a specific implementation of jpa, it is just a further encapsulation of the jpa specification standard. hibernate is the most common implementation framework for jpa, of course others include eclipseLink and topLink.

The characteristics of MyBatis are that when optimizing SQL, the optimization of complex SQL is highly controllable, and the internal calling level of the framework is simple. In addition to some parts of the code that can be automatically generated, there are also many SQLs that need to be coded by yourself. The characteristic of spring-data-jpa (hibernate) is that during the development process, it is developed without SQL coding. Of course, it also supports local SQL for query, and the internal calling level of the framework is complex. Based on the above, you can make a choice based on actual business progress and business support.

In fact, you can support MyBatis and spring-data-jpa at the same time in one project. For complex SQL, use mybatis, and for common SQL, use spring-data-jpa.

In view of the number of uses in actual development, we selected

MyBatis for analysis.

mybatis

Friends who are new to development may not know the predecessor of MyBatis. Before 2010, I will not pay MyBatis, called ibatis.

MyBatis is an excellent persistence layer framework that supports customized SQL, stored procedures and advanced mapping. MyBatis avoids almost all JDBC code and manual setting of parameters and retrieval of result sets. MyBatis You can use simple XML or annotations to configure and map native information, mapping interfaces and Java's POJOs (Plain Ordinary Java Object, ordinary Java objects) into records in the database .

特点

  • 简单易学:本身就很小且简单。没有任何第三方依赖,最简单安装只要两个jar文件+配置几个sql映射文件易于学习,易于使用,通过文档和源代码,可以比较完全的掌握它的设计思路和实现。
  • 灵活:MyBatis 不会对应用程序或者数据库的现有设计强加任何影响。 sql写在xml里,便于统一管理和优化。通过sql语句可以满足操作数据库的所有需求。
  • 解除sql与程序代码的耦合:通过提供DAO层,将业务逻辑和数据访问逻辑分离,使系统的设计更清晰,更易维护,更易单元测试。sql和代码的分离,提高了可维护性。
  • 提供映射标签,支持对象与数据库的orm字段关系映射
  • 提供对象关系映射标签,支持对象关系组建维护
  • 提供xml标签,支持编写动态sql。

案例

需要来源两个jar包:MyBatis的jar包和MySQL数据库连接jar包。

<dependency>
  <groupId>org.mybatis</groupId>
  <artifactId>mybatis</artifactId>
  <version>x.x.x</version>
</dependency>
<dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>8.0.16</version>
</dependency>
Copy after login

创建一个表t_user(数据库也是肯定要自己创建的哈)

 CREATE TABLE `t_user` (
      `id` int(11) NOT NULL AUTO_INCREMENT,
      `name` varchar(255) DEFAULT NULL,
      `age` int(11) DEFAULT NULL,
      PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;
Copy after login

插入一条数据:

INSERT INTO `t_user` VALUES ('1', 'tian', '19', '1');
Copy after login

创建该数据库表的实体类:

public class User {
    private Integer id;
    private String name;
    private Integer age;
    //set get
}
Copy after login

创建mapper配置文件:UserMapper.xml

<?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="com.tian.mapper.UserMapper">
    <select id="selectUserById" resultType="com.tian.domain.User">
        select * from t_user where id = #{id}
    </select>
</mapper>
Copy after login

创建mapper接口:UserMapper.java

import com.tian.domain.User;

public interface UserMapper {
    User selectUserById(Integer id);
}
Copy after login

MyBatis 整体配置文件:

<?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>
    <environments default="development">
        <environment id="development">
            <transactionManager type="JDBC"/>
            <dataSource type="POOLED">
                <property name="driver" value="com.mysql.cj.jdbc.Driver"/>
                <property name="url" value="jdbc:mysql://localhost:3306/mblog?useUnicode=true&amp;characterEncoding=utf8&amp;autoReconnect=true&amp;useSSL=false&amp;serverTimezone=UTC"/>
                <property name="username" value="root"/>
                <property name="password" value="123456"/>
            </dataSource>
        </environment>
    </environments>
    <mappers>
        <mapper resource="mappers/UserMapper.xml"/>
    </mappers>
</configuration>
Copy after login

上面这些就是我们使用MyBatis基本开发代码。

下面我们来写一个测试类:

import com.tian.domain.User;
import com.tian.mapper.UserMapper;
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 java.io.IOException;
import java.io.InputStream;

public class MybatisApplication {

    public static void main(String[] args) {
        String resource = "mybatis-config.xml";
        InputStream inputStream = null;
        SqlSession sqlSession =null;
        try {
            //读取配置文件
            inputStream = Resources.getResourceAsStream(resource);
            //创建SqlSession工厂
            SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
            //创建sql操作会话
            sqlSession = sqlSessionFactory.openSession();
            UserMapper userMapper=sqlSession.getMapper(UserMapper.class);
            //获取数据并解析成User对象
            User user = userMapper.selectUserById(1);
            //输出
            System.out.println(user);
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            //关闭相关资源
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            sqlSession.close();
        }
    }

}
Copy after login

测试结果:

User{id=1, name='tian', age=19}

如上面的代码所示,SqlSession是MyBatis中提供的与数据库交互的接口,SqlSession实例通过工厂模式创建。

为了创建SqlSession对象,首先需要创建SqlSessionFactory对象,而SqlSessionFactory对象的创建依赖于SqlSessionFactoryBuilder类,该类提供了一系列重载的build()方法,我们需要以主配置文件的输入流作为参数调用SqlSessionFactoryBuilder对象的bulid()方法,该方法返回一个SqlSessionFactory对象。

After you have the SqlSessionFactory object, call the SqlSessionFactory object's openSession() method to obtain a SqlSession## that establishes a connection with the database. #Instance.

We defined the

UserMapper interface earlier. Here we need to call the getMapper() method of SqlSession to create a dynamic proxy object, and then call UserMapperThe method of proxy instance can complete the interaction with the database.

For the above case, let’s sort out the overall execution process and core components of

MyBatis.

MyBatis core components

MyBatis execution process

After learning the MyBatis source code in one week, I got a 10,000-word summary


Configuration

is used to describe the main configuration information of MyBatis, others When a component needs to obtain configuration information, it can be obtained directly through the Configuration object. In addition, MyBatis registers Mapper configuration information, type aliases, TypeHandler, etc. into the Configuration component when the application starts. When other components need this information, they can also download it from Configuration Obtained from the object.

MappedStatement

MappedStatement is used to describe the SQL configuration information in Mapper, which is a reference to the Mapper XML configuration file# An encapsulation of configuration information with tags such as ## or annotations such as @Select/@Update.

SqlSession

SqlSession is the user-oriented API provided by MyBatis, which represents the session object when interacting with the database. Used to complete the addition, deletion, modification and query functions of the database. SqlSession is the appearance of the Executor component, which aims to provide an easy-to-understand and use database operation interface to the outside world.

Executor

Executor is the SQL executor of MyBatis. All add, delete, modify and query operations on the database in MyBatis are performed by Executor The component is completed.

StatementHandler

StatementHandlerencapsulates operations on JDBC Statement objects, such as Statement The object sets parameters, calls the methods provided by the Statement interface to interact with the database, and so on.

ParameterHandler

When the Statement type used by the MyBatis framework is CallableStatement and When PreparedStatement is used, ParameterHandler is used to set values ​​for Statement object parameter placeholders.

ResultSetHandler

ResultSetHandlerencapsulates the operation of the ResultSet object in JDBC, when executing the SQL type SELECT statement , ResultSetHandler is used to convert query results into Java objects.

TypeHandler

TypeHandler is the type processor in MyBatis, used to handle the mapping between Java types and JDBC types. Its function is mainly reflected in the ability to call the PreparedStatement or CallableStatement method corresponding to the setXXX() object according to the Java type, and can set the value for the Statement object according to the Java type Call getXXX() corresponding to the ResultSet object to obtain the SQL execution result.

Using JDBC API to develop applications, one of the more cumbersome aspects is processing the conversion between JDBC types and Java types. The two situations involving Java type and JDBC type conversion are as follows:

  • PreparedStatementWhen the object sets the value for the parameter placeholder, it needs to call a series of setXXX()## provided in the PreparedStatement interface #Method, convert Java types to corresponding JDBC types and assign values ​​to parameter placeholders.
  • After executing the SQL statement to obtain the
    ResultSet object, you need to call the getXXX() method of the ResultSet object to obtain the field value. At this time, the JDBC Type conversion to Java type.

MyBatis provides TypeHandler and the corresponding relationship between Java types and JDBC types:

After learning the MyBatis source code in one week, I got a 10,000-word summary

Summary

We use the

SqlSession component, which is a user-level API. In fact, SqlSession is the appearance of the Executor component, which aims to provide users with a more friendly database operation interface. This is a typical application of the appearance pattern in the design pattern.

It is the Executor component that actually performs SQL operations. Executor can be understood as a SQL executor. It will use the

StatementHandler component to operate the JDBC Statement object.

When the Statement type is CallableStatement and PreparedStatement, the parameter placeholder will be assigned a value through the ParameterHandler component. ParameterHandler The component will find the corresponding TypeHandler object based on the Java type. The TypeHandler will use the setXXX() method provided by the Statement object ( For example, the setString() method) sets the value for the parameter placeholder in the Statement object.

StatementHandlerAfter the component uses the Statement object in JDBC to complete the interaction with the database, when the SQL statement type is SELECT, MyBatis obtains the ResultSet from the Statement object through the ResultSetHandler component. object and then convert the ResultSet object to a Java object.

Advanced Skills

##Design Pattern

Design patterns are widely used in MyBatis. In MyBatis we can learn several design patterns:

  • Factory pattern
  • Template method pattern
  • Agent pattern
  • Builder pattern
  • Singleton pattern
  • Adaptation pattern
  • Decorator pattern
  • Chain of responsibility model
  • ....

Cache

In web applications, caching is an essential component. Usually we use caching middleware such as Redis or memcached to intercept a large number of requests to the database and reduce the pressure on the database. As an important component, MyBatis naturally also provides corresponding support internally. By adding caching functions at the framework level, the pressure on the database can be reduced and the query speed can be improved at the same time. It can be said that it kills two birds with one stone.

MyBatis cache structure consists of level one cache and second level cache. Both levels of cache are implementation classes using the Cache interface. Therefore, in the following chapters, I will first introduce you to the source code of several Cache implementation classes, and then analyze the implementation of first-level and second-level cache.

The use of MyBatis first-level cache and second-level cache: MyBatis first-level cache is a SqlSession-level cache. It is enabled by default and cannot be turned off; the second-level cache needs to be set in the MyBatis main configuration file by setting the cacheEnabled parameter. value to enable.

The first level cache is implemented in Executor. MyBatis's Executor component has three different implementations, namely SimpleExecutor, ReuseExecutor and BatchExecutor. These classes all inherit from BaseExecutor. In the query() method of the BaseExecutor class, the query results are first obtained from the cache. If not, the results are retrieved from the database, and then the query results are cached. The second-level cache of MyBatis is implemented through the decorator mode. When the second-level cache is enabled through the cacheEnabled parameter, the MyBatis framework will use CachingExecutor to SimpleExecutor, ReuseExecutor or BatchExecutor is decorated. When a query operation is performed, the query results are cached, and when an update operation is performed, the secondary cache is updated. This chapter finally introduces how MyBatis integrates Redis as a secondary cache.

In addition, MyBatis also supports Ehcache, OSCache, etc. This feature is not commonly used.

Plug-ins

Most frameworks support plug-ins. Users can extend their functions by writing plug-ins, and Mybatis is no exception.

MyBatis provides an extension mechanism that can change the execution behavior of SQL when executing Mapper. This extension mechanism is implemented through interceptors, and user-defined interceptors are also called MyBatis plug-ins.

MyBatis framework supports interception of the methods of four components: Executor, ParameterHandler, ResultSetHandler, StatementHandler. Master the implementation principle of the MyBatis plug-in, and then implement a paging query plug-in and a slow SQL statistics plug-in. When the functions we need cannot be satisfied by the MyBatis framework, we can consider implementing them through custom plug-ins.

Classic implementation: PageHelper.

Log

MyBatis provides corresponding implementations of the Log interface for different logging frameworks. The implementation class of the Log interface is shown in the figure below Show. As can be seen from the implementation class, MyBatis supports 7 different log implementations, as detailed below.

After learning the MyBatis source code in one week, I got a 10,000-word summary

The following is a brief explanation of the commonly used ones:

  • Apache Commons Logging: Using JCL Output log.
  • Log4j 2: Use Log4j 2 framework to input logs.
  • Java Util Logging: Use the JDK's built-in log module to output logs.
  • Log4j: Use the Log4j framework to output logs.
  • No Logging: No logs are output.
  • SLF4J: Use the SLF4J log facade to output logs.
  • Stdout: Output logs to the standard output device (such as the console).

The order in which MyBatis searches for log frames is

SLF4J→JCL→Log4j2→Log4j→JUL→No Logging.

If there is no logging framework under the Classpath, use the NoLoggingImpl log implementation class, that is, no logs will be output.

Dynamic SQL Binding

Dynamic SQL refers to the specific conditions that cannot be predicted in advance and need to be dynamically generated according to the specific situation at runtime. Generate SQL statements.

There are a wealth of dynamic SQL tags in MyBatis, such as: <where>, <if>, <choose|when|otherwise&gt ;, <foreach>, etc.

There is a SqlSource object in the MyBatis source code that will be saved in the MappedStatement object as a property of the MappedStatement object. When Mapper is executed, the getBoundSql() method of the SqlSource object is called based on the incoming parameter information to obtain the BoundSql object. This process completes the process of converting the SqlNode object into a SQL statement.

For example:, #{}The placeholder will be replaced with "?", and then the setXXX() method of the PreparedStatement object in JDBC is called to set the value for the parameter placeholder, and $ The {} placeholder will be directly replaced with the passed parameter text content.

Summary

This article is the overall experience of MyBatis source code analysis. I hope it will be of some help to you.

The above is the detailed content of After learning the MyBatis source code in one week, I got a 10,000-word summary. For more information, please follow other related articles on the PHP Chinese website!

Related labels:
source:Java后端技术全栈
Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn
Popular Tutorials
More>
Latest Downloads
More>
Web Effects
Website Source Code
Website Materials
Front End Template