前言
MyBatis是一个开源的、轻量级的数据持久化框架,是JDBC和Hibernate的替代方案。它内部封装了JDBC,简化了加载驱动、创建连接、创建statement等繁杂的过程,开发者只需要关注SQL语句本身。MyBatis支持定制化SQL、存储过程以及高级映射,可以在实体类和SQL语句之间建立映射关系,是一种半自动化的ORM实现。其封装性低于Hibernate,但性能优秀、小巧、简单易学、应用广泛。MyBatis的主要思想是将程序中的大量SQL语句剥离出来,使用XML文件或注解的方式实现SQL的灵活配置,将SQL语句与程序代码分离,在不修改程序代码的情况下,直接在配置文件中修改SQL语句。与JDBC相比,减少了50%以上的代码量。MyBatis是最简单的持久化框架,小巧并且简单易学。支持存储过程。
说的通俗易懂一点
MyBatis是一个可以帮助开发者处理数据库操作的工具。它简化了使用JDBC进行数据库操作的过程,让开发者只需要关注SQL语句本身,而不需要花费精力去处理连接、语句创建等繁琐的过程。MyBatis可以将SQL语句与程序代码分离,通过XML文件或注解的方式配置SQL语句,使得SQL语句更加灵活和易于管理。与JDBC相比,MyBatis减少了代码量,并且更加简单易学。MyBatis适用于各种规模的项目,无论是小型项目还是大型项目,都可以通过MyBatis轻松地进行数据库操作。
Mybatis的入门案例
第一步:导入依赖
导入Mybatis的基础依赖
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.6</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
第二步:准备配置
准备 一个mybatis的Xml配置文件
<?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>
<properties resource="db.properties"></properties>
<!--导入参数来源-->
<settings>
<setting name="logImpl" value="STDOUT_LOGGING"/>
<!--用于生成可视的sql命令-->
<setting name="mapUnderscoreToCamelCase" value="true"/>
</settings>
<typeAliases>
<!--如果下面这种,则自动扫描包pojo下的注解类的别名-->
<package name="cn.whale.domian"></package>
</typeAliases>
<environments default="development">
<environment id="development"><!--环境-->
<transactionManager type="JDBC"/><!--事务管理器-->
<dataSource type="POOLED"><!--数据源-->
<property name="driver" value="${mysql.driver}"/>
<property name="url" value="${mysql.url}"/>
<property name="username" value="${mysql.username}"/>
<property name="password" value="${mysql.password}"/>
</dataSource>
</environment>
</environments>
<mappers>
<mapper resource="mapper/StudentMapper.xml"/>
</mappers>
</configuration>
数据库配置文件如下:
mysql.driver=com.mysql.jdbc.Driver
mysql.url=jdbc:mysql://localhost:3306/test?useSSL=false
mysql.username=root
mysql.password=admin
第三步:编写SQL映射文件
编写SQL映射文件StudnetMapper.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="cn.whale.mapper.StudentMapper">
<resultMap id="resultMap" type="cn.whale.domian.Student">
<id column="id" property="id"/>
<result column="username" property="username" />
</resultMap>
<select id="selectAll" resultType="cn.whale.domian.Student">
select * from student
</select>
<select id="selectById" resultMap="resultMap">
select id,username from student where id = #{id}
</select>
</mapper>
第四步:编写实体类和接口
编写实体类,和mapper映射器接口
public interface StudentMapper {
List<Student> selectAll();
Student selectById(Long id);
}
第五步:进行测试
public class StudentTest {
@Test
public void test() throws IOException {
//加载配置
InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml");
//创建一个sqlSessionFactory
SqlSessionFactory sqlSessionFactory = new SqlSessionFactoryBuilder().build(inputStream);
//创建SqlSession
SqlSession sqlSession = sqlSessionFactory.openSession();
Student student = sqlSession.selectOne("cn.whale.mapper.StudentMapper.selectById",1L);
System.out.println(student);
//使用最原始方式: namespace.statementid 执行
List<Student> objects = sqlSession.selectList("cn.whale.mapper.StudentMapper.selectAll");
objects.stream().forEach( System.out::println);
//使用mapper映射器接口方式执行
StudentMapper mapper = sqlSession.getMapper(StudentMapper.class);
List<Student> students = mapper.selectAll();
students.stream().forEach( System.out::println);
}
}
Mybatis执行流程
下面这个图是mybatis的组成结构图,后面我会详细介绍下面的组件,先混个眼熟
这里说几个比较重要的组件
- SqlSessionFactoryBuilder:这是一个创建者类,用于构建SqlSessionFactory,采用的是分步构建的Builder模式。
- SqlSessionFactory:这是MyBatis的核心,负责创建和管理SqlSession。
- SqlSession:这是执行数据库操作的主要接口,每个线程都应该有它自己的SqlSession实例。类似于JDBC中的Connection,可以用SqlSession实例来直接执行被映射的SQL语句。
- Executor:这是MyBatis中执行SQL语句的核心模块,它负责解析SQL语句,执行查询,处理结果等。MyBatis中所有的Mapper语句的执行都是通过Executor执行的。
- Mapper:Mapper是MyBatis的重要组件之一,它由一个Java接口和XML文件(或注解)构成,需要给出对应的SQL和映射规则,负责发送SQL去执行,并返回结果。在现有的技术中,一般会让其在业务逻辑代码中“消失”,而使用MyBatis提供的SQLMapper接口编程技术,它能提高代码的可读性和可维护性。
- Configuration :配置对象,主要包括mybatis-config.xml中的配置项目
然后我们先来分析一下Mybatis的执行流程,根据上面的测试案例我们可以分为两部分。创建SqlSession和执行SqlSession。首先第一行代码 :InputStream inputStream= Resources.getResourceAsStream("mybatis-config.xml")
的作用是加载Mybatis配置文件,然后通过SqlSessionFactoryBuilder().build解析配置文件,以及mapper.xml 映射文件,并创建一个 SqlSessionFactory
然后是通过 sqlSessionFactory.openSession() 创建SqlSession,SqlSession是和数据库的一次会话对象。然后是通过sqlSession.selectList来执行语句,可以通过“namespace”加上“statementid”来找到要执行的SQL,也可以通过获取Mapper映射器接口的方式来执行,第二种方式最终会采用第一种方式去执行SQL。
执行完SQL会有结果集,然后会调用结果映射器处理结果集并返回,下面这个图是宏观层面的,Mybatis执行流程
Mybatis执行流程如下:
第一种:
- 加载配置:MyBatis首先会从配置文件(mybatis-config.xml)和Java代码的注解中加载SQL的配置信息,这些信息包括传入参数映射配置、执行的SQL语句、结果映射配置等,形成一个或多个MappedStatement对象,并存储在内存中。
- SQL解析:当API接口层接收到调用请求时,会根据传入的SQL的ID找到对应的MappedStatement,然后根据传入参数对象对MappedStatement进行解析,解析后可以得到最终要执行的SQL语句和参数。
- SQL执行:将最终得到的SQL和参数拿到数据库进行执行,得到操作数据库的结果。
- 结果映射:将操作数据库的结果按照映射的配置进行转换,可以转换成HashMap、JavaBean或者基本数据类型,并将最终结果返回。
此外,MyBatis在执行过程中,还会使用SqlSessionFactory来创建SqlSession对象,每个线程都有自己的SqlSession实例,通过SqlSession来执行SQL语句。SqlSessionFactory是线程安全的,可以被多个线程共享。而SqlSession是非线程安全的,不能被共享,应该尽量避免在多线程环境中使用。
第二种:
- 初始化阶段,加载配置文件
- 根据配置文件,创建SqlSessionFactoryBuider,执行build方法来创建SqlSessionFactory,build方法会解析配置文件,然后封装到一个Configuration对象中。Configuration会保存在创建的SqlSessionFactory
- 通过SqlSessionFactory来创建SqlSesion,底层会创建一个Executor执行器保存在SqlSession中
- 然后就是SqlSesson的执行了,SqlSession会调用 executor 执行器去执行
- 执行器中会创建一个StatementHandler,调用StatementHandler去执行Statement语句,当然执行Statement语句前涉及到参数的处理
- 执行完成之后使用ResultSetHandler映射结果为实体对象并返回
源码解析
SqlSessionFactory的创建
代码入手肯定是new SqlSessionFactoryBuilder().build(inputStream),直接看源码见:org.apache.ibatis.session.SqlSessionFactoryBuilder#build(j…)
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
//1. 创建一个XML配置的Builder,inputStream是通过Resources.getResourceAsStream加载的xml配置
//environment 和 properties都是null
//这一步会创建一个 Configuration对象
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
//2. parser.parse()解析一个configuration对象,然后创建SqlSessionFactory
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.
}
}
}
Mybatis的首先是通过Resources.getResourceAsStream加载的xml配置(inputStream)交给 XMLConfigBuilder ,创建一个XML解析器在new XMLConfigBuilder(…)代码中会创建Configuration对象。然后调用parser.parse() 解析配置,解析之后得到一个 Configuration 对象,交给builder方法去创建一个默认的DefaultSqlSessionFactory,同时把Configuraton对象保存给SqlSessionFactory。
XMLConfigBuilder是BaseBuilder的实现类,用作配置文件解析,针对于不同的构建目标还有不同的子类
我们先来看parser.parse()方法的源码,然后再看build方法的源码,见org.apache.ibatis.builder.xml.XMLConfigBuilder#parse
public Configuration parse() {
//parsed是用来判断是否已经解析过了
if (parsed) {
throw new BuilderException("Each XMLConfigBuilder can only be used once.");
}
parsed = true;
//解析配置,使用的是XPathParser解析器来解析一个configuration根节点。
parseConfiguration(parser.evalNode("/configuration"));
return configuration;
}
使用xPathParser解析器来解析配置文件,/configuration 就是mybatis-config.xml配置中的根节点,
parseConfiguration方法的源码
//解析配置项目
private void parseConfiguration(XNode root) {
try {
//issue #117 read properties first
//1.拿到properties元素,也就是 <properties resource="db.properties"></properties>
propertiesElement(root.evalNode("properties"));
//2.处理 <settings> 元素,并设置到Properties 对象中
Properties settings = settingsAsProperties(root.evalNode("settings"));
loadCustomVfs(settings);
//3.处理 <typeAliases> 用户配置的别名
typeAliasesElement(root.evalNode("typeAliases"));
//4.处理 <plugins> 插件
pluginElement(root.evalNode("plugins"));
//5.处理 <objectFactory type=""></objectFactory> 对象工厂
objectFactoryElement(root.evalNode("objectFactory"));
//用来装饰object的工厂
objectWrapperFactoryElement(root.evalNode("objectWrapperFactory"));
//6.处理反射工厂<reflectorFactory type=""/>
reflectorFactoryElement(root.evalNode("reflectorFactory"));
//把 settings 设置到COnfiguration对象中
settingsElement(settings);
// read it after objectFactory and objectWrapperFactory issue #631
//7.处理 <environments default="development"> , 数据源就在这个元素里面
environmentsElement(root.evalNode("environments"));
databaseIdProviderElement(root.evalNode("databaseIdProvider"));
//8.处理 <typeHandlers></typeHandlers> 类型处理器
typeHandlerElement(root.evalNode("typeHandlers"));
//9 处理mappers 映射文件
mapperElement(root.evalNode("mappers"));
} catch (Exception e) {
throw new BuilderException("Error parsing SQL Mapper Configuration. Cause: " + e, e);
}
}
这里我们看到,parseConfiguration方法对于mybatis配置文件中的所有项目都做了解析。
propertiesElement(root.evalNode(“properties”)) : 解析 ,加载db.properties中的配置项目,然后会把properties设置到Configuration的variables存储起来
Properties settings = settingsAsProperties(root.evalNode(“settings”)); 处理 元素,转换为Properties ,然后通过 settingsElement(settings); 方法把settings中的配置保存到Configfiguration。见org.apache.ibatis.builder.xml.XMLConfigBuilder#settingsElement
typeAliasesElement(root.evalNode(“typeAliases”)); :处理别名配置,如果是通过<package>方式配置别名,会把配置的实体类的class添加到Configuration对象的TypeAliasRegistry别名注册器中,TypeAliasRegistry内部维护了一个new HashMap<String, Class<?>>() ,就是以类的简单名字小写为key,以实体类的class为值来映射别名到HashMap。见org.apache.ibatis.type.TypeAliasRegistry
如果是通过<typeAlias type="" 方式直接配置别名,那么就会注册到 BaseBuilder的TypeAliasRegistry中。
在Configuration对象的构造器中默认映射了很多的内置类型的别名。
pluginElement(root.evalNode(“plugins”)); 处理插件配置,该方法会解析拦截器配置比如<plugin interceptor="cn.whale.interceptor.MyInterceptor" ></plugin>,然后使用反射创建实例,保存到Configuration的InterceptorChain interceptorChain 拦截器执行链中,这里使用到了责任链模式。
objectFactoryElement(root.evalNode(“objectFactory”)); 对象工厂处理解析,默认情况Mybaits在映射结果的时候会使用 DefaultObjectFactory 工厂利用反射来实例化实体类,你可以通过 <objectFactory type=""></objectFactory> 配置来创建自定义的实例化工厂。指定自己的实例化方式。该工厂类也是保存到configuration对象的ObjectFactory objectFactory 字段上。
environmentsElement(root.evalNode(“environments”)); 环境处理,<environments default="development">中主要包括事务 <transactionManager type="JDBC"/> 和 <dataSource type="POOLED">数据源的配置。environmentsElement方法中会根据type=JDBC 从TypeAliasRegistry中找到一个JdbcTransactionFactory事务工厂,使用反射创建实例,根据type="POOLED"找到一个PooledDataSource,使用反射创建实例,最后创建一个 Environment 环境对象,把 JdbcTransactionFactory 事务工厂 和PooledDataSource连接池保存到Environment中
typeHandlerElement(root.evalNode(“typeHandlers”)); 处理类型处理器<typeHandlers></typeHandlers>,typeHandler是用来处理数据库的类型到Java的类型转换的,在 TypeHandlerRegistry的构造器中初始化了内置的很多的类型处理器,比如:VARCHAR类型转换为String就需要用到内置的 StringTypeHandler 处理器。当然我们也可以定义我们自己的类型处理器。
mapperElement(root.evalNode(“mappers”)); 处理mapper映射文件,比如:<mapper resource="mapper/StudentMapper.xml"/>,方法内部会构建 XMLMapperBuilder 去解析xml文件,见org.apache.ibatis.builder.xml.XMLMapperBuilder#parse
public void parse() {
//解析 cache , cache,parameterMap,resultMap,sql,select|insert|update|delete
//把SQL元素解析后封装成一个MappedStatement,存储到Configuration中的Map<String, MappedStatement>中
if (!configuration.isResourceLoaded(resource)) {
configurationElement(parser.evalNode("/mapper"));
configuration.addLoadedResource(resource);
//绑定Mapper接口
bindMapperForNamespace();
}
parsePendingResultMaps();
parsePendingCacheRefs();
parsePendingStatements();
}
configurationElement方法底层会解析到mapper.xml文件,包括: cache,parameterMap,resultMap,sql,select | insert | update | delete等元素的解析。然后把SQL语句封装成MappedStatement,以 namespace.id 为 key把MappedStatement映射到Configuration中的Map<String, MappedStatement>中。
bindMapperForNamespace();方法中,会根据namespace找到mapper映射器接口,然后添加到 MapperRegistry中。
private void bindMapperForNamespace() {
String namespace = builderAssistant.getCurrentNamespace();
if (namespace != null) {
Class<?> boundType = null;
try {
boundType = Resources.classForName(namespace);
} catch (ClassNotFoundException e) {
//ignore, bound type is not required
}
if (boundType != null) {
if (!configuration.hasMapper(boundType)) {
// Spring may not know the real resource name so we set a flag
// to prevent loading again this resource from the mapper interface
// look at MapperAnnotationBuilder#loadXmlResource
configuration.addLoadedResource("namespace:" + namespace);
configuration.addMapper(boundType);
}
}
}
}
MapperRegistry中维护了一个HashMap<Class<?>, MapperProxyFactory<?>>()
,key是mapper接口的class 类型,Value是一个MapperProxyFactory工厂,工厂中维护了mapper接口和接口中的方法如下
public class MapperProxyFactory<T> {
//mapper接口
private final Class<T> mapperInterface;
//接口中的方法
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
SqlSession的创建
接下来我们分析 sqlSessionFactory.openSession(); ,该方法是通过SqlSessionFactory创建SqlSession见:org.apache.ibatis.session.defaults.DefaultSqlSessionFactory#openSession()
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
这里从configuration中获取默认的executor类型默认是simple,事务的提交方式指定为手动提交,然后交给 openSessionFromDataSource 去处理
// execType :执行器的类型 ; autoCommit :事务提交方式为手动提交
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
//1.从Configuration拿到配置对象,配置对象中包括 JdbcTranscationFactory 和 PooledDataSource
final Environment environment = configuration.getEnvironment();
//从environment总获取事务工厂
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
//2.通过事务工厂transactionFactory创建Transaction事务对象,默认实现是JdbcTransaction
//JdbcTransaction中包括了Connection连接对象;DataSource 数据源;autoCommmit提交方式为false
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//3.根据execType创建执行器,默认是SimpleExecutor,
//SimpleExecutor继承了BaseExecutor,其中中维护了Transcation对象和PerpetualCache一级缓存一级configuration
//SimpleExecutor被包装到 CachingExecutor 总,这里使用了装饰者模式
//然后会把Executor添加到Configuration的interceptorChain拦截器链中
final Executor executor = configuration.newExecutor(tx, execType);
//4.创建SqlSession ,默认实现是DefaultSqlSession
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
//5.发生异常,关闭事务
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
总结一下上面的方法的核心业务
- 从Configuration拿到Environment对象,该对象中包括 JdbcTranscationFactory事务工厂 和 PooledDataSource 连接池
- 从Environment中获取事务工厂TransactionFactory ,通过事务工厂transactionFactory创建Transaction事务对象,默认实现是JdbcTransaction;JdbcTransaction中包括了Connection连接对象、DataSource 数据源、autoCommmit提交方式为false。JdbcTransaction中提供了事务的提交,回滚,关闭等方法。
- 然后根据execType创建执行器,默认是SimpleExecutor,SimpleExecutor继承了BaseExecutor,BaseExecutor维护了Transcation对象和PerpetualCache一级缓存、以及Configuration。
- 如果配置了 cacheEnabled=ture,会用装饰器模式对 executor 进行包装,SimpleExecutor被包装到 CachingExecutor 中,这里使用了装饰者模式然后会把Executor添加到Configuration的interceptorChain拦截器链中。
public Executor newExecutor(Transaction transaction, ExecutorType executorType) {
executorType = executorType == null ? defaultExecutorType : executorType;
executorType = executorType == null ? ExecutorType.SIMPLE : executorType;
Executor executor;
//1.根据类型创建Executor
if (ExecutorType.BATCH == executorType) {
executor = new BatchExecutor(this, transaction);
} else if (ExecutorType.REUSE == executorType) {
executor = new ReuseExecutor(this, transaction);
} else {
executor = new SimpleExecutor(this, transaction);
}
if (cacheEnabled) {
//2.如果开启了一级缓存,默认是true,把SimpleExecutor交给Cachin gExecutor ,装饰者模式
executor = new CachingExecutor(executor);
}
//3.把executor加入Configuration的interceptorChain拦截器链中
executor = (Executor) interceptorChain.pluginAll(executor);
return executor;
}
Executor的继承体系如下
- 创建SqlSession ,默认实现是DefaultSqlSession,其中维护了Configuration对象,Executor,autoCommit为false。
- 在catch中关闭事务closeTransaction , 底层会调用connection.close关闭事务。
这里要单独说一下三个Executor的区别
- SimpleExecutor:每执行一次 SQL就创建一个 Statement 对象,用 完立刻关闭 Statement 对象。
- ReuseExecutor:它能够实现Statement的复用,执行 SQL,会先把SQL 作为 key 查找 Statement 对象, 存在就使用,不存在就创建,用完后把Statement放置于 Map 内不关闭, 供下一次使用。
- BatchExecutor:执行 Update SQL(没有 select,不支持 select),将所 有 SQL都添加到批处理中(addBatch()),等待统一执行(executeBatch()),它缓存 了多个 Statement 对象,每个 Statement 对象都是 addBatch()完毕后,等待逐一执行 executeBatch()批处理。与 JDBC 批处理相同。
总结
MyBatis的初始化过程可以总结为以下几个主要步骤:
- 加载配置文件:MyBatis会首先加载配置文件,如mybatis-config.xml,该文件包含了数据库连接、属性、类型别名、类型处理器、插件、环境配置、映射器(mapper.xml)等信息。
- 创建SqlSessionFactory:根据配置文件中的信息,创建SqlSessionFactory对象。SqlSessionFactory是MyBatis的核心,用于创建和管理SqlSession。
- 加载映射文件:MyBatis会加载映射文件(mapper.xml),这些文件通常以XML格式存在,包含了SQL语句和映射规则的定义。映射文件可以是单个文件的映射,也可以是多个文件的映射。
- 创建SqlSession:通过SqlSessionFactory创建SqlSession对象,每个线程都有自己的SqlSession实例,用于执行SQL语句。
- 解析SQL语句:当需要执行SQL语句时,MyBatis会根据配置文件中的映射规则和参数对象,解析SQL语句并生成执行计划。
- 执行SQL语句:根据解析得到的执行计划,通过SqlSession执行SQL语句,并处理结果。
- 结果映射:将执行数据库的结果按照映射的配置进行转换,可以转换成Java对象或者基本数据类型,并将最终结果返回。
在初始化过程中,MyBatis会根据配置文件的设置进行相应的解析和配置。例如,对于<properties>元素,MyBatis会将其解析为Properties对象并存储到Configuration的variables属性中;对于<settings>元素,MyBatis会将其解析为Properties并设置到Configuration中,如延迟加载配置、二级缓存配置等;对于<typeAliases>元素,MyBatis会解析类的class并注册到Configuration的TypeAliasRegistry中;对于<plugins>元素,插件会注册到Configuration中的InterceptorChain拦截器链中;对于<environments>元素,MyBatis会解析出transactionManager和dataSource,并设置给Environment对象;对于<typeHandlers>元素,MyBatis会解析配置的typeHandler的class并注册到TypeHandlerRegistry中;对于<mapper>元素,MyBatis会解析其中的cache、parameterMap、resultMap、sql、select | insert | update | delete等元素,并将SQL语句封装成MappedStatement,以namespace.id为key把MappedStatement映射到Configuration中的Map<String, MappedStatement>中;然后根据namespace找到mapper映射器接口,并添加到MapperRegistry中。
最后,通过SqlSessionFactory创建SqlSession实例,并为其配置Transaction(默认使用JdbcTransaction)和Executor(默认使用SimpleExecutor)。
联系方式
大家如果有疑问可以通过关注公众号《编程乐学》,进行留言,我会在第一时间进行解答,同时,公众号还有更多有趣的项目以及关于学习编程的笔记资料大家可以看看。