mybatis工作流程
基本使用方法
// 擷取mybatis配置檔案
InputStream is = Resources.getResourceAsStream("mybatis-config.xml");
// 建立SqlSessionFactory建立器
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
// 通過SqlSessionFactoryBuilder 建立SqlSessionFactory ,并傳入配置檔案流
SqlSessionFactory ssf= sfb.build(is);
// 通過工廠擷取sqlSession
SqlSession sqlSession = ssf.openSession();
// sqlSession擷取mapper
DatasourceMapper mapper = sqlSession.getMapper(xxxMapper.class);
// 在通過mapper調用相關方法
String s = mapper.getXxx();
System.out.println(s);
解析
SqlSessionFactoryBuilder sfb = new SqlSessionFactoryBuilder();
SqlSessionFactory ssf= sfb.build(is);
public SqlSessionFactory build(InputStream inputStream) {
return build(inputStream, null, null);
}
public SqlSessionFactory build(Reader reader, String environment, Properties properties) {
try {
// xml解析器
XMLConfigBuilder parser = new XMLConfigBuilder(reader, environment, properties);
// parser.parse() 擷取配置檔案資訊,并封裝成Configuration對象
return build(parser.parse());
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error building SqlSession.", e);
} finally {
ErrorContext.instance().reset();
try {
reader.close();
} catch (IOException e) {
// Intentionally ignore. Prefer previous error.
}
}
}
public SqlSessionFactory build(Configuration config) {
return new DefaultSqlSessionFactory(config);
}
// DefaultSqlSessionFactory 是 SqlSessionFactory的一個實作類
public DefaultSqlSessionFactory(Configuration configuration) {
this.configuration = configuration;
}
SqlSession sqlSession = ssf.openSession();
public SqlSession openSession() {
return openSessionFromDataSource(configuration.getDefaultExecutorType(), null, false);
}
/**
* @Param execType 執行器 預設SIMPLE (SIMPLE, REUSE, BATCH)
* @Param level 事務等級
* @Param autoCommit 自動送出事務 false
*/
private SqlSession openSessionFromDataSource(ExecutorType execType,
TransactionIsolationLevel level,
boolean autoCommit) {
Transaction tx = null;
try {
// 通過配置檔案中的<Encironment>标簽中的資料,擷取資料庫配置資訊。
final Environment environment = configuration.getEnvironment();
// 通過environment中建立事務工廠
final TransactionFactory transactionFactory = getTransactionFactoryFromEnvironment(environment);
// 通過事務工廠建立事務 【資料源,資料庫隔離等級,是否自動送出】
tx = transactionFactory.newTransaction(environment.getDataSource(), level, autoCommit);
// 建立執行器 相當于JDBC中的statement
final Executor executor = configuration.newExecutor(tx, execType);
// 傳回SqlSession
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();
}
}
DatasourceMapper mapper = sqlSession.getMapper(xxxMapper.class);
<T> T getMapper(Class<T> type);
@Override
public <T> T getMapper(Class<T> type) {
return getConfiguration().getMapper(type, this);
}
// 實際上就是通過 mapperRegistry 幫我們存儲了所有的mapper對象,mapperRegistry 底層封裝了HashMap。
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
return mapperRegistry.getMapper(type, sqlSession);
}
public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
// private final Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<>();
//
final MapperProxyFactory<T> mapperProxyFactory = (MapperProxyFactory<T>) knownMappers.get(type);
if (mapperProxyFactory == null) {
throw new BindingException("Type " + type + " is not known to the MapperRegistry.");
}
try {
return mapperProxyFactory.newInstance(sqlSession);
} catch (Exception e) {
throw new BindingException("Error getting mapper instance. Cause: " + e, e);
}
}
// class MapperProxyFactory<T>
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<>(sqlSession, mapperInterface, methodCache);
return newInstance(mapperProxy);
}
// 類下的成員變量
// private final Class<T> mapperInterface;
// private final Map<Method, MapperMethodInvoker> methodCache = new ConcurrentHashMap<>();
protected T newInstance(MapperProxy<T> mapperProxy) {
// JDK 動态代理
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
String s = mapper.getXxx();
其實是通過調用
MapperProxy
的invoke方法。
public Object invoke(Object proxy, Method method, Object[] args, SqlSession sqlSession) throws Throwable {
return mapperMethod.execute(sqlSession, args);
}
execute
方法
public Object execute(SqlSession sqlSession, Object[] args) {
Object result;
switch (command.getType()) {
case INSERT: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.insert(command.getName(), param));
break;
}
case UPDATE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.update(command.getName(), param));
break;
}
case DELETE: {
Object param = method.convertArgsToSqlCommandParam(args);
result = rowCountResult(sqlSession.delete(command.getName(), param));
break;
}
case SELECT:
if (method.returnsVoid() && method.hasResultHandler()) {
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
result = executeForCursor(sqlSession, args);
} else {
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
if (method.returnsOptional()
&& (result == null || !method.getReturnType().equals(result.getClass()))) {
result = Optional.ofNullable(result);
}
}
break;
case FLUSH:
result = sqlSession.flushStatements();
break;
default:
throw new BindingException("Unknown execution method for: " + command.getName());
}
if (result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) {
throw new BindingException("Mapper method '" + command.getName()
+ " attempted to return null from a method with a primitive return type (" + method.getReturnType() + ").");
}
return result;
}
查詢流程
public <E> List<E> query(MappedStatement ms, Object parameterObject,
RowBounds rowBounds, ResultHandler resultHandler,
CacheKey key, BoundSql boundSql)
throws SQLException {
// 從二級緩存中擷取
Cache cache = ms.getCache();
// 如果有 則從緩存中取
if (cache != null) {
flushCacheIfRequired(ms);
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
list = delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
// 查詢一級緩存
return delegate.query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
總結
- 擷取配置檔案,轉成流。(
)InputStream is = Resources.getResourceAsStream("mybatis-config.xml")
- 解析流得到 configuration
- 通過SqlSessionFactoryBuilder 建立 SqlSessionFactory
- 通過SqlSessionFactory 擷取 SqlSession
- 使用SqlSession 執行SQL (MapperProxy)
- CachingExecutor 判斷是否開啟二級緩存
- 如果沒有開啟二級緩存,則調用 BaseExecutor 調用一級緩存
- 如果一級緩存有,則傳回,否則,請往下
- RountingStatementHandle 選中sql執行方式
- 選則預編譯方式,PreparedStatementHandle
- 最後,通過DefaultResultSetHandle傳回結果。
參考:https://blog.csdn.net/qq_38270106/article/details/93398694