mapper sql的映射接口 mybatis的接口是如何与xml的sql关联的
sql映射现在有两种方式
- 注解方式
- xml配置方法
注册mapper接口
/*******解析mapper xml 详见XMLMapperBuilder.java*************/
private void configurationElement(XNode context) {
try {
String namespace = context.getStringAttribute("namespace");
if (namespace == null || namespace.equals("")) {
throw new BuilderException("Mapper's namespace cannot be empty");
}
//设定正在解析的mapper名称空间
builderAssistant.setCurrentNamespace(namespace);
/*解析引用的缓存*/
cacheRefElement(context.evalNode("cache-ref"));
/*解析自己名称空间的缓存*/
cacheElement(context.evalNode("cache"));
/*解析参数映射的map*/
parameterMapElement(context.evalNodes("/mapper/parameterMap"));
/*解析结果集映射*/
resultMapElements(context.evalNodes("/mapper/resultMap"));
/*解析sql模板*/
sqlElement(context.evalNodes("/mapper/sql"));
/*解析增删改查的sql*/
buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
} catch (Exception e) {
throw new BuilderException("Error parsing Mapper XML. The XML location is '" + resource + "'. Cause: " + e, e);
}
}
mapper接口执行逻辑分析
- mapper 接口MapperProxyFactory生成动态代理对象MapperProxy
- MapperProxy 执行接口方法Method 映射的MapperMethod方法获取方法执行结果
- MapperMethod对象调用sqlSession对象执行数据库 增删改查操作
- sqlSession将操作代理给Executor执行
- Executor根据接口映射的MappedStatement对象执行底层数据库操作
- MappedStatement 获取sqlSource,并根据参数生成最终的sql语句,GenericTokenParser【${} 直接替换成参数值,#{} 替换成 ?】 解析替换sql内的参数表达式
- MappedStatement 获取到Statement ,如果是PreparedStatement,则跟根据参数类型选择合适的typeHandler,为PreparedStatement设置查询的参数值,优先已参数上设置的typeHandler为准,不设置,则自动判断来获取
- Statement执行sql,结果集交给ResultSetHandler处理,自动转换成需要的Pojo对象
- 获取到结果,如果存在ResultHandler,则交给ResultHandler处理结果
- 处理事务,关闭资源
mapper生成代理对象
public class MapperProxyFactory<T> {
private final Class<T> mapperInterface;
private final Map<Method, MapperMethod> methodCache = new ConcurrentHashMap<Method, MapperMethod>();
public MapperProxyFactory(Class<T> mapperInterface) {
this.mapperInterface = mapperInterface;
}
public Class<T> getMapperInterface() {
return mapperInterface;
}
public Map<Method, MapperMethod> getMethodCache() {
return methodCache;
}
/*获取mapper接口的动态代理对象*/
@SuppressWarnings("unchecked")
protected T newInstance(MapperProxy<T> mapperProxy) {
return (T) Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy);
}
public T newInstance(SqlSession sqlSession) {
final MapperProxy<T> mapperProxy = new MapperProxy<T>(sqlSession, mapperInterface, methodCache);
return newInstance(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) {
this.sqlSession = sqlSession;
this.mapperInterface = mapperInterface;
this.methodCache = methodCache;
}
//mapper 接口的实际执行逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
try {
//如果是object对象方法则直接调用
if (Object.class.equals(method.getDeclaringClass())) {
return method.invoke(this, args);
} else if (isDefaultMethod(method)) {
//如果是接口默认方法则直接调用
return invokeDefaultMethod(proxy, method, args);
}
} catch (Throwable t) {
throw ExceptionUtil.unwrapThrowable(t);
}
//接口声明的sql映射类方法,执行对应的MapperMethod方法
final MapperMethod mapperMethod = cachedMapperMethod(method);
return mapperMethod.execute(sqlSession, args);
}
/*方法解析后缓存已解析好的MapperMethod*/
private MapperMethod cachedMapperMethod(Method method) {
MapperMethod mapperMethod = methodCache.get(method);
if (mapperMethod == null) {
mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration());
methodCache.put(method, mapperMethod);
}
return mapperMethod;
}
/*调用接口的默认实现*/
@UsesJava7
private Object invokeDefaultMethod(Object proxy, Method method, Object[] args)
throws Throwable {
final Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class
.getDeclaredConstructor(Class.class, int.class);
if (!constructor.isAccessible()) {
constructor.setAccessible(true);
}
final Class<?> declaringClass = method.getDeclaringClass();
return constructor
.newInstance(declaringClass,
MethodHandles.Lookup.PRIVATE | MethodHandles.Lookup.PROTECTED
| MethodHandles.Lookup.PACKAGE | MethodHandles.Lookup.PUBLIC)
.unreflectSpecial(method, declaringClass).bindTo(proxy).invokeWithArguments(args);
}
/**
* Backport of java.lang.reflect.Method#isDefault()
*/
/*是否默认方法*/
private boolean isDefaultMethod(Method method) {
return (method.getModifiers()
& (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) == Modifier.PUBLIC
&& method.getDeclaringClass().isInterface();
}
}
接口方法映射的MapperMethod,实际的sql执行的路由逻辑,根据SqlCommand方式路由到SqlSession中执行对应的方法
public class MapperMethod {
//sql的类型 update/delete/insert/select/flush
private final SqlCommand command;
//mapper方法的元信息
private final MethodSignature method;
public MapperMethod(Class<?> mapperInterface, Method method, Configuration config) {
this.command = new SqlCommand(config, mapperInterface, method);
this.method = new MethodSignature(config, mapperInterface, method);
}
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()) {
//处理带有ResultHandler参数方式的接口
executeWithResultHandler(sqlSession, args);
result = null;
} else if (method.returnsMany()) {
//处理返回列表类型的接口
result = executeForMany(sqlSession, args);
} else if (method.returnsMap()) {
//处理返回Map集合的接口
result = executeForMap(sqlSession, args);
} else if (method.returnsCursor()) {
//处理返回游标的接口
result = executeForCursor(sqlSession, args);
} else {
//处理只有一条记录返回的接口
Object param = method.convertArgsToSqlCommandParam(args);
result = sqlSession.selectOne(command.getName(), param);
}
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;
}
/*
* INSERT UPDATE DELETE 返回值只有四种 void,int,long,boolean
* */
private Object rowCountResult(int rowCount) {
final Object result;
if (method.returnsVoid()) {
result = null;
} else if (Integer.class.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) {
result = rowCount;
} else if (Long.class.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) {
result = (long)rowCount;
} else if (Boolean.class.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) {
result = rowCount > 0;
} else {
throw new BindingException("Mapper method '" + command.getName() + "' has an unsupported return type: " + method.getReturnType());
}
return result;
}
...
public static class MethodSignature {
//是否返回多条记录
private final boolean returnsMany;
//是否返回map
private final boolean returnsMap;
//是否没有返回值
private final boolean returnsVoid;
//是否返回游标
private final boolean returnsCursor;
//返回类型
private final Class<?> returnType;
//返回值为Map是作为key的属性
private final String mapKey;
//resultHandler参数的参数索引位置
private final Integer resultHandlerIndex;
//rowBounds参数的参数索引位置
private final Integer rowBoundsIndex;
//参数名称解析实现类
private final ParamNameResolver paramNameResolver;
public MethodSignature(Configuration configuration, Class<?> mapperInterface, Method method) {
Type resolvedReturnType = TypeParameterResolver.resolveReturnType(method, mapperInterface);
if (resolvedReturnType instanceof Class<?>) {
this.returnType = (Class<?>) resolvedReturnType;
} else if (resolvedReturnType instanceof ParameterizedType) {
this.returnType = (Class<?>) ((ParameterizedType) resolvedReturnType).getRawType();
} else {
this.returnType = method.getReturnType();
}
this.returnsVoid = void.class.equals(this.returnType);
this.returnsMany = configuration.getObjectFactory().isCollection(this.returnType) || this.returnType.isArray();
this.returnsCursor = Cursor.class.equals(this.returnType);
this.mapKey = getMapKey(method);
this.returnsMap = this.mapKey != null;
this.rowBoundsIndex = getUniqueParamIndex(method, RowBounds.class);
this.resultHandlerIndex = getUniqueParamIndex(method, ResultHandler.class);
this.paramNameResolver = new ParamNameResolver(configuration, method);
}
...
sqlSession 根据commandName获取到对应的MappedStatement,交给executor执行
public final class MappedStatement {
//资源文件
private String resource;
//核心配置类
private Configuration configuration;
//唯一标识
private String id;
//sql设置的fetchSize
private Integer fetchSize;
private Integer timeout;
//Statement 类型
private StatementType statementType;
private ResultSetType resultSetType;
//sql的信息
private SqlSource sqlSource;
//对应的缓存地址
private Cache cache;
//配置的参数映射集合
private ParameterMap parameterMap;
//结果集映射
private List<ResultMap> resultMaps;
//是否刷新缓存
private boolean flushCacheRequired;
//是否使用缓存
private boolean useCache;
private boolean resultOrdered;
//sql的类型
private SqlCommandType sqlCommandType;
//主键生成策略
private KeyGenerator keyGenerator;
private String[] keyProperties;
private String[] keyColumns;
private boolean hasNestedResultMaps;
private String databaseId;
private Log statementLog;
private LanguageDriver lang;
private String[] resultSets;
...
executor查询
/*详见BaseExecutor.java*/
@Override
public <E> List<E> query(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
//根据参数获取需要执行的sql
BoundSql boundSql = ms.getBoundSql(parameter);
CacheKey key = createCacheKey(ms, parameter, rowBounds, boundSql);
return query(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
/***详见MappedStatement.java***/
public BoundSql getBoundSql(Object parameterObject) {
//根据参数获取需要执行的sql,将${},#{}处理掉,处理掉条件语句,组装成最终的SQL
BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
if (parameterMappings == null || parameterMappings.isEmpty()) {
boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject);
}
// check for nested result maps in parameter mappings (issue #30)
for (ParameterMapping pm : boundSql.getParameterMappings()) {
String rmId = pm.getResultMapId();
if (rmId != null) {
ResultMap rm = configuration.getResultMap(rmId);
if (rm != null) {
hasNestedResultMaps |= rm.hasNestedResultMaps();
}
}
}
return boundSql;
}
/*详见CachingExecutor.java*/
@Override
public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, CacheKey key, BoundSql boundSql)
throws SQLException {
//获取mapper对应的缓存
Cache cache = ms.getCache();
if (cache != null) {
//如果需要刷新缓存就清掉二级缓存
flushCacheIfRequired(ms);
//如果使用缓存,且没有resultHandler则先试着从缓存读取结果
if (ms.isUseCache() && resultHandler == null) {
ensureNoOutParams(ms, boundSql);
@SuppressWarnings("unchecked")
List<E> list = (List<E>) tcm.getObject(cache, key);
if (list == null) {
//没有缓存,则执行后面的代理操作
list = delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
tcm.putObject(cache, key, list); // issue #578 and #116
}
return list;
}
}
return delegate.<E> query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
}
/*详见BaseExecutor.java*/
@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()) {
clearLocalCache();
}
List<E> list;
try {
queryStack++;
//从一级缓存读取查询结果
list = resultHandler == null ? (List<E>) localCache.getObject(key) : null;
if (list != null) {
handleLocallyCachedOutputParameters(ms, key, parameter, boundSql);
} else {
list = queryFromDatabase(ms, parameter, rowBounds, resultHandler, key, boundSql);
}
} finally {
queryStack--;
}
if (queryStack == 0) {
for (DeferredLoad deferredLoad : deferredLoads) {
deferredLoad.load();
}
// issue #601
deferredLoads.clear();
//如果LocalCacheScope为STATEMENT,则不缓存
if (configuration.getLocalCacheScope() == LocalCacheScope.STATEMENT) {
// issue #482
clearLocalCache();
}
}
return list;
}