携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第3天,点击查看活动详情
在学习一个框架前,我们不能只看到他的表象,也得知道他的内在结构,今天介绍下他的核心组件
SqlSessionFactoryBuilder
SqlSessionFactory的构造器,根据配置信息或代码配置生成SqlSessionFactory。对于这个对象的使用,一般new SqlSessionFactoryBuilder(),就直接使用这个对象构造 SqlSessionFactory。
源码(篇幅有限,只列举主要代码)
public SqlSessionFactory build(InputStream inputStream, String environment, Properties properties) {
try {
// 解析mybatis配置文件
XMLConfigBuilder parser = new XMLConfigBuilder(inputStream, environment, properties);
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.
}
}
}
/**
* 真正创建SqlSessionFactory方法
*
* 调用来源
* 1.通过解析xml配置文件获取信息并填充Configuration配置类中
* 2.后面mybatis-spring框架通过解析配置注解并填充Configuration配置类中
*
* @param config
* @return
*/
public SqlSessionFactory build(Configuration config) {
// 传入配置类通过构造方法创建默认的SqlSessionFactory
return new DefaultSqlSessionFactory(config);
}
通过源码可以看出,这个类主要是通过获取一个全文的配置类,通过构造方法创建一个默认的SqlSessionFactory。使用的是建造者模式。
SqlSessionFactory
生成SqlSession的工厂接口
SqlSessionFactory接口有两个实现类
- DefaultSqlSessionFactory:默认的实现类
- SqlSessionManager:暂时没有进行使用
源码(篇幅有限,只列举主要代码)
代码比较简单,就不注释了
@Override
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
@Override
public SqlSession openSession(boolean autoCommit) {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, autoCommit);
}
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
try {
final Environment environment = configuration.getEnvironment();
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
final Executor executor = configuration.newExecutor(tx, execType);
return new DefaultSqlSession(configuration, executor, autoCommit);
} catch (Exception e) {
closeTransaction(tx); // may have fetched a connection so lets call close()
throw ExceptionFactory.wrapException("Error opening session. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
构建SqlSessionFactory的方式
使用XML
就是创建mybatis.xml进行一系列的配置,太古老,就不演示了
在程序中使用代码
// 不推荐使用代码方式,要设置很多配置属性,目前mybatis-spring已经实现注解加配置去实现了
@Bean
public SqlSessionFactory sqlSessionFactory2(){
// 构建数据库连接池
PooledDataSource pooledDataSource = new PooledDataSource();
pooledDataSource.setDriver("com.mysql.cj.jdbc.Driver");
pooledDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/mybatis_study?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai");
pooledDataSource.setUsername("root");
pooledDataSource.setPassword("root");
// 事务管理工厂
TransactionFactory transactionFactory = new JdbcTransactionFactory();
// 数据库运行环境
Environment environment = new Environment("dev", transactionFactory, pooledDataSource);
// 构建配置对象
Configuration configuration = new Configuration(environment);
// 设置数据库属性映射别名
configuration.getTypeAliasRegistry().registerAlias("userMapper",UserMapper.class);
// 添加mapper映射文件
configuration.addMapper(UserMapper.class);
return new SqlSessionFactoryBuilder().build(configuration);
}
mybatis-spring框架的实现
先留个截图,之后有机会在spring专栏再说
SqlSession
sql执行的会话接口
从上面的源码,我们能看到SqlSession使用的实现类是DefaultSqlSession
那么SqlSession怎么就说是一个sql会话接口呢,我们看看源码
源码(篇幅有限,只列举主要代码)
/**
* 通过接口的class文件名获取接口的代理对象
* @param type Mapper interface class
* @param <T>
* @return
*/
@Override
public <T> T getMapper(Class<T> type) {
return configuration.<T>getMapper(type, this);
}
截取一个查询为例
/**
*
* @param statement 执行sql的id,例:statement = com.wood.mybais.mapper.UserMapper.query
* @param parameter 参数对象
* @param handler 结果处理器
*/
@Override
public void select(String statement, Object parameter, ResultHandler handler) {
select(statement, parameter, RowBounds.DEFAULT, handler);
}
/**
*
* @param statement
* @param parameter
* @param rowBounds RowBound instance to limit the query results
* @param handler
*/
@Override
public void select(String statement, Object parameter, RowBounds rowBounds, ResultHandler handler) {
try {
// 通过sql的id获取映射的关系对象
MappedStatement ms = configuration.getMappedStatement(statement);
// executor通过构造方法注入
// 执行器去执行sql
executor.query(ms, wrapCollection(parameter), rowBounds, handler);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
注:Executor内部会获取数据库连接,然后执行真正的数据库交互工作
主要用途
由上面的源码不难看出,SqlSession有以下作用:
- 获取映射器。让映射器通过命名空间和接口名称找到对应的sql,然后发送到数据库并返回结果
- 直接通过命令信息去执行sql返回结果。SqlSession就有update,insert等方法,带上sql的id操作XML配置好的sql去执行;并且他还支持事务,通过commit和rollback提交或回滚事务。
SqlMapper
映射器,由Java接口和XML文件(或者注解)共同组成
作用
- 定义参数类型
- 描述缓存
- 描述SQL语句
- 定义查询结果和对象的映射关系
实现方式
- XML配置文件
Java接口+SQL配置文件
- 注解
Java接口+注解
生命周期
- SqlSessionFactoryBuilder
作用就是构建SqlSessionFactory,构建完就失去了存在的意义。所以他的生命周期存在于方法的局部
-
SqlSessionFactory
- 作用就是创建sqlsession,而每次程序访问数据库的时候都需要创建新的sqlsession,所以SqlSessionFactory应该存在于mybatis应用的整个生命周期中
- 如果同一个数据库多次创建SqlSessionFactory,而每次创建SqlSessionFactory都会打开更多的数据库连接资源,造成资源浪费
- 所以SqlSessionFactory应该存在于mybatis的整个生命周期中,并且采用单例模式
-
SqlSession
- 数据库连接的一个会话,相当于JDBC的Connection对象。生命周期存在于应用对数据库的请求和操作中,每次创建后的SqlSession都必须要关闭它
-
Mapper
- 就是一个接口,是个方法级别的东西。在被调用后他的生命周期就结束了,最大的声明周期和SqlSession一样,也就是SqlSession只执行了一条SQL语句。
总结
通过上面的介绍,是不是发现和JDBC的操作步骤有些类似。其实框架无非是对于JDBC的充分封装,屏蔽了很多的细节而已。
结语
觉得写的不错的xdm,可以点波小赞。
文章难免有疏漏,也欢迎xdm指正。
一起学习,一起成长!