一丶工厂获取产品
源码部分:
DefaultSqlSession 类
@Override
public <T> T selectOne(String statement) {
return this.<T>selectOne(statement, null);
}
@Override
public <T> T selectOne(String statement, Object parameter) {
// Popular vote was to return null on 0 results and throw exception on too many.
List<T> list = this.<T>selectList(statement, parameter);
if (list.size() == 1) { //通过list.size()来进行判断,当=1的时候返回结果,大于1的时候抛出异常。
return list.get(0);
} else if (list.size() > 1) {
throw new TooManyResultsException("Expected one result (or null) to be returned by selectOne(), but found: " + list.size());
} else {
return null;
}
}
@Override
public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
try {
MappedStatement ms = configuration.getMappedStatement(statement);// 返回数据库执行语句
return executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
} catch (Exception e) {
throw ExceptionFactory.wrapException("Error querying database. Cause: " + e, e);
} finally {
ErrorContext.instance().reset();
}
}
//query 中的核心
@SuppressWarnings("unchecked")
@Override
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 (closed) {
throw new ExecutorException("Executor was closed.");
}
if (queryStack == 0 ms.isFlushCacheRequired()) { //当计数器为0 且为需要刷新缓存的时候
clearLocalCache();//清空本地缓存
}
List<E> list;
try {
queryStack++; //计数器+1
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;当为null时,先从本地的缓存中去取
if (list != null) { //取到了对象
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);//对相同的语句进行优化,之前有,而且没有需要刷新缓存还存在的数据
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);//实在没有那就在查一次
}
} finally {
queryStack--;
}
if (queryStack == 0) { //当计数器为0,循环从本地缓存中查找
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) { //作用于为sql的时候,清空本地缓存
// issue #482
clearLocalCache();
}
}
return list;
}
private <E> List<E> queryFromDatabase(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql) throws SQLException {
List<E> list;
localCache.putObject(key, EXECUTION_PLACEHOLDER); //做一个占位符,将本地缓存,用对应的key占位
try {
list = doQuery(ms, parameter, rowBounds, resultHandler, boundSql);//查询返回list
} finally {
localCache.removeObject(key); //将刚才占位的移除
}
localCache.putObject(key, list); //添加真正的本地缓存
if (ms.getStatementType() == StatementType.CALLABLE) { //如果配置文件开启了缓存,把这个结果放入一级缓存
localOutputParameterCache.putObject(key, parameter);
}
return list;
}
public MappedStatement getMappedStatement(String id, boolean validateIncompleteStatements) {
if (validateIncompleteStatements) {
buildAllStatements();
}
return mappedStatements.get(id);// 传入mapper类路径,在建立工厂的时候,已经将代理工厂作为value,类名作为key
//方法如下:
这边put方法的思路很清晰,第一步判断是否存在key,如果已经存在抛出异常,否则将传入的mapper路径通过getShortName截取到.后面的字符串
//Ambiguity这个类其实就是一个字符串。
//当Ambiguity抛异常就表面有两个id相同的sql语句,mybatis不知道要执行哪一个了,所以异常了。
//在这边放入value,在get方法取出时value instanceof Ambiguity 来校验
@SuppressWarnings("unchecked")
public V put(String key, V value) {
if (containsKey(key)) {
throw new IllegalArgumentException(name + " already contains value for " + key);
}
if (key.contains(".")) {
final String shortKey = getShortName(key);
if (super.get(shortKey) == null) {
super.put(shortKey, value);
} else {
super.put(shortKey, (V) new Ambiguity(shortKey));
}
}
return super.put(key, value);
}
}
//
public V get(Object key) {
V value = super.get(key);
if (value == null) {
throw new IllegalArgumentException(name + " does not contain value for " + key);
}
if (value instanceof Ambiguity) {
throw new IllegalArgumentException(((Ambiguity) value).getSubject() + " is ambiguous in " + name
+ " (try using the full name including the namespace, or rename one of the entries)");
}
return value;
}
// mappedStatements是被Configuration类中new StrictMap出来的
protected final Map<String, MappedStatement> mappedStatements = new StrictMap<MappedStatement>("Mapped Statements collection");
//与map不一样他多了 name
public StrictMap(String name, Map<String, ? extends V> m) {
super(m);
this.name = name;
}
总体思路:
1.工厂生成产品,返回默认的产品,这些产品也和工厂一样,不同的配置生成出不一样的产品。
2.默认产品实现SqlSession接口下的某得接口,例如selectOne接口,通过selectList,返回list,当个数为一返回结果。
3.selectList方法,通过getMappedStatement返回执行语句,调用核心的executor.query()方法,这个方法主要就是有缓存,从缓存去,没有缓存,再查询。