简介
Mybatis是一款流行的持久层框架,基于ORM(Object-Relation Mapper)思想,对针对JDBC的封装,通过xml配置支持灵活复杂的SQL查询。
框架组件架构图
Mybatis核心成员数据流
核心成员说明
核心代码流程
1)Mybatis通过SqlSessionFactory获取sqlSession,然后有sqlSession完成数据库的交互。SqlSessionFactory默认接口实现是是DefaultSqlSessionFactory。
//默认new DefaultSqlSessionFactory()
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
2) SqlSessionFactory有多个openSession方法,以无参的方法为例。
public SqlSession openSession() {
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
//executor 默认有多个实现,根据ExecutorType可知有以下几种
public enum ExecutorType {
SIMPLE,
REUSE,
BATCH;
private ExecutorType() {
}
}
针对Dao层的定义的接口,MapperRegistry维护了Dao层接口的代理工厂,并由工厂生成具体的代理去处理sqlSession,并交底层Executor调度器去执行。
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
//MapperMethod对应Dao层接口的方法
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return this.mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return this.methodCache;
}
protected T newInstance(MapperProxy<T> mapperProxy) {
return Proxy.newProxyInstance(this.mapperInterface.getClassLoader(), new Class[]{this.mapperInterface}, mapperProxy);
}
//根据接口类型生成具体代理
public T newInstance(SqlSession sqlSession) {
MapperProxy<T> mapperProxy = new MapperProxy(sqlSession, this.mapperInterface, this.methodCache);
return this.newInstance(mapperProxy);
}
}
Executor调度器与StatementHandler等处理器交互,完成SQL操作
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException {
Statement stmt = null;
List var9;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
stmt = this.prepareStatement(handler, ms.getStatementLog());
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
并发场景的思考:DefaultSqlSessionFactory是线程安全的么?如何做到线程安全?
是不线程安全的,这个会在后面解释。
缓存机制
一级缓存核心类是PerpetualCache,本质是一个hashMap
二级缓存默认不开启。
Spring 与Mybatis的整合
Spring bean 生命周期
MapperScannerConfigurer
MapperScannerConfigurer的主要工作是扫描basePackage包下所有的mapper接口类,并将mapper接口类封装成为BeanDefinition对象,注册到spring的BeanFactory容器中核心类图如下:
以上知道了Spring的bean注册到容器的核心流程,通过理解Spring的核心流程,可以梳理出Dao层接口Mapper通过MapperScannerConfigurer整合到spring的流程:
SqlSessionFactoryBean
类定义如下:
public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory>, InitializingBean, ApplicationListener<ApplicationEvent> {
//省略一些详细代码
public void setDataSource(DataSource dataSource) {
if (dataSource instanceof TransactionAwareDataSourceProxy) {
this.dataSource = ((TransactionAwareDataSourceProxy)dataSource).getTargetDataSource();
} else {
this.dataSource = dataSource;
}
}
public void setMapperLocations(Resource[] mapperLocations) {
this.mapperLocations = mapperLocations;
}
}
从这个类的定义可以看出SqlSessionFactoryBean与DataSource和Mapper有关。
在bean被创建的中,通过接口InitializingBean中的afterPropertiesSet方法设置属性。
public void afterPropertiesSet() throws Exception {
Assert.notNull(this.dataSource, "Property 'dataSource' is required");
Assert.notNull(this.sqlSessionFactoryBuilder, "Property 'sqlSessionFactoryBuilder' is required");
Assert.state(this.configuration == null && this.configLocation == null || this.configuration == null || this.configLocation == null, "Property 'configuration' and 'configLocation' can not specified with together");
this.sqlSessionFactory = this.buildSqlSessionFactory();
}
buildSqlSessionFactory方法主要完成SqlSession的初始化操作,完成在上面讲的Mybatis核心代码流程。
SqlSessionFactoryBean整合进Spring的流程
Mybatis整合Spring的整体流程
以下面简单的代码做主要流程说明
@Service
class AService{
@Autowire
private BDao bDao;
}
Spring在初始化的过程中@Service注解的类,AService类初始化完成之后,会进行属性赋值,bDao接口就是AService的一个属性,
1)首先根据这个bDao的名字或者类型从spring的BeanFactory中获取它的BeanDefinition,再从BeanDefinition中获取BeanClass,bDao对应的BeanClass就是MapperFactoryBean,这在创建MapperScannerConfigurer对象的时候设置的。
2)创建MapperFactoryBean对象,创建完成后,对属性进行赋值,其中有一个属性就是SqlSessionFactoryBean
3)MapperFactoryBean对象的属性设置完成之后,就调用它的getObject()方法,来获取bDao对应的实现类,获取的是一个JDK的代理类
public class MapperProxy<T> implements InvocationHandler, Serializable {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else {
MapperMethod mapperMethod = this.cachedMapperMethod(method);
return mapperMethod.execute(this.sqlSession, args);
}
}
}
程序在调用AService对象的某个方法的时候,就会调用到MapperProxy对象的invoke()方法,去完成对数据库的操作。
如何解决SqlSession的线程安全问题
MapperFactoryBean.getObject()获取的实例,实际是通过一个SqlSessionTemplate对象创建的,注入的Mapper对象实际上最终都执行的是SqlSessionTemplate方法。
关键代码如下:
public SqlSessionTemplate(SqlSessionFactory sqlSessionFactory, ExecutorType executorType, PersistenceExceptionTranslator exceptionTranslator) {
Assert.notNull(sqlSessionFactory, "Property 'sqlSessionFactory' is required");
Assert.notNull(executorType, "Property 'executorType' is required");
this.sqlSessionFactory = sqlSessionFactory;
this.executorType = executorType;
this.exceptionTranslator = exceptionTranslator;
this.sqlSessionProxy = (SqlSession)Proxy.newProxyInstance(SqlSessionFactory.class.getClassLoader(), new Class[]{SqlSession.class}, new SqlSessionTemplate.SqlSessionInterceptor());
}
private class SqlSessionInterceptor implements InvocationHandler {
private SqlSessionInterceptor() {
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
SqlSession sqlSession = SqlSessionUtils.getSqlSession(SqlSessionTemplate.this.sqlSessionFactory, SqlSessionTemplate.this.executorType, SqlSessionTemplate.this.exceptionTranslator);
Object unwrapped;
try {
Object result = method.invoke(sqlSession, args);
if (!SqlSessionUtils.isSqlSessionTransactional(sqlSession, SqlSessionTemplate.this.sqlSessionFactory)) {
sqlSession.commit(true);
}
unwrapped = result;
} catch (Throwable var11) {
unwrapped = ExceptionUtil.unwrapThrowable(var11);
if (SqlSessionTemplate.this.exceptionTranslator != null && unwrapped instanceof PersistenceException) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
sqlSession = null;
Throwable translated = SqlSessionTemplate.this.exceptionTranslator.translateExceptionIfPossible((PersistenceException)unwrapped);
if (translated != null) {
unwrapped = translated;
}
}
throw (Throwable)unwrapped;
} finally {
if (sqlSession != null) {
SqlSessionUtils.closeSqlSession(sqlSession, SqlSessionTemplate.this.sqlSessionFactory);
}
}
return unwrapped;
}
}
————————————————
版权声明:本文为CSDN博主「slagsea」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_34147021/article/details/118885110
共同学习,写下你的评论
评论加载中...
作者其他优质文章