赞
踩
计算机的基本工作就是存储和计算,而MyBatis是存储领域的利器。MyBatis的基本工作原理就是:先封装SQL,接着调用JDBC操作数据库,最后把数据库返回的表结果封装成Java类。
mybatis应用程序通过SqlSessionFactoryBuilder从mybatis-config.xml配置文件中构建出SqlSessionFactory,然后,SqlSessionFactory的实例直接开启一个SqlSession,再通过SqlSession实例获得Mapper对象并运行Mapper映射的SQL语句,完成对数据库的CRUD和事务提交,之后关闭SqlSession。如下图所示:
MyBatis的工作原理如下图所示:
sqlsessionfactoryBuilder类加载核心配置文件(sqlmapConfig.xml)parse方法会产生会产生一个configration对象, configration对象通过构造方法的方式交给sqlsessionfactory对象。sqlsessionfactory产生sqlsession对象,并且将configuration对象通过sqlsession 构造方法的方式传给sqlsession对象。Sqlsession通configration对象拿到excutor执行器,调用select方法时,底层该方法会从configuration对象中去找sql语句(mappedstatement),执行并返回结果集
SqlSessionFactory是MyBatis中的一个关键接口,用于创建SqlSession对象,是MyBatis的核心组件之一。
SqlSessionFactory是通过SqlSessionFactoryBuilder创建的,SqlSessionFactoryBuilder会读取MyBatis的配置文件(mybatis-config.xml),并根据配置文件中的信息构建SqlSessionFactory对象。
SqlSessionFactory的主要作用是提供了创建SqlSession对象的方法,SqlSession对象是MyBatis中执行数据库操作的主要接口。SqlSession可以通过SqlSessionFactory的openSession方法创建,并且可以设置是否自动提交事务。SqlSession的生命周期应该在一个较小的范围内控制,避免长时间持有,以免占用数据库连接资源。
SqlSessionFactory可以被多个线程共享,应该保证SqlSessionFactory的单例,避免资源浪费。
除此之外,SqlSessionFactory还可以配置MyBatis的一些全局属性,如数据库连接池、缓存等,这些全局属性可以在整个应用程序中共享,从而提高应用程序的性能和可维护性。
总之,SqlSessionFactory是MyBatis中非常重要的一个接口,负责创建SqlSession对象和管理MyBatis全局属性的配置,使用SqlSessionFactory可以简化数据库操作的编写和管理,提高应用程序的性能和可维护性。
SqlSession的理解
MyBatis是一个优秀的持久层框架,而SqlSession则是MyBatis框架中最为核心的组件之一。SqlSession可以看做是对数据库操作的一次会话,每个会话中可以执行多次数据库操作。下面是对SqlSession的一些理解:
MyBatis框架中的Executor是一个执行器,负责执行SQL语句,与数据库进行交互,并将执行结果返回给调用方。Executor是MyBatis中最为核心的组件之一,它的实现涉及到多种设计模式和技术,包括装饰器模式、代理模式、线程池等。
Executor的实现类:MyBatis中默认提供了三个Executor的实现类,分别是SimpleExecutor、ReuseExecutor和BatchExecutor。SimpleExecutor是最简单的Executor实现,每次执行SQL语句都会创建一个新的Statement对象;ReuseExecutor会尝试重用Statement对象,避免多次创建Statement对象,提高执行效率;BatchExecutor则是批量执行SQL语句的Executor实现。
Executor的作用:Executor的主要作用是执行SQL语句,并将执行结果返回给调用方。在执行SQL语句之前,Executor会首先创建Statement对象,然后通过JDBC与数据库进行交互,将执行结果返回给MyBatis框架。Executor还负责缓存Statement对象,避免多次创建Statement对象,提高执行效率。
Executor的执行流程:Executor的执行流程可以概括为以下几个步骤:
Spring提供了两种解决方案来解决SqlSession的线程安全问题:
1.使用SqlSessionTemplate
SqlSessionTemplate是Spring提供的一个线程安全的SqlSession实现。它封装了SqlSession的操作,并确保每个线程都有自己的SqlSession实例。因此,在多线程环境下,每个线程都可以独立地使用自己的SqlSession实例,而不会相互干扰。可以在配置文件中定义SqlSessionTemplate bean,然后在需要使用SqlSession时注入该bean。
2.使用@Scope注解
另一个解决方案是在配置文件中使用@Scope注解,将SqlSession的作用域设置为prototype。这将确保每次从容器中获取SqlSession时都会返回一个新的实例,因此每个线程都可以使用自己的SqlSession实例。可以在配置文件中声明SqlSession bean,并使用@Scope注解将其作用域设置为prototype。在需要使用SqlSession时,可以注入该bean。
这两种解决方案都可以有效地解决SqlSession的线程安全问题。选择哪种方案取决于具体的需求和实现细节。
MyBatis中的Configuration的源码的理解
Configuration类的源码主要涉及以下几个方面:
1.加载配置文件
在MyBatis的配置文件中,可以配置数据源、映射文件、插件、类型别名等信息。Configuration通过XMLConfigBuilder类来加载配置文件,并将解析后的配置信息保存到Configuration对象中。
2.创建SqlSessionFactory
Configuration类也负责创建SqlSessionFactory。它会通过build方法创建SqlSessionFactory对象,并将该对象缓存起来,以便后续使用。在创建SqlSessionFactory对象时,会将Configuration对象作为参数传入,以便SqlSessionFactory可以获取MyBatis的配置信息和映射信息。
3.管理映射信息
MyBatis中的映射文件通常包含SQL语句和实体类之间的映射关系。Configuration会读取映射文件,将其中的SQL语句解析成MappedStatement对象,并将其保存到mappedStatements集合中。mappedStatements集合中保存了所有映射文件中定义的SQL语句,以及它们对应的MappedStatement对象。
4.管理缓存
Configuration还负责管理MyBatis的缓存。它会读取配置文件中的缓存配置信息,并创建对应的缓存对象,缓存对象被保存在caches集合中。在执行SQL语句时,如果该语句对应的MappedStatement对象中配置了缓存,则会从caches集合中获取缓存对象,并使用缓存对象来提高查询效率。
总的来说,Configuration类是MyBatis框架的核心组成部分之一,它负责加载配置文件、管理映射信息和缓存等功能,是整个框架的配置和管理中心。通过深入理解Configuration的源码,我们可以更好地理解MyBatis框架的
Mapper接口是没有实现类的,当调用接口方法时,采用了JDK的动态代理,先从Configuration配置类MapperRegistry对象中获取mapper接口和对应的代理对象工厂信息(MapperProxyFactory),然后利用代理对象工厂MapperProxyFactory创建实际代理类(MapperProxy),最后在MapperProxy类中通过MapperMethod类对象内保存的中对应方法的信息,以及对应的sql语句的信息进行分析,最终确定对应的增强方法进行调用。
为什么MyBatis Mapper接口中的方法不支持重载
在MyBatis源码中有这么几行代码,我们可以看到在解析XML文件创建mapper接口对应方法的时候,采用了接口全限名+方法名的方式作为StrictMap(MappedStatement数据存放的Map集合)的key值,而源码对于StrictMap的put方法进行了判断,如果存入的数据key已重复则抛出异常,所以Mapper接口中的方法不支持重载
id = applyCurrentNamespace(id, false);
public String applyCurrentNamespace(String base, boolean isReference) {
...
//返回值为mapper的全限名(xml中namespace的值)+方法名(xml中Statement id的值)
return currentNamespace + "." + base;
}
(1)初始化阶段:通过XMLConfigBuilder、XMLMapperBuilder、XMLStatementBuilder解析XML文件中的信息存储到Configuration类中;
(2)代理阶段:先从Configuration配置类MapperRegistry对象中获取mapper接口和对应的代理对象工厂信息,再利用代理对象工厂MapperProxyFactory创建实际代理类,最后在MapperProxy类中通过MapperMethod类对象内保存的中对应方法的信息,以及对应的sql语句的信息进行分析,最终确定对应的增强方法进行调用。
(3)数据读写阶段:通过四种Executor调用四种Handler进行查询和封装数据;
Mybatis都有哪些Executor执行器?它们之间的区别是什么
BaseExecutor:基础抽象类,实现了executor接口的大部分方法,主要提供了缓存管理和事务管理的能力,使用了模板模式,doUpdate,doQuery,doQueryCursor 等方法的具体实现交给不同的子类进行实现
CachingExecutor:直接实现Executor接口,使用装饰器模式提供二级缓存能力。先从二级缓存查,缓存没有命中再从数据库查,最后将结果添加到缓存中。如果在xml文件中配置了cache节点,则会创建CachingExecutor。
BatchExecutor:BaseExecutor具体子类实现,在doUpdate方法中,提供批量执行多条SQL语句的能力;
SimpleExecutor:BaseExecutor具体子类实现且为默认配置,在doQuery方法中使用PrepareStatement对象访问数据库, 每次访问都要创建新的 PrepareStatement对象;
ReuseExecutor:BaseExecutor具体子类实现,与SimpleExecutor不同的是,在doQuery方法中,使用预编译PrepareStatement对象访问数据库,访问时,会重用缓存中的statement对象,而不是每次都创建新的PrepareStatement。
(1)一级缓存: 基于 PerpetualCache 的 HashMap 本地缓存,其存储作用域为 Session,当 Session flush 或 close 之后,该 Session 中的所有 Cache 就将清空,Mybatis默认打开一级缓存,一级缓存存放在BaseExecutor的localCache变量中:
(2)二级缓存与一级缓存其机制相同,默认也是采用 PerpetualCache,HashMap 存储,不同在于其存储作用域为 Mapper(Namespace)级别。Mybatis默认不打开二级缓存,可以在config文件中xml开启全局的二级缓存,但并不会为所有的Mapper设置二级缓存,每个mapper.xml文件中使用标签来开启当前mapper的二级缓存,二级缓存存放在MappedStatement类cache变量中:
(3)对于缓存数据更新机制,当某一个作用域(一级缓存 Session/二级缓存Namespaces)的进行了C/U/D 操作后,默认该作用域下所有 select 中的缓存将被清除并重新更新,如果开启了二级缓存,则只根据配置判断是否刷新。
Mybatis 仅可以编写针对 ParameterHandler、ResultSetHandler、
StatementHandler、Executor 这 4 种接口的插件,Mybatis 使用 JDK 的动态代理,为需要拦截的接口生成代理对象以实现接口方法拦截功能,每当执行这 4 种接口对象的方法时,就会进入拦截方法,具体就是 InvocationHandler 的 invoke()方法,当然,只会拦截那些你指定需要拦截的方法。
编写插件:实现 Mybatis 的 Interceptor 接口并复写 intercept()方法,然 后在给插件编写注解,指定要拦截哪一个接口的哪些方法即可,记住,别忘了 在配置文件中配置你编写的插件
MyBatis 的插件(Interceptor)是一种可以拦截并修改 MyBatis 执行过程的机制,它可以在 SQL 语句执行的各个阶段进行干预和增强,比如在 SQL 语句执行前后添加日志、统计信息等功能。插件的运行原理主要涉及以下几个关键点:
应用场景
Mybatis 是一个流行的 Java ORM 框架,允许将 SQL 语句映射到 Java 对象。编写一个 Mybatis 插件可以扩展框架的功能,提供更好的灵活性和可维护性。下面是一个简单的 Mybatis 插件示例:
public Object intercept(Invocation invocation) throws Throwable;
public Object plugin(Object target);
public void setProperties(Properties properties);
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.session.Configuration;
import java.sql.Connection;
import java.util.Properties;
@Intercepts({
@Signature(type = StatementHandler.class, method = "prepare", args = {Connection.class, Integer.class})
})
public class MyPlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 在 StatementHandler 准备期间执行的操作
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
String originalSql = statementHandler.getBoundSql().getSql();
System.out.println("原始 SQL 语句: " + originalSql);
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 为目标对象创建代理
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 接收来自 Mybatis 配置文件的属性设置
String foo = properties.getProperty("foo");
System.out.println("foo 属性: " + foo);
}
}
编写插件的步骤:
(1)实现Interceptor接口方法
(2)确定拦截的签名
(3)在配置文件中配置插件
在创建三个重要的Handler(StatementHandler、ParameterHandler、ResultSetHandler)时通过插件数组包装了三大Handler:
resultSetHandler = (ResultSetHandler) interceptorChain.pluginAll(resultSetHandler);
获取到所有的Interceptor(拦截器)(插件需要实现的接口),调用:
interceptor.plugin(target);
返回target包装后的对象,最后回调回自定义插件的intercept方法执行插件内的代码逻辑。可拦截的接口和方法一览:
Executor(update、query 、 flushStatment 、 commit 、 rollback 、 getTransaction 、 close 、 isClose)
StatementHandler(prepare 、 paramterize 、 batch 、 update 、 query)
ParameterHandler( getParameterObject 、 setParameters )
ResultSetHandler( handleResultSets 、 handleCursorResultSets 、 handleOutputParameters )
MyBatis 是一个开源的持久层框架,它简化了数据库操作,并且提供了很多方便的功能。MyBatis 插件是一种扩展机制,允许开发人员在 MyBatis 的核心功能上添加自定义的功能或者行为。下面是一些常见的 MyBatis 插件的应用场景:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。