这篇文章主要介绍了mybatis查询语句之封装数据的示例分析,具有一定借鉴价值,感兴趣的朋友可以参考下,希望大家阅读完这篇文章之后大有收获,下面让小编带着大家一起了解一下。

创新互联专注于乌鲁木齐企业网站建设,响应式网站,电子商务商城网站建设。乌鲁木齐网站建设公司,为乌鲁木齐等地区提供建站服务。全流程按需网站开发,专业设计,全程项目跟踪,创新互联专业和态度为您提供的服务
分析
mybatis在最后的查询最终会走SimpleExecutor类的doQuery方法,
@Override publicList doQuery(MappedStatement ms, Object parameter, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) throws SQLException { Statement stmt = null; try { Configuration configuration = ms.getConfiguration(); // 这里也就是采用了策略模式(个人感觉有点像),实际的statementHandler为routingStatementHandler StatementHandler handler = configuration.newStatementHandler(wrapper, ms, parameter, rowBounds, resultHandler, boundSql); stmt = prepareStatement(handler, ms.getStatementLog()); // 虽然是执行的routingStatementHandler.query,但返回结果的还是PreparedStatementHandler处理 return handler.query(stmt, resultHandler); } finally { closeStatement(stmt); } } private Statement prepareStatement(StatementHandler handler, Log statementLog) throws SQLException { Statement stmt; // 使用了代理模式,也可以理解为对connection进行了一层包装,这里的作用就是加了log处理 Connection connection = getConnection(statementLog); //进行预编译,即类似jdbc的 sql,如 select * from user where id=? stmt = handler.prepare(connection, transaction.getTimeout()); // 对执行查询的sql进行参数设置 handler.parameterize(stmt); return stmt; } 
关于 handler.prepare的作用这里简单介绍下,不做代码分析。
会设置fetchSize,作用就是一次性从数据库抓取数据,好像默认值是10条,如果每次只抓取一条,则进行rs.next的时候,会再次查库。
如果是insert操作,并且数据库主键自增且还设置了可以返回主键,则会还做获取主键的操作。
先从设置参数说起,也就是handler.parameterize。先看下源码,具体位置在DefaultParameterHandler类里面
@Override
 public void setParameters(PreparedStatement ps) {
 ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
 // 获取配置文件里面的sql参数信息,如sql为select * from user where id=#{userId,jdbcType=INTEGER}
 // ParameterMapping 记录了参数名也就是userId,还有记录了对应的jdbc类型,还有对应的javaType等等,具体可以debug看下
 List parameterMappings = boundSql.getParameterMappings();
 if (parameterMappings != null) {
 for (int i = 0; i < parameterMappings.size(); i++) {
 ParameterMapping parameterMapping = parameterMappings.get(i);
 if (parameterMapping.getMode() != ParameterMode.OUT) {
  Object value;
  String propertyName = parameterMapping.getProperty();
  // 如果为true,那么sql参数中有类似 user.name 格式
  if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
  value = boundSql.getAdditionalParameter(propertyName);
  } else if (parameterObject == null) {
  value = null;
  } else if (typeHandlerRegistry.hasTypeHandler(parameterObject.getClass())) {
  value = parameterObject;
  } else {
  // metaObject 类似一个工具类,它里面有一个反射工厂,可以专门解析一个类的信息,如字段的setter/getter/属性信息,这里不做多余介绍
  // 1、下面详细介绍 
  MetaObject metaObject = configuration.newMetaObject(parameterObject);
  value = metaObject.getValue(propertyName);// 取值
  }
  // 获取对应的typeHandler,一般情况不设置的话,基本都是ObjectTypeHandler
  TypeHandler typeHandler = parameterMapping.getTypeHandler();
  JdbcType jdbcType = parameterMapping.getJdbcType();
  if (value == null && jdbcType == null) {
  jdbcType = configuration.getJdbcTypeForNull();
  }
  try {
  // 进行设值
  typeHandler.setParameter(ps, i + 1, value, jdbcType);
  } catch (TypeException e) {
  throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  } catch (SQLException e) {
  throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
  }
 }
 }
 }
 } 对于上述代码中的一部分这里负责将parameterObject的里面的值整出来(也就是传入的参数),如果参数是map结构,就从map里面取值,如果不是,如单个非javabean参数,则直接取值,如果是单个javabean,则通过metaObject类转换成一个BeanWrapper,进行取值
这段代码也就负责对预编译后的sql设置参数,这里逻辑主要是围绕以下步骤进行得,
获取参数名,获取参数值,获取参数类型,然后做进行设值操作
/** * mybatis数据处理有单结果集和多结果集处理,一般多结果集出现存储过程中,如果存储过程中写了两条select语句,如 * select * from user , select * from classes 这种情况这里不做介绍,因为本人用的不多,理解的也不是很透彻。 * 这里不多做介绍,这里只针对简单映射做一个大概介绍 * */ public List
以上代码就是为结果映射做一个铺垫,重点是在hanleResultSet方法里,
private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, ListmultipleResults, ResultMapping parentMapping) throws SQLException { try {// 针对简单映射,parentMapping是为Null的 if (parentMapping != null) { handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping); } else { // 默认使用defaultResultHandler,如需使用自定义的,则可在传参加入resultHandler接口实现类 if (resultHandler == null) { DefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory); // 处理结果,结果存在resultHandler里 handleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null); multipleResults.add(defaultResultHandler.getResultList()); } else { handleRowValues(rsw, resultMap, resultHandler, rowBounds, null); } } } finally { // issue #228 (close resultsets) closeResultSet(rsw.getResultSet()); } } 
public void handleRowValues(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping) throws SQLException {
 // 处理有嵌套映射的情况
 if (resultMap.hasNestedResultMaps()) {
 ensureNoRowBounds();
 checkResultHandler();
 handleRowValuesForNestedResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
 } else {//没有嵌套映射
 handleRowValuesForSimpleResultMap(rsw, resultMap, resultHandler, rowBounds, parentMapping);
 }
 }private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)
 throws SQLException {
 DefaultResultContext resultContext = new DefaultResultContext<>();
 ResultSet resultSet = rsw.getResultSet();
 // 跳过多少行,到达指定记录位置,如在传参的时候传入了rowBounds,则会根据该类的offset值跳到指定记录位置
 skipRows(resultSet, rowBounds);
 // shouldProcessMoreRows 用来检测是否能继续对后续的结果进行映射
 while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {
 //用来处理resultMap节点中配置了discriminator节点,这里忽略掉
 ResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);
 // 得到的结果就是sql执行后的一行记录,如返回User对象信息,则rowValue就代表一个user实例,里面已经有值了
 Object rowValue = getRowValue(rsw, discriminatedResultMap, null);
 //保存数据
 storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);
 }
 } private Object getRowValue(ResultSetWrapper rsw, ResultMap resultMap, String columnPrefix) throws SQLException {
 final ResultLoaderMap lazyLoader = new ResultLoaderMap();
 // 创建对象,可以理解为对resultMap节点的type属性值,进行了反射处理,得到了一个对象,但属性值都是默认值。
 Object rowValue = createResultObject(rsw, resultMap, lazyLoader, columnPrefix);
 if (rowValue != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {
 final MetaObject metaObject = configuration.newMetaObject(rowValue);
 boolean foundValues = this.useConstructorMappings;
 //是否需要自动映射,有三种映射,分别为None,partial,full,默认第二种,处理非嵌套映射,可通过autoMappingBehavior 配置
 if (shouldApplyAutomaticMappings(resultMap, false)) {
 // 映射resultMap中未明确指定的列,如类中含有username属性,但是resultMap中没配置,则通过这个进行数据映射,还是可以查询到结果
 foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;
 }
 // 处理resultMap中指定的列
 foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;
 foundValues = lazyLoader.size() > 0 || foundValues;
 // 如果没查询到结果,但配置可返回空对象(指的是没有设置属性值得对象),则返回空对象,否则返回null
 rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;
 }
 return rowValue;
 }这里只介绍resultMap中有明确指定的列
private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)
 throws SQLException {
 // 获取数据字段名
 final List mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);
 boolean foundValues = false;
 // 获取的数据就是resultMap节点中配置的result节点,有多个result节点,这个集合大小就是多少
 // 里面存储的是属性名/字段名等信息
 final List propertyMappings = resultMap.getPropertyResultMappings();
 for (ResultMapping propertyMapping : propertyMappings) {
 String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);
 // 是否有嵌套映射
 if (propertyMapping.getNestedResultMapId() != null) {
 // the user added a column attribute to a nested result map, ignore it
 column = null;
 }
 // 针对1来说一般常与嵌套查询配合使用
 // 2 判断属性基本映射
 // 3 多结果集的一个处理
 if (propertyMapping.isCompositeResult()// 1
  || (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))// 2
  || propertyMapping.getResultSet() != null) {// 3
 // 获取当前column字段对于的值,有用到typeHandler来进行参数的一个转换
 Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);
 
 //获取类的属性字段名
 final String property = propertyMapping.getProperty();
 if (property == null) {
  continue;
 } else if (value == DEFERRED) {// 类似占位符。处理懒加载数据
  foundValues = true;
  continue;
 }
 if (value != null) {
  foundValues = true;
 }
 if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {
  // 进行设置属性值
  metaObject.setValue(property, value);
 }
 }
 }
 return foundValues;
 }  或许有人奇怪为啥没看到查询的对象有set操作,值就到了对象里面去了,这里全是metaObject给你操作了,具体的,大家可以自行了解这个类,只能说这个类的功能很强大。
感谢你能够认真阅读完这篇文章,希望小编分享的“mybatis查询语句之封装数据的示例分析”这篇文章对大家有帮助,同时也希望大家多多支持创新互联,关注创新互联行业资讯频道,更多相关知识等着你来学习!
网站题目:mybatis查询语句之封装数据的示例分析
当前链接:http://www.scyingshan.cn/article/iiieos.html

 建站
建站
 咨询
咨询 售后
售后
 建站咨询
建站咨询 
 