Mapper 映射的内部组成
一般而言,一个映射器是由3部分组成的:
- MappedStatement
它保存映射器的一个节点(select | insert | delete | update)。包括许多我们配置的 SQL、SQL 的 id、缓存信息、resultMap、parameterType、resultType 和 languageDriver 等重要的内容。 - SqlSource
它是提供 BoundSql 对象的地方,是 MappedStatement 的一个属性。 - BoundSql
它是建立 SQL 和参数的地方。它有3个常用的属性:SQL、parameterObject 和 parameterMappings。
映射器的内部组成如图所示:
MappedStatement 对象涉及的东西较多,我们一般不去修改它,因为容易产生不必要的错误。
SqlSource 是一个接口,它的主要作用是根据参数和其他的规则组装SQL。
对于参数和 SQL 而言,主要的规则都反映在 BoundSql 类对象上,BoundSql 会提供3个主要的属性:parameterMappings、parameterObject 和 sql:
parameterObject
它为参数本身,它有如下的规则:- 传递简单对象时,如int类型,MyBatis会把参数变为其对应的包装类Integer对象传递。类似的long、float也是如此。
- 如果传递的是POJO或者Map,则类型不变。
- 可以传递多个参数。如果没有
@Param
注解,那么MyBatis会把parameterObject变成一个Map<String, Object>
对象,键值类似{“1”: p1, “2”: p2, “3”: p3…, “param1”: p1, “param2”: p2, “param3”: p3…},所以我们可以使用#{paramN}或者是#{N}去引用第N个参数;如果使用@param
注解,MyBatis也会把parameterObject变为一个Map<String, Object>
对象,只是把纯数字的键置换成@param
注解的键,如@param(“key1”) String p1, @param(“key2”) int p2, @param(“key3”) Role p3, 那么这个parameterObject对象就是一个Map<String, Object>
对象,键值包含{“key1”: p1, “key2”: p2, “key3”: p3, “param1”: p1, “param2”: p2, “param3”: p3}。
parameterMappings
它是一个List,每一个元素都是ParameterMapping的对象,这个对象会描述我们的参数。参数包括属性、名称、表达式、javaType、jdbcType、typeHandler等重要信息。通过它可以实现参数和SQL的结合,以便PreparedStatement能够通过它找到parameterObject对象的属性并设置参数,使得程序准确运行。sql
sql属性就是我们书写在映射器里面的一条SQL。
Mapper 映射的实现
Mapper映射是通过动态代理来实现的,下面是MapperProxyFactory的部分源码:
public class MapperProxyFactory<T> {
@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);
}
}
在这里可以看到动态代理对接口的绑定,它的作用就是生成动态代理对象(占位),而代理的方法则被放到了MapperProxy类中。