Article Directory
- Preface
- project address
- 1. Traditional JDBC problems and custom framework solutions
- 2. Customized persistence layer framework design ideas
-
- 2.1. User side (project): introduce the jar package of the custom persistence layer framework
- 2.2. The custom persistence layer framework itself (engineering): the essence is to encapsulate JDBC
-
- 2.2.1. Read the configuration file:
- 2.2.2. Parsing the configuration file: I use dom4j here, but you can also use other
- 2.2.3. Create the SqlSessionFactory interface and the implementation class DefaultSqlSessionFactory.
- 2.2.4. Create Executor interface and implementation class SimpleExecutor implementation class, create a query method to execute JDBC code.
- 3.genericTokenParserzheg tag parser class
- 4. About sqlessionFactoyBuilder, sqlessionFactoy, sqlession.
- 5. About the return value resultType and input parameter paramterType
- 6. Interface development specification in mybatis
- 7. About mybatis source code content
- 8.Mybatis lazy loading, what is its implementation principle
- 9. The three types of Mybatis Executor, the difference between them
- 10. Mybatis's primary and secondary caches (distributed caching cannot be implemented, a third-party caching framework is required)
- 11. Mybatis plug-in operation principle, and how to write a plug-in
Preface
The output source of the article content: Lagou Education Java High Salary Training Camp. P7 Course
This article is part of the after-school notes in the learning course.
project address
Project code:
Link: https://pan.baidu.com/s/1pdtE7NkQb1SHQo9RnfSOTw
Extraction code: sc4m
Code cloud address: https://gitee.com/nie_jian_ming/njm_all_homework/tree/master/%E7%AC%AC%E4%B8%80%E9%98%B6%E6%AE%B5.%E6%A8% A1%E5%9D%97%E4%B8%80.mybatis%E4%BD%9C%E4%B8%9A
1. Traditional JDBC problems and custom framework solutions
Questions:
1. Frequent creation and release of database connections causes waste of system resources and thus affects system performance.
2. The sql statement, parameter passing, and analysis result set are all hard-coded. SQL changes require changing the java code, which makes the code difficult to maintain.
Solution:
1. Use the database connection pool to initialize connection resources to solve the problem of frequently creating and releasing database connections.
2. Extract sql statements into xml configuration files, use reflection, introspection and other underlying technologies to automatically map entities and tables into attributes and fields, reflection to set parameters, and introspection to return results Set package.
Design patterns involved:
Builder design pattern, manual pattern (session factory), proxy mode (JDK dynamic proxy to generate proxy objects for Dao interface)
2. Customized persistence layer framework design ideas
2.1. User side (project): introduce the jar package of the custom persistence layer framework
- Provide two parts of configuration information: database configuration information, sql configuration information (sql statement, parameter type, return value type)
- Use the configuration file to provide these two parts of configuration information:
1.sqlMapConfig.xml: store database configuration information, import mapper.xml.
2.mapper.xml: store sql configuration information.
2.2. The custom persistence layer framework itself (engineering): the essence is to encapsulate JDBC
2.2.1. Read the configuration file:
- Create a class to load the configuration file into a byte input stream according to the path of the configuration file and store it in memory.
Implementation steps : Create a class Resources, load method: InputSteam getResourceAsSteam(String path)
The configuration information read is stored in the memory in the form of a stream, which is not easy to operate. Here, two javaBeans (container objects) are created for object-oriented thinking. : Store the parsed content of the configuration file, which is also convenient for later access.
Implementation steps : Create two configuration classes
Configuration : Core configuration class: store the content parsed by sqlMapConfig.xml, store basic information of the database, Map<only ID, Mapper> Unique ID: namespace + "." + id
MappedStatement : mapping Configuration class: store the content parsed by mapper.xml, store sql statement, statement type, input parameter java type, output parameter java type
2.2.2. Parsing the configuration file: I use dom4j here, but you can also use other
Implementation steps:
Create the SqlSessionFactoryBuilder class, and then create a method: build(InputSteam in) to build the session factory.
Two things are implemented in the build method:
1. Use dom4j to parse the configuration file and encapsulate the parsed content into a container object.
2. Create SqlSessionFactory (factory mode) object; produce sqlSession session object
2.2.3. Create the SqlSessionFactory interface and the implementation class DefaultSqlSessionFactory.
Then create the SqlSessionFactory interface and the implementation class DefaultSqlSessionFactory based on the opening and closing principle. Write a method for producing sqlSession.
Method: openSession() //Get the implementation class instance object of
sqlSession interface Remember to create the sqlSession interface and the implementation class DefaultSqlSession to encapsulate the CRUD method of JDBC.
2.2.4. Create Executor interface and implementation class SimpleExecutor implementation class, create a query method to execute JDBC code.
Method: query(Configuration,MappedStatement,Object... params);
Configuration : When using dom4j to parse sqlMapConfig.xml, the parsed content will be encapsulated into the Configuration object in different forms, and the information in the database configuration is stored inside.
MappedStatement : When using dom4j to parse mapper.xml, the content of each tag corresponds to a mappedStatement object, which stores the SQL information
Object... params : This is the parameter passed in by the user, because it is not sure how many will be worn. So Object... Variable parameters
3.genericTokenParserzheg tag parser class
- This class can only be created through parameterized construction
- genericTokenParser is a generic token parser class
- When genericTokenParser parses #{} placeholders, it must cooperate with tokenHandler
- The three construction parameters of genericTokenParser are start tag, end tag, and tag processor
4. About sqlessionFactoyBuilder, sqlessionFactoy, sqlession.
- The best scope of sqlessionFactoyBuilder is the method scope, which can be defined as a local method variable
- The best range of sqlessionFactoy is the application range
- The best scope of sqlession is the method scope or the request scope
5. About the return value resultType and input parameter paramterType
- The return value type of resultType is: full class name or alias, basic data types are allowed, String, int, etc.
- The data structure of resultType and resultMap is the same, both are map structures
- In mybatis, in addition to using the @param annotation to implement multiple parameter entry, you can also use the Map object to implement multiple parameter transfer
6. Interface development specification in mybatis
- The namespace in mapper.xml is the same as the classpath of the mapper interface
- The mapper interface method name is the same as the id of each statement defined in mapper.xml
- The input parameter type of the mapper interface method is the same as the parameterType type of each SQL defined in mapper.xml
- The output parameter type of the mapper interface method is the same as the resultType type of each sql defined in mapper.xml
7. About mybatis source code content
- The design patterns involved are: agent model, builder (builder/constructor) model, factory model, iterator model
- The functional architecture can be divided into three layers: interface layer, data processing layer, framework support layer
- Support plug-ins to intercept core objects such as statementHandler, paramterHandle, and resultsHandler
- Executor is the executor, responsible for sql generation and query cache maintenance
- statementtHandler encapsulates jdbc statement (the interface for executing database sql) operations and is responsible for the operation of jdbc statement
- typeHandler is responsible for the mapping and conversion between java data types and jdbc data types
- sqlSource is responsible for dynamically producing SQL statements according to the parameterObject passed by the user, and encapsulating the information into the boundsql() object
8.Mybatis lazy loading, what is its implementation principle
Mybatis supports lazy loading and
only supports lazy loading of association objects and collection objects;
association refers to one-to-one, and collection refers to one-to-many query.
In the configuration file, you can configure whether to enable lazy loading lazyLoadingEnabled=true|false.
<settings>
<!-- 打开延迟加载的开关 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 将积极加载改为消极加载,即延迟加载 -->
<setting name="aggressiveLazyLoading" value="false"/>
</settings>
Implementation principle
Use CGLIB to create the proxy object of the target object. When the target method is called, it enters the interceptor
method. When the data is needed, it calls SQL to query the DB.
For example: when a.getB().getName() is called, the interceptor invoke() method finds that a.getB() is a
null value, then it will separately send the sql saved in advance to query the associated B object, and query B. Then call a.setB(b), so the object b attribute of a has a value, and then complete the call of the a.getB().getName() method.
9. The three types of Mybatis Executor, the difference between them
The default is SimplExcutor
SimpleExecutor: every time an update or select is executed, a Statement object is opened, and the Statement object is closed immediately after use.
ReuseExecutor: Execute update or select, use sql as the key to find the Statement object, use it if it exists, and create it if it does not exist. After use, the Statement object is not closed but placed in the Map for the next use.
In short, it is to reuse the Statement object.
BatchExecutor: execute update (no select, JDBC batch processing does not support select), add all sql to the batch addBatch(), wait for the unified execution of executeBatch(), it caches multiple Statement objects, each Statement object is After addBatch() completes, wait for executeBatch() batch processing one by one.
Same as JDBC batch processing.
Scope of action: These characteristics of Executor are strictly limited to the scope of the SqlSession life cycle.
In the Mybatis configuration file, you can specify the default ExecutorType actuator type, or you can manually pass the ExecutorType type parameter to the method of creating SqlSession of DefaultSqlSessionFactory.
10. Mybatis's primary and secondary caches (distributed caching cannot be implemented, a third-party caching framework is required)
1. Storage structure: the first level cache and the second level cache are all cached in the HashMap structure.
2. Scope: The
first level cache is at the SqlSession level, and the scope is SqlSession. Mybatis turns on the first level cache by default. In the same SqlSession, when the same Sql is queried, the first query will be taken from the cache If there is no data, then query it from the DB and cache it in the HashMap. The second query is directly fetched from the cache, and if there is data, it will be returned directly without checking the DB.
The second-level cache is at the mapper level. Multiple SqlSessions operate on the same mapper's SQL statement. Multiple SqlSessions can share the second-level cache. The second-level cache is across SqlSessions.
When the sql under mapper is called for the first time, the information is queried. The queried information will be stored in the secondary cache area corresponding to the mapper. The second time the mapper mapping file under the namespace is called, the same SQL is used to query directly. Fetch the result in the secondary cache.
3. Invalidation scenario:
When the first level cache is added, deleted, or modified, the cache will be invalidated.
In spring container management, each query creates a new sqlSession, so there will be no data inconsistency in a distributed environment.
When using the second-level cache, you need to open the cache tag, add the useCache attribute to true on the select, and manually enable flushCache to refresh the cache when updating and deleting. If useCache=false is set, the second level cache is turned off.
11. Mybatis plug-in operation principle, and how to write a plug-in
The methods of interception allowed by MyBatis are as follows:
Executor: (update, query, commit, rollback, etc. methods);
SQL syntax builder StatementHandler: (prepare, parameterize, batch, updates query, etc. methods);
parameter processor ParameterHandler: (getParameterObject, setParameters methods);
ResultSetHandler: (handleResultSets, handleOutputParameters, etc. methods);
1. Operating principle:
Mybatis can write plug-ins for the four interfaces of Executor, StatementHandler, ParameterHandler, and ResultSetHandler. Mybatis uses the dynamic proxy of JDK to generate proxy objects for the interfaces that need to be intercepted, and then implements the interception method of the interface, so when the execution needs to be intercepted When the interface method, it will enter the interception method (AOP thought).
2. How to write:
1. Write the implementation class of the Intercepror interface
2. Set the signature of the plug-in, tell mybatis which method of which object to intercept
3. Finally, register the plug-in in the global configuration file
Example:
package com.njm.plugin;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import java.sql.Connection;
import java.util.Properties;
//插件签名,告诉mybatis当前插件拦截哪个对象的哪个方法
@Intercepts({ //这是个⼤花括号,也就这说这⾥可以定义多个@Signature,对多个地⽅拦截,都⽤这个拦截器
/*
type:表示要拦截的核心(目标)对象,拦截哪个接⼝,StatementHandler是一个sql语句构建器,用来完成sql语句预处理
method:表示要要拦截的方法,prepare是StatementHandler里的sql预编译方法
args:表示要拦截方法的参数,按方法里的参数顺序写,可能方法有重载,所以要通过⽅法名和⼊参来确定唯⼀。
*/
@Signature(type = StatementHandler.class,
method = "prepare",
args = {Connection.class,Integer.class})
})
public class MyPlugin implements Interceptor {
//截方法:只要被拦截的目标对象的目标方法被执行时,每次都会执行intercept方法
@Override
public Object intercept(Invocation invocation) throws Throwable {
/*
* 插件的主要功能:在执行目标方法之前,可以对sql进行修改已完成特定的功能
* 例如增加分页功能,实际就是给sql语句添加limit;还有其他等等操作都可以
* */
System.out.println("对方法进行了增强。。。。。。。");
return invocation.proceed(); //invocation.proceed():原方法执行并返回值
}
//主要为了把当前的拦截器生成代理存到拦截器链中,包装目标对象,为目标对象创建代理对象
@Override
public Object plugin(Object target) {
//target:被拦截的目标对象,this:表示当前自定义的插件实现类,当前拦截器,也就是现在这个类,
//wrap方法利用mybatis封装的方法为目标对象创建代理对象(没有拦截的对象会直接返回,不会创建代理对象)
Object wrap = Plugin.wrap(target, this);
return wrap;
}
//获取配置文件的参数,就是获取插件在配置文件中配置的参数值
//插件初始化的时候调⽤,也只调⽤⼀次,插件配置的属性从这⾥设置进来
@Override
public void setProperties(Properties properties) {
System.out.println("获取到的配置文件的参数是:"+properties);
}
}
The plugin is registered in the global configuration file
<!--配置自定义插件类
interceptor:配置类的路径
property:配置的参数-->
<plugins>
<!--这个是我自定义的插件-->
<plugin interceptor="com.njm.plugin.MyPlugin">
<property name="name" value="tom"/>
</plugin>
<!--这是分页插件,上面的是我自定义的插件-->
<!-- <plugin interceptor="com.github.pagehelper.PageHelper">-->
<!--指定方言-->
<!-- <property name="dialect" value="mysql"/>-->
<!-- </plugin>-->
</plugins>