As we all know, MyBatis
is a product that encapsulates JDBC
, so , before talking about MyBatis source code, we must first understand JDBC
.
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")); } } }
Description:
Database driver:
Class.forName("com.mysql.jdbc.Driver");
Get connection:
Connection conn = DriverManager.getConnection(URL, USER, PASSWORD);
Create Statement
or PreparedStatement
object:
Statement stmt = conn.createStatement();
执行sql数据库查询:
ResultSet rs = stmt.executeQuery("SELECT id, name, age FROM m_user where id =1");
解析结果集:
System.out.println("name: "+rs.getString("name")+" 年龄:"+rs.getInt("age"));
在使用的时候,业务处理完成后记得关闭相关资源
使用过JDCB的朋友都知道,JDBC如果用到我们项目中基本上都会存在以下几个问题:
针对上面这些问题,于是一大堆持久化框架应运而生。
做持久层的框架有很多,有orm
系和utils
系列。
orm
series include: hibernate
, eclipseLink
, topLink
; series include:
MyBatis,
dbUtils,
jdbcTemplate, etc.;
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.
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包: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>
创建一个表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;
插入一条数据:
INSERT INTO `t_user` VALUES ('1', 'tian', '19', '1');
创建该数据库表的实体类:
public class User { private Integer id; private String name; private Integer age; //set get }
创建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>
创建mapper接口:UserMapper.java
import com.tian.domain.User; public interface UserMapper { User selectUserById(Integer id); }
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&characterEncoding=utf8&autoReconnect=true&useSSL=false&serverTimezone=UTC"/> <property name="username" value="root"/> <property name="password" value="123456"/> </dataSource> </environment> </environments> <mappers> <mapper resource="mappers/UserMapper.xml"/> </mappers> </configuration>
上面这些就是我们使用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(); } } }
测试结果:
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.
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.
MyBatis.
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 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 ##b5d5a6a8d1a81baf21ea188537c0af35 or annotations such as
@Select/@Update.
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
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
encapsulates 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.
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
encapsulates 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
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:
PreparedStatement
When 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.
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:
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.
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.
StatementHandler
After 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.
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.
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.
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.
The following is a brief explanation of the commonly used ones:
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 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: 196185dae55b7edbe154a5051db664a7
, f3bf5eff46860b27119c8dd4e92f1e57
, 0cc9641c8831aac22f6e1b15c62b0af6
, 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.
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!