Mybatis中的resultMap和resultType和parameterMap与pa。。
说实话Mybatis的知识点不少,在之前讲过(作⽤于在Executor组件)。⽽今天的主题是parameterMap 、parameterType、resultType、parameterMap,它们作⽤于ParameterHandler组件与ResultSetHandler 组件层。如果有⼈问你这类问题,其实是在考你的基本功(是否知道mybatis的架构或源码),这样才能get到对⽅关注的点。
在XML 映射⽂件中随处可⽤:parameterMap 、parameterType、resultType、parameterMap
<select id="selectByPrimaryKey" resultMap="BaseResultMap" parameterType="java.lang.String" >
select
<include refid="Base_Column_List" />
from bas_branchroute
where branch_route_id = #{branchRouteId,jdbcType=VARCHAR}
</select>
<delete id="deleteByPrimaryKey" parameterType="java.lang.String" >
delete from bas_branchroute
where branch_route_id = #{branchRouteId,jdbcType=VARCHAR}
</delete>
<delete id="deleteByExample" parameterType="s.model.BasBranchrouteExample" >
delete from bas_branchroute
<if test="_parameter != null" >
<include refid="Example_Where_Clause" />
</if>
</delete>
基本⽤法
parameterMap
这是引⽤外部 parameterMap 的已经被废弃的⽅法。请使⽤内联参数映射和 parameterType 属性。
parameterType
将会传⼊这条语句的参数类的完全限定名或别名。这个属性是可选的,因为 MyBatis 可以通过类型处理器(TypeHandler) 推断出具体传⼊语句的参数,默认值为未设置(unset)。
resultType
从这条语句中返回的期望类型的类的完全限定名或别名。 注意如果返回的是集合,那应该设置为集合包含的类型,⽽不是集合本⾝。可以使⽤ resultType 或 resultMap,但不能同时使⽤。
resultMap
外部 resultMap 的命名引⽤。结果集的映射是 MyBatis 最强⼤的特性,如果你对其理解透彻,许多复杂映射的情形都能迎刃⽽解。可以使⽤ resultMap 或 resultType,但不能同时使⽤。
数据库不可能永远是你所想或所需的那个样⼦。 我们希望每个数据库都具备良好的第三范式或 BCNF 范式,⽽ ResultMap 就是 MyBatis 对这个问题的答案。它⽀持的元素有constructor(实例化类时注⼊)、association(关联⼀个对象)、collection(关联多个对象),可以表⽰对象间⼀对⼀、⼀对多等关系。更多介绍见
<!-- 构造⽅法 -->
<resultMap id="userMap" type="User">
<constructor>
<idArg column="id" javaType="int"/>
<arg column="username" javaType="String"/>
<arg column="age" javaType="_int"/>
</constructor>
</resultMap>
<!-- ⼀对⼀ -->
<resultMap id="userMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<result property="address" column="address"></result>
<result property="email" column="email"></result>
<association property="role" javaType="Role">
<id property="id" column="role_id"></id>
<result property="name" column="role_name"></result>
</association>
</resultMap>
<!-- ⼀对多 -->
<resultMap id="userMap" type="User">
<id property="id" column="id"></id>
<result property="username" column="username"></result>
<result property="password" column="password"></result>
<result property="address" column="address"></result>
<result property="email" column="email"></result>
<collection property="roles" ofType="Role">
<id property="id" column="role_id"></id>
<result property="name" column="role_name"></result>
</collection>
</resultMap>
<!-- ⼀对多:嵌套 Select 查询 -->
<resultMap id="menusMap" type="Menu">
<id property="id" column="id"></id>
<result property="name" column="name"></result>
<result property="url" column="url"></result>
<result property="m_desc" column="m_desc"></result>
<result property="parent_id" column="parent_id"></result>
<!-- ofType="Menu" 对应返回数据的类型-->
<!--select="getMenus" 指定了SELECT语句的id-->
<!--column="{parent_id=id}" 则是列的别名,参数的表达式-->
<collection property="childMenu" ofType="Menu" select="getMenus"  column="{parent_id=id}"></collection>
</resultMap>
系统架构
关键组件
SqlSession:selectOne、selectList、selectMap、select、insert、update、delete、commit、rollback、flushStatements、close、clearCache、getConfiguration、getMapper、getConnection
Executor:update, query, flushStatements, commit, rollback, getTransaction, close, isClosed
StatementHandler:prepare, parameterize, batch, update, query
ParameterHandler:getParameterObject, setParameters
ResultSetHandler:handleResultSets, handleOutputParameters
内部交互
StatementHandler是⾮常重要的⼀层,它主要是对Statement的各种特殊处理(不负责执⾏),它⽀持三种Statement、Prepared、Callable模式,默认值:Prepared。RoutingStatementHandler提供了⼀种适配模式化的统⼀⼊⼝。
源码解析
你理解了上⾯的内容,再回头看源码就不复杂了!源码分析基于版本展开。
ParameterHandler
public interface ParameterHandler {
//获取参数对象
Object getParameterObject();
//设置参数对象
void setParameters(PreparedStatement ps) throws SQLException;
}
public class DefaultParameterHandler implements ParameterHandler {
public void setParameters(PreparedStatement ps) {
ErrorContext.instance().activity("setting parameters").object(ParameterMap().getId());
List<ParameterMapping> parameterMappings = ParameterMappings();
if (parameterMappings != null) {
for(int i = 0; i < parameterMappings.size(); ++i) {//遍历参数
ParameterMapping parameterMapping = ((i);
if (Mode() != ParameterMode.OUT) {
String propertyName = Property();//参数名称
Object value;//参数值
if (this.boundSql.hasAdditionalParameter(propertyName)) {//是否有这个参数
value = AdditionalParameter(propertyName);//获取参数值
} else if (this.parameterObject == null) {
value = null;
} else if (peHandlerRegistry.hasTypeHandler(Class())) {
value = this.parameterObject;
} else {
MetaObject metaObject = wMetaObject(this.parameterObject);//这个是什么⿁,不急慢慢看
value = Value(propertyName);
}
TypeHandler typeHandler = TypeHandler();
JdbcType jdbcType = JdbcType();
if (value == null && jdbcType == null) {
jdbcType = JdbcTypeForNull();
}
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);
}
}
}
}
}
}
问题1:确实setParameters()是关键点,它是什么时候被触发的呢?
它分别为 PreparedStatementHandler 和 CallableStatementHandler (执⾏存储过程)的  parameterize()中被调⽤。它在构建Statement 时被触发。
public class SimpleExecutor extends BaseExecutor {
public <E> List<E> doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLE    Statement stmt = null;
try {
Configuration configuration = ms.getConfiguration();
StatementHandler handler = wStatementHandler(this, ms, parameter, rowBounds, resultHandler, boundSql);
//构建Statement对象
stmt = prepareStatement(handler, ms.getStatementLog());
return handler.<E>query(stmt, resultHandler);
} finally {
closeStatement(stmt);
}
}
private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException {
Statement stmt;
Connection connection = getConnection(statementLog);
//此时很关键,最终路径:RoutingStatementHandler.parameterize -> PreparedStatementHandler.parameterize
stmt = handler.prepare(connection);
handler.parameterize(stmt);
return stmt;
}
}
public class PreparedStatementHandler extends BaseStatementHandler {
public void parameterize(Statement statement) throws SQLException {
//最终执⾏这个
parameterHandler.setParameters((PreparedStatement) statement);
}
}
问题2:MetaObject是什么⿁?
MetaObject是将Properties映射为bean属性,实际上就是提供 类|集合|Map 的⼀种⾃动识别的访问形式。PropertyTokenizer是的属性分
词器,提供了对象和集合的⼀种概念形式,如: object.parent.name(只是记录了 object ⽽已,可以通过next⽅法创建⼀个对象,返回new PropertyTokenizer(“parent”) 再次调⽤next 返回new PropertyTokenizer(“name”))。resultset 遍历
//基本⽤法
@Test
public void testGetSet(){
Animal animal = new Animal();
//testBean
MetaObject metaObject = MetaObject.forObject(animal, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.setValue("name","bean");
System.out.Name());
//testMap
animal.setName("map");
Map<String,Animal> map = new HashMap<>();
metaObject = MetaObject.forObject(map, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.setValue("deer",animal);
System.out.("deer").getName());
//testCollection
animal.setName("collection");
List<Animal> list = new ArrayList<>();
metaObject = MetaObject.forObject(list, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.add(animal);
System.out.(0).getName());
//testTokenizer
animal.setParent(new Animal());
metaObject = MetaObject.forObject(animal, new DefaultObjectFactory(), new DefaultObjectWrapperFactory(), new DefaultReflectorFactory());
metaObject.setValue("parent.name","tokenizer");
System.out.Parent().getName());
}
//源码
public class MetaObject {

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。