一:架构
1、架构理解:
mybatis架构主要分为三层:
1、接口层: 提供api接口,也就是mapper相关。
包含:sqlSession
2、数据处理层: 处理数据的。 将参数组装生成动态sql,执行后将结果封装返回。
包含:Executor,StatementHandler,ParameterHandler,ResultSetHandler,
TypeHandler,MappedStatement,BoundSql,SqlSource(负责根据⽤户传递的parameterObject,动态地⽣成SQL语句,将信息封装到BoundSql)
3、支撑层:底层事务、链接、缓存等管理。 为处理层做支撑。
2、执行流程:
a、容器启动
加载并解析配置文件到Configuration(可以基于注解或xml文件)。
将sql配置信息加载到MappedStatement。
b、api调用
通过调用mapper接口,传入参数。
通过mapper接口的全路径,对应着mapper.xml中namespace + id,确定statementid, 找到sql。
解析生成动态的sql并执行。
将结果封装并返回。
二:mybatis源码解析
在之前已简单写过持久层框架,只是读取了个别标签配置。 在mybatis中有很多的标签,现在来看一下:
原生api调用流程
1、初始化流程:
首先我们会读取xml,创建SqlSessionFactory。
Inputstream inputstream = Resources.getResourceAsStream("mybatis-config.xml");
//这⼀⾏代码正是初始化⼯作的开始。
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSessionFactory就是mybatis提供的,这里开始进入源码。
build方法经过重载,最终到以下方法:
parser.parse()创建了Configuration,里面都包含了一些什么信息:
如上,解析了很多的标签,包括之前手写过的mappers标签。
对于mappers中的每一个mapper.xml,都会解析成一个个的MappedStatement,具体对应着一个个的select/update/insert/delete节点,最终存放在Configuration中
Map < String , MappedStatement > mappedStatements = new StrictMap < MappedStatement > ( "Mapped Statements collection" )
2、sql执行流程:
sql的执行是先通过获取SqlSession开始,然后调用它提供的api:
SqlSession sqlSession = factory.openSession();
List<User> list = sqlSession.selectList("com.mapper.UserMapper.getUserByName");
SqlSession通常与ThreadLocal绑定,⼀个会话使⽤⼀ 个 ,使用完后需要调用close()关闭。
openSession():
public SqlSession openSession() {
//getDefaultExecutorType传递的是SimpleExecutor
return this.openSessionFromDataSource(this.configuration.getDefaultExecutorType(), (TransactionIsolationLevel)null, false);
}
openSessionFromDataSource():
/**
*ExecutorType 为Executor的类型,TransactionIsolationLevel为事务隔离级别,
*autoCommit是否开启事务;
*openSession的多个重载⽅法可以指定获得的SeqSession的Executor类型和事务的处理
*/
private SqlSession openSessionFromDataSource(ExecutorType execType, TransactionIsolationLevel level, boolean autoCommit) {
Transaction tx = null;
DefaultSqlSession var8;
try {
Environment environment = this.configuration.getEnvironment();
TransactionFactory transactionFactory = this.getTransactionFactoryFromEnvironment(environment);
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
//根据参数创建指定类型的Executor
Executor executor = this.configuration.newExecutor(tx, execType);
//返回DefaultSqlSession
var8 = new DefaultSqlSession(this.configuration, executor, autoCommit);
} catch (Exception var12) {
this.closeTransaction(tx);
throw ExceptionFactory.wrapException("Error opening session. Cause: " + var12, var12);
} finally {
ErrorContext.instance().reset();
}
return var8;
}
获取sqlSession后,进入selectList方法,有多个重载方法:
public <E> List<E> selectList(String statement) {
return this.selectList(statement, (Object)null);
}
public <E> List<E> selectList(String statement, Object parameter) {
return this.selectList(statement, parameter, RowBounds.DEFAULT);
}
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
List var5;
try {
//根据传⼊的全限定名+⽅法名从映射的Map中取出MappedStatement对象
MappedStatement ms = this.configuration.getMappedStatement(statement);
//调⽤Executor中的⽅法处理
//RowBounds是⽤来逻辑分⻚
// wrapCollection(parameter)是⽤来装饰集合或者数组参数
var5 = this.executor.query(ms, this.wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception var9) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + var9, var9);
} finally {
ErrorContext.instance().reset();
}
return var5;
}
最终调用的是Executor的查询方法
进入Executor:
//此⽅法在SimpleExecutor的⽗类BaseExecutor中的实现
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//根据传⼊的参数动态获得SQL语句,最后返回⽤BoundSql对象表示
BoundSql boundSql = ms.getBoundSql(parameter);
//为本次查询创建缓存的Key
CacheKey key = this.createCacheKey(ms, parameter, rowBounds, boundSql);
return this.query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
//重载方法开始查询
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
ErrorContext.instance().resource(ms.getResource()).activity("executing a query").object(ms.getId());
if (this.closed) {
throw new ExecutorException("Executor was closed.");
} else {
if (this.queryStack == 0 && ms.isFlushCacheRequired()) {
this.clearLocalCache();
}
List list;
try {
++this.queryStack;
list = resultHandler == null ? (List)this.localCache.getObject(key) : null;
if (list != null) {
this.handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
//如果缓存中没有本次查找的值,那么从数据库中查询
list = this.queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
--this.queryStack;
}
if (this.queryStack == 0) {
Iterator var8 = this.deferredLoads.iterator();
while(var8.hasNext()) {
BaseExecutor.DeferredLoad deferredLoad = (BaseExecutor.DeferredLoad)var8.next();
deferredLoad.load();
}
this.deferredLoads.clear();
if (this.configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
this.clearLocalCache();
}
}
return list;
}
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
this.localCache.putObject(key, ExecutionPlaceholder.EXECUTION_PLACEHOLDER);
List list;
try {
//查询的⽅法
list = this.doQuery(ms, parameter, rowBounds, resultHandler, boundSql);
} finally {
this.localCache.removeObject(key);
}
//放入缓存
this.localCache.putObject(key, list);
if (ms.getStatementType() == StatementType.CALLABLE) {
this.localOutputParameterCache.putObject(key, parameter);
}
return list;
}
真正执行doQuery()是在实现类中
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();
//传⼊参数创建StatementHanlder对象来执⾏查询。 之前介绍过插件四大对象,都是生成的代理对象。
StatementHandler handler = configuration.newStatementHandler(this.wrapper, ms, parameter, rowBounds, resultHandler, boundSql);
//创建jdbc中的statement对象
stmt = this.prepareStatement(handler, ms.getStatementLog());
// StatementHandler 进⾏查询处理
var9 = handler.query(stmt, resultHandler);
} finally {
this.closeStatement(stmt);
}
return var9;
}
看看prepareStatement方法:
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
//获取连接。经过重重调⽤最后会调⽤openConnection⽅法,从连接池中获得连接
Connection connection = this.getConnection(statementLog);
//使用StatementHandler准备Statement(待会儿再来看)
Statement stmt = handler.prepare(connection, this.transaction.getTimeout());
handler.parameterize(stmt);
return stmt;
}
//从连接池datasource获取连接
protected void openConnection() throws SQLException {
if (log.isDebugEnabled()) {
log.debug("Opening JDBC Connection");
}
this.connection = this.dataSource.getConnection();
if (this.level != null) {
this.connection.setTransactionIsolation(this.level.getLevel());
}
this.setDesiredAutoCommit(this.autoCommmit);
}
Executor.query()⽅法⼏经转折,最后会创建⼀个StatementHandler对象,然后将必要的参数传 递给 StatementHandler来完成对数据库的查询,最终返回List结果集。
1 、根据传递的参数,完成 SQL 语句的动态解析,⽣成 BoundSql 对象,供 StatementHandler 使⽤;2 、为查询创建缓存,以提⾼性能3 、创建 JDBC 的 Statement 连接对象,执行查询 ,返回 List 查询结果。
在executor中真正的查询是给了StatementHandler,StatementHandler主要完成了两件事:
1、创建JDBC的PreparedStatement对象,并对sql中的问号占位符用参数替换,生成可执行sql。
2、通过List query方法完成执行Statement,将db返回结果封装成list返回。
进⼊到 StatementHandler 的 parameterize(statement):
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(this.mappedStatement.getParameterMap().getId());
//之前我们自己实现过boundSql,知道这里存放了解析后的sql和所有参数名的映射。
//sql中的每个?对应着一个ParameterMapping(ParameterMapping存放着当前的参数名是什么,类型等)
List<ParameterMapping> parameterMappings = this.boundSql.getParameterMappings();
if (parameterMappings != null) {
for(int i = 0; i < parameterMappings.size(); ++i) {
ParameterMapping parameterMapping = (ParameterMapping)parameterMappings.get(i);
if (parameterMapping.getMode() != ParameterMode.OUT) {
String propertyName = parameterMapping.getProperty();
Object value;
if (this.boundSql.hasAdditionalParameter(propertyName)) {
value = this.boundSql.getAdditionalParameter(propertyName);
} else if (this.parameterObject == null) {
value = null;
} else if (this.typeHandlerRegistry.hasTypeHandler(this.parameterObject.getClass())) {
value = this.parameterObject;
} else {
MetaObject metaObject = this.configuration.newMetaObject(this.parameterObject);
value = metaObject.getValue(propertyName);
}
// 每⼀个 Mapping都有⼀个 TypeHandler,根据 TypeHandler 来对 preparedStatement
进⾏设置参数
TypeHandler typeHandler = parameterMapping.getTypeHandler();
JdbcType jdbcType = parameterMapping.getJdbcType();
if (value == null && jdbcType == null) {
jdbcType = this.configuration.getJdbcTypeForNull();
}
try {
typeHandler.setParameter(ps, i + 1, value, jdbcType);
} catch (TypeException var10) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var10, var10);
} catch (SQLException var11) {
throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + var11, var11);
}
}
}
}
}
经过以上方法完成了参数设置,进入实现类PreparedStatementHandler的查询:
public <E> List<E> query(Statement statement, ResultHandler resultHandler) throws SQLException {
PreparedStatement ps = (PreparedStatement)statement;
ps.execute();
//.使⽤ ResultSetHandler 来处理 ResultSet
return this.resultSetHandler.handleResultSets(ps);
}
public List<Object> handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity("handling results").object(this.mappedStatement.getId());
//多ResultSet的结果集合,每个ResultSet对应⼀个Object对象。
//⽽实际上,每 个 Object 是List<Object> 对象。
//在不考虑存储过程的多ResultSet的情况,普通的查询,实际就⼀个ResultSet,
//也就是说,multipleResults最终最多就⼀个元素。
List<Object> multipleResults = new ArrayList();
int resultSetCount = 0;
//获得⾸个ResultSet对象,并封装成ResultSetWrapper对象
ResultSetWrapper rsw = this.getFirstResultSet(stmt);
//在不考虑存储过程的多ResultSet的情况,普通的查询,实际就⼀个ResultSet,也 就是说,
resultMaps就⼀个元素
List<ResultMap> resultMaps = this.mappedStatement.getResultMaps();
int resultMapCount = resultMaps.size();
this.validateResultMapsCount(rsw, resultMapCount);
while(rsw != null && resultMapCount > resultSetCount) {
ResultMap resultMap = (ResultMap)resultMaps.get(resultSetCount);
//处理ResultSet,将结果添加到multipleResults中
this.handleResultSet(rsw, resultMap, multipleResults, (ResultMapping)null);
//获取下一个(不考虑存储过程,普通查询就只有一个,这里为null,会跳出循环)
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
//因为'mappedStatement.resultSets'只在存储过程中使⽤,本系列暂时不考虑,忽略即可
String[] resultSets = this.mappedStatement.getResultSets();
if (resultSets != null) {
while(rsw != null && resultSetCount < resultSets.length) {
ResultMapping parentMapping = (ResultMapping)this.nextResultMaps.get(resultSets[resultSetCount]);
if (parentMapping != null) {
String nestedResultMapId = parentMapping.getNestedResultMapId();
ResultMap resultMap = this.configuration.getResultMap(nestedResultMapId);
this.handleResultSet(rsw, resultMap, (List)null, parentMapping);
}
rsw = this.getNextResultSet(stmt);
this.cleanUpAfterHandlingResultSet();
++resultSetCount;
}
}
//如果是multipleResults单元素,则取⾸元素返回
return this.collapseSingleResultList(multipleResults);
}
上面解析了sqlSession调用原生api的流程。 实际使用不会直接这样调用,而是通过动态代理获取Mapper。
mapper调用流程
mapper使用方法:
public static void main(String[] args) {
//前三步都相同
InputStream inputStream = Resources.getResourceAsStream("sqlMapConfig.xml");
SqlSessionFactory factory = new SqlSessionFactoryBuilder().build(inputStream);
SqlSession sqlSession = factory.openSession();
//这⾥不再调⽤SqlSession的api,⽽是获得了接⼝对象,调⽤接⼝中的⽅法。
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
List<User> list = mapper.getUserByName("tom");
}
MapperRegistry是Configuration中的⼀个属性,它内部维护了一个HashMap存放mapper接口和对应的工厂类,一个mapper对应一个工厂类。
mybatis 初始化除了把mapper.xml中解析成一个个的MappedStatement对象,还会根据配置的mapper接口扫描路径,对每一个mapper创建对应的MapperProxyFactory,作为map中的value,key是当前mapper的字节码对象
public class MapperRegistry {
private final Configuration config;
private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap();
//省略……
//添加接口
public <T> void addMapper(Class<T> type) {
if (type.isInterface()) {
if (this.hasMapper(type)) {
throw new BindingException("Type " + type + " is already known to the MapperRegistry.");
}
boolean loadCompleted = false;
try {
//为每一个mapper接口创建MapperProxyFactory
this.knownMappers.put(type, new MapperProxyFactory(type));
MapperAnnotationBuilder parser = new MapperAnnotationBuilder(this.config, type);
parser.parse();
loadCompleted = true;
} finally {
if (!loadCompleted) {
this.knownMappers.remove(type);
}
}
}
}
调用 sqlSession.getMapper(UserMapper.class)时,调用了Configuration中的getMapper
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return this.mapperRegistry.getMapper(type, sqlSession);
}
接着调用了MapperRegistry中的
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory)this.knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
} else {
try {
//通过动态代理生成
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception var5) {
throw new BindingException("Error getting mapper instance. Cause: " + var5, var5);
}
}
}
MapperProxyFactory中
//MapperProxy实现了InvocationHandler,使用jdk动态代理
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);
}
MapperProxy:
public class MapperProxy<T> implements InvocationHandler, Serializable {
private static final long serialVersionUID = -6424540398559729838L;
private final SqlSession sqlSession;
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache;
public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethod> methodCache) {
//传⼊了 SqlSession,说明每个session中的代理对象的不同的!
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//如果是Object定义的⽅法,直接调⽤
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
}
if (this.isDefaultMethod(method)) {
return this.invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable var5) {
throw ExceptionUtil.unwrapThrowable(var5);
}
//获得 MapperMethod 对象
MapperMethod mapperMethod = this.cachedMapperMethod(method);
//重点在这:MapperMethod最终调⽤了执⾏的⽅法
return mapperMethod.execute(this.sqlSession, args);
}
最终的execute方法:
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
Object param;
switch(this.command.getType()) {
//判断当前mapper执行的⽅法类型
case INSERT:
param = this.method.convertArgsToSqlCommandParam(args);
//command.getName()得到的就是当前方法的全路径,也就是statementid,底层调用executor执行。
result = this.rowCountResult(sqlSession.insert(this.command.getName(), param));
break;
case UPDATE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.update(this.command.getName(), param));
break;
case DELETE:
param = this.method.convertArgsToSqlCommandParam(args);
result = this.rowCountResult(sqlSession.delete(this.command.getName(), param));
break;
case SELECT:
if (this.method.returnsVoid() && this.method.hasResultHandler()) {
this.executeWithResultHandler(sqlSession, args);
result = null;
} else if (this.method.returnsMany()) {
result = this.executeForMany(sqlSession, args);
} else if (this.method.returnsMap()) {
result = this.executeForMap(sqlSession, args);
} else if (this.method.returnsCursor()) {
result = this.executeForCursor(sqlSession, args);
} else {
param = this.method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(this.command.getName(), param);
if (this.method.returnsOptional() && (result == null || !this.method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + this.command.getName());
}
if (result == null && this.method.getReturnType().isPrimitive() && !this.method.returnsVoid()) {
throw new BindingException("Mapper method '" + this.command.getName() + " attempted to return null from a method with a primitive return type (" + this.method.getReturnType() + ").");
} else {
return result;
}
}
spring整合后,创建的mapper和sqlSession有多少个?
从上面的源码我们知道mapper是创建的动态代理,mapper和sqlSession都是每次创建新的。
与spring整合后,通过注入的方式,不再是先获取sqlSession调用sqlSession.getMapper(UserMapper.class), 而是通过注入,那时候,mapper代理对象就是单例了。 而且创建mapper代理对象时,通过SqlSessionTemplate来创建的(也是实现了jdk动态代理InvocationHandler)。 在它的invoke方法中,每一次调用时才来创建新的sqlSession。 也就是mapper是唯一的一个,sqlSession每次请求时创建。
具体的spring中再说。