日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Mybatis源码阅读(三):结果集映射3.1 —— ResultSetBuilder与简单映射

發布時間:2025/3/11 编程问答 46 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Mybatis源码阅读(三):结果集映射3.1 —— ResultSetBuilder与简单映射 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

*************************************優雅的分割線 **********************************

分享一波:程序員賺外快-必看的巔峰干貨

如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程

請關注微信公眾號:HB荷包

一個能讓你學習技術和賺錢方法的公眾號,持續更新
*************************************優雅的分割線 **********************************
前言

在前面的文章中,已經介紹了三種SqlSource的代碼,下面開始介紹執行select語句對查詢結果集封裝的過程。
ResultSetHandler

前面的文章中得知,mybatis會將結果集按照映射配置文件中定義的映射規則,如resultMap節點,映射成相應的結果對象。

在StatementHandler接口執行完指定的select語句后,會將查詢結果集交給ResultSetHandler完成映射處理。

ResultSetHandler接口代碼如下:

/**

  • 處理select查詢的結果集

  • @author Clinton Begin
    */
    public interface ResultSetHandler {

    /**

    • 處理結果集,生成結果集集合
    • @param stmt
    • @param
    • @return
    • @throws SQLException
      */
      List handleResultSets(Statement stmt) throws SQLException;

    /**

    • 處理結果集,返回相應的游標
    • @param stmt
    • @param
    • @return
    • @throws SQLException
      */
      Cursor handleCursorResultSets(Statement stmt) throws SQLException;

    /**

    • 處理存儲過程
    • @param cs
    • @throws SQLException
      */
      void handleOutputParameters(CallableStatement cs) throws SQLException;

}

ResultSetHandler只有DefaultResultSetHandler一個實現,該類是處理結果集映射的核心類。核心字段如下所示:

public class DefaultResultSetHandler implements ResultSetHandler {

private static final Object DEFERRED = new Object();/*** MyBatis執行器*/ private final Executor executor; private final Configuration configuration; /*** Sql節點*/ private final MappedStatement mappedStatement; /*** 游標*/ private final RowBounds rowBounds; /*** 參數處理器*/ private final ParameterHandler parameterHandler; /*** 結果集處理器*/ private final ResultHandler<?> resultHandler; /*** Sql對象*/ private final BoundSql boundSql; private final TypeHandlerRegistry typeHandlerRegistry; /*** 對象工廠和反射工廠*/ private final ObjectFactory objectFactory; private final ReflectorFactory reflectorFactory;/*** 映射緩存*/ private final Map<CacheKey, Object> nestedResultObjects = new HashMap<>(); private final Map<String, Object> ancestorObjects = new HashMap<>();/*** 自動映射列緩存*/ private final Map<String, List<UnMappedColumnAutoMapping>> autoMappingsCache = new HashMap<>();/*** 記錄是否使用構造器創建映射對象*/ private boolean useConstructorMappings;

}

handlerResultSets方法

通過select語句查詢司機卡得到的結果集由handlerResultSets方法進行處理。該方法可以處理由Statement、PreparedStatement、CallableStatement產生的結果集。其中,Statement用于處理靜態SQL,PrepareStatement用于處理預處理的SQL,CallableStatement用于處理存儲過程,存儲過程的結果集可能有多個,mybatis中對多結果集也進行了處理。由于java開發多數是mysql,而mysql中存儲過程使用頻率非常之少,因此這里不對多結果集進行講解。

handleResultSets方法的代碼如下。

/**
* ☆
* select查詢到的結果集會在這里被處理
*
* @param stmt
* @return
* @throws SQLException
*/
@Override
public List handleResultSets(Statement stmt) throws SQLException {
ErrorContext.instance().activity(“handling results”).object(mappedStatement.getId());

// 保存映射得到的結果集對象final List<Object> multipleResults = new ArrayList<>();// 結果集數量int resultSetCount = 0;// 獲取第一個結果集ResultSetWrapper rsw = getFirstResultSet(stmt);// 獲取到sql節點所有的resultMap(一般只有一個)List<ResultMap> resultMaps = mappedStatement.getResultMaps();// resultMap的數量int resultMapCount = resultMaps.size();validateResultMapsCount(rsw, resultMapCount);// 遍歷resultMapswhile (rsw != null && resultMapCount > resultSetCount) {// 獲取指定下標的resultMapResultMap resultMap = resultMaps.get(resultSetCount);// 處理resultSethandleResultSet(rsw, resultMap, multipleResults, null);// 獲取下一個結果集rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}// resultSets是多結果集時適用。實際開發中幾乎不用這個String[] resultSets = mappedStatement.getResultSets();if (resultSets != null) {while (rsw != null && resultSetCount < resultSets.length) {ResultMapping parentMapping = nextResultMaps.get(resultSets[resultSetCount]);if (parentMapping != null) {String nestedResultMapId = parentMapping.getNestedResultMapId();ResultMap resultMap = configuration.getResultMap(nestedResultMapId);handleResultSet(rsw, resultMap, null, parentMapping);}rsw = getNextResultSet(stmt);cleanUpAfterHandlingResultSet();resultSetCount++;}}return collapseSingleResultList(multipleResults); }

查詢到的結果集可能有多個,mybatis默認先處理單結果集,getFirstResultSet方法用于獲取第一個結果集對象。而getNextResultSet則是用于獲取下一個結果集

/*** 獲取第一個結果集對象。* 在操作存儲過程時,可能會得到多個結果集* 該方法只獲取第一個結果集** @param stmt* @return* @throws SQLException*/ private ResultSetWrapper getFirstResultSet(Statement stmt) throws SQLException {// 獲取結果集ResultSet rs = stmt.getResultSet();// 結果集如果為null就繼續向下獲取while (rs == null) {// move forward to get the first resultset in case the driver// doesn't return the resultset as the first result (HSQLDB 2.1)if (stmt.getMoreResults()) {rs = stmt.getResultSet();} else {if (stmt.getUpdateCount() == -1) {// no more results. Must be no resultsetbreak;}}}return rs != null ? new ResultSetWrapper(rs, configuration) : null; }/*** 獲取下一個resultSet結果集** @param stmt* @return*/ private ResultSetWrapper getNextResultSet(Statement stmt) {// Making this method tolerant of bad JDBC driverstry {// 檢測jdbc是否支持多結果集if (stmt.getConnection().getMetaData().supportsMultipleResultSets()) {// 檢測是否還存在需要處理的結果集if (!(!stmt.getMoreResults() && stmt.getUpdateCount() == -1)) {ResultSet rs = stmt.getResultSet();if (rs == null) {return getNextResultSet(stmt);} else {return new ResultSetWrapper(rs, configuration);}}}} catch (Exception e) {// Intentionally ignored.}return null; }

在上面的代碼中,DefaultResultHandler在獲取到結果集對象之后,會將其封裝成ResultSetWrapper對象再進行處理。ResultSetWrapper對象中記錄了結果集的一些元數據,并提供了一系列操作ResultSet的輔助方法,下面是ResultSetWrapper的核心字段。

/**

  • 對ResultSet進行封裝

  • 存放了ResultSet的元數據

  • @author Iwao AVE!
    */
    public class ResultSetWrapper {

    /**

    • 查詢得到的結果集
      /
      private final ResultSet resultSet;
      /*
    • 一堆類型處理器
      /
      private final TypeHandlerRegistry typeHandlerRegistry;
      /*
    • resultSet每列列名
      /
      private final List columnNames = new ArrayList<>();
      /*
    • 每列對應的java類型
      /
      private final List classNames = new ArrayList<>();
      /*
    • 每列對應的jdbc類型
      /
      private final List jdbcTypes = new ArrayList<>();
      /*
    • key是列名,value是TypeHandler
      /
      private final Map<String, Map<Class<?>, TypeHandler<?>>> typeHandlerMap = new HashMap<>();
      /*
    • 記錄被映射的列名
      /
      private final Map<String, List> mappedColumnNamesMap = new HashMap<>();
      /*
    • 記錄未映射的列名
      */
      private final Map<String, List> unMappedColumnNamesMap = new HashMap<>();
      }

在ResultSetWrapper的構造方法中,會初始化columnNames、jdbcTypes、classNames三個集合,代碼如下。

public ResultSetWrapper(ResultSet rs, Configuration configuration) throws SQLException {super();this.typeHandlerRegistry = configuration.getTypeHandlerRegistry();this.resultSet = rs;// 獲取resultSet的元信息final ResultSetMetaData metaData = rs.getMetaData();// 獲取resultSet列數final int columnCount = metaData.getColumnCount();// 遍歷每一列,封裝 列名、jdbc類型、java類型for (int i = 1; i <= columnCount; i++) {columnNames.add(configuration.isUseColumnLabel() ? metaData.getColumnLabel(i) : metaData.getColumnName(i));jdbcTypes.add(JdbcType.forCode(metaData.getColumnType(i)));classNames.add(metaData.getColumnClassName(i));} }

簡單映射

介紹完整體的流程,下面來看handleResultSet方法。該方法的核心功能是完成對單個結果集的映射(即單表查詢的映射)。代碼如下。

/*** 根據resultMap定義的映射規則去處理resultSet。并將映射的結果添加到multipleResults集合** @param rsw* @param resultMap* @param multipleResults* @param parentMapping* @throws SQLException*/ private void handleResultSet(ResultSetWrapper rsw, ResultMap resultMap, List<Object> multipleResults, ResultMapping parentMapping) throws SQLException {try {if (parentMapping != null) {// 處理結果集中的嵌套映射。(resultMap中套著resultMap)handleRowValues(rsw, resultMap, null, RowBounds.DEFAULT, parentMapping);} else {if (resultHandler == null) {// 用戶沒有指定resultHandler,就用DefaultResultHandlerDefaultResultHandler defaultResultHandler = new DefaultResultHandler(objectFactory);// 對resultSet進行映射,并將映射結果添加到defaultResultHandlerhandleRowValues(rsw, resultMap, defaultResultHandler, rowBounds, null);// 將defaultResultHandler中保存的集合添加到multipleResultsmultipleResults.add(defaultResultHandler.getResultList());} else {// 使用用戶指定的resultHandler處理結果集handleRowValues(rsw, resultMap, resultHandler, rowBounds, null);}}} finally {// issue #228 (close resultsets)closeResultSet(rsw.getResultSet());} }

該方法的核心代碼就是handleRowValues。方法中判斷是否包含嵌套映射去決定處理簡單映射還是嵌套映射,代碼如下。

/*** 結果集映射核心方法** @param rsw* @param resultMap* @param resultHandler* @param rowBounds* @param parentMapping* @throws SQLException*/ 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);} }

下面先看簡單映射。簡單映射的核心代碼在handleRowValuesForSimpleResultMap方法中,下面先分析該方法執行流程。

調用skipRows方法,根據RowBounds中的offset值定位到指定的記錄行。RowBounds叫做游標,后面的文章會對其進行介紹。 調用shouldProcessMoreRows方法檢測是否還有需要映射的記錄。 通過resolveDiscriminatedResultMap方法確定映射要使用的ResultMap對象 調用getRowValue方法對Result中的一行記錄進行映射。通過createResultObject方法創建映射后的結果對象。通過shouldApplyAutomaticMap平時方法檢測是否開啟了自動映射功能通過applyAutomaiticMappings方法自動映射ResultMap中為明確映射的列通過applyPropertyMap平時方法映射ResultMap中明確映射的列,到這里該行記錄的數據已經完全映射到了結果對象的相應屬性中。 調用storeObject方法保存映射得到的結果集對象

handleRowValuesForSimpleResultMap代碼如下。

/*** 簡單結果集映射處理** @param rsw* @param resultMap* @param resultHandler* @param rowBounds* @param parentMapping* @throws SQLException*/ private void handleRowValuesForSimpleResultMap(ResultSetWrapper rsw, ResultMap resultMap, ResultHandler<?> resultHandler, RowBounds rowBounds, ResultMapping parentMapping)throws SQLException {DefaultResultContext<Object> resultContext = new DefaultResultContext<>();ResultSet resultSet = rsw.getResultSet();// 通過游標的offset值定位到指定的記錄行skipRows(resultSet, rowBounds);// 檢測是否還有需要映射的記錄while (shouldProcessMoreRows(resultContext, rowBounds) && !resultSet.isClosed() && resultSet.next()) {// 確定使用的ResultMap對象。多數情況下,這里指的還是傳入的ResultMapResultMap discriminatedResultMap = resolveDiscriminatedResultMap(resultSet, resultMap, null);// 映射Object rowValue = getRowValue(rsw, discriminatedResultMap, null);// 保存映射結果storeObject(resultHandler, resultContext, rowValue, parentMapping, resultSet);} }

skipRows方法是根據RowBounds.offset字段的值定位到指定的記錄。

/*** 通過游標定位到指定行** @param rs* @param rowBounds* @throws SQLException*/ private void skipRows(ResultSet rs, RowBounds rowBounds) throws SQLException {if (rs.getType() != ResultSet.TYPE_FORWARD_ONLY) {if (rowBounds.getOffset() != RowBounds.NO_ROW_OFFSET) {// 直接定位到指定行rs.absolute(rowBounds.getOffset());}} else {for (int i = 0; i < rowBounds.getOffset(); i++) {if (!rs.next()) {break;}}} }

定位到指定的記錄行之后,再通過shouldProcessMoreRows方法檢測是否還有需要映射的行。

/*** 檢測是否還有需要映射的數據** @param context* @param rowBounds* @return*/ private boolean shouldProcessMoreRows(ResultContext<?> context, RowBounds rowBounds) {return !context.isStopped() && context.getResultCount() < rowBounds.getLimit(); }

resolveDiscriminatedResultMap方法會根據ResultMap對象中記錄的Discriminator以及參與映射的列值,選擇映射操作最終使用的ResultMap,具體實現如下,。

/*** 根據ResultMap中記錄的Discriminator對象以及參與映射的記錄行中的列值* 確定使用的ResultMap對象** @param rs* @param resultMap* @param columnPrefix* @return* @throws SQLException*/ public ResultMap resolveDiscriminatedResultMap(ResultSet rs, ResultMap resultMap, String columnPrefix) throws SQLException {Set<String> pastDiscriminators = new HashSet<>();// 通過discriminator標簽去確定使用哪個ResultMap。使用不多,不進行注釋Discriminator discriminator = resultMap.getDiscriminator();while (discriminator != null) {final Object value = getDiscriminatorValue(rs, discriminator, columnPrefix);final String discriminatedMapId = discriminator.getMapIdFor(String.valueOf(value));if (configuration.hasResultMap(discriminatedMapId)) {resultMap = configuration.getResultMap(discriminatedMapId);Discriminator lastDiscriminator = discriminator;discriminator = resultMap.getDiscriminator();if (discriminator == lastDiscriminator || !pastDiscriminators.add(discriminatedMapId)) {break;}} else {break;}}return resultMap; } private Object getDiscriminatorValue(ResultSet rs, Discriminator discriminator, String columnPrefix) throws SQLException {final ResultMapping resultMapping = discriminator.getResultMapping();final TypeHandler<?> typeHandler = resultMapping.getTypeHandler();return typeHandler.getResult(rs, prependPrefix(resultMapping.getColumn(), columnPrefix)); }

通過上面方法的處理確定了映射使用的ResultMap對象,之后會調用getRowValue完成對該記錄的映射。首先根據ResultMap指定的類型創建對應的結果對象和MetaObject,再根據配置信息決定是否自動映射ResultMap中未明確映射的列,映射完畢后返回結果對象。代碼如下。

/*** 映射** @param rsw* @param resultMap* @param columnPrefix* @return* @throws SQLException*/ 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())) {// 創建上面對象的metaObjectfinal MetaObject metaObject = configuration.newMetaObject(rowValue);// 成功映射任意屬性,則為true,否則為falseboolean foundValues = this.useConstructorMappings;// 檢測是否需要自動映射if (shouldApplyAutomaticMappings(resultMap, false)) {// 自動映射resultMap未指定的列foundValues = applyAutomaticMappings(rsw, resultMap, metaObject, columnPrefix) || foundValues;}// 映射resultMap指定的列foundValues = applyPropertyMappings(rsw, resultMap, metaObject, lazyLoader, columnPrefix) || foundValues;foundValues = lazyLoader.size() > 0 || foundValues;// 如果沒有映射任何屬性,就根據mybatis-config.xml配置的returnInstanceForEmptyRow配置決定如何返回rowValue = foundValues || configuration.isReturnInstanceForEmptyRow() ? rowValue : null;}return rowValue; }

該方法中,createResultObject方法負責創建數據庫記錄映射得到的結果對象,該方法會返回結果集的列數、constructorResultMappings集合等信息,選擇不同的方式創建結果對象。具體實現如下。

/*** 創建該行記錄映射之后的結果對象,就是resultMap的type屬性指定的類** @param rsw* @param resultMap* @param lazyLoader* @param columnPrefix* @return* @throws SQLException*/ private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, ResultLoaderMap lazyLoader, String columnPrefix) throws SQLException {this.useConstructorMappings = false; // reset previous mapping result// 構造的參數類型final List<Class<?>> constructorArgTypes = new ArrayList<>();// 構造參數final List<Object> constructorArgs = new ArrayList<>();// 創建該行記錄的結果對象。該方法是該步驟的核心Object resultObject = createResultObject(rsw, resultMap, constructorArgTypes, constructorArgs, columnPrefix);// TODO 如果包含嵌套查詢且配置了延遲加載,就創建代理對象if (resultObject != null && !hasTypeHandlerForResultObject(rsw, resultMap.getType())) {final List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {// issue gcode #109 && issue #149if (propertyMapping.getNestedQueryId() != null && propertyMapping.isLazy()) {resultObject = configuration.getProxyFactory().createProxy(resultObject, lazyLoader, configuration, objectFactory, constructorArgTypes, constructorArgs);break;}}}// 記錄是否使用構造器創建對象this.useConstructorMappings = resultObject != null && !constructorArgTypes.isEmpty(); // set current mapping resultreturn resultObject; }/*** 創建映射結果對象** @param rsw* @param resultMap* @param constructorArgTypes* @param constructorArgs* @param columnPrefix* @return* @throws SQLException*/ private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)throws SQLException {// 根據resultMap配置的type屬性去創建對應的MetaClassfinal Class<?> resultType = resultMap.getType();final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);// 獲取到constructor節點final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();if (hasTypeHandlerForResultObject(rsw, resultType)) {// 結果集只有一列,并且存在TypeHandler對象可以將該列轉換成resultType指定的值(Integer、String等)return createPrimitiveResultObject(rsw, resultMap, columnPrefix);} else if (!constructorMappings.isEmpty()) {// resultMap中指定了constructor標簽,通過反射方式調用構造方法創建對象return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);} else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {// 使用默認的無參構造創建return objectFactory.create(resultType);} else if (shouldApplyAutomaticMappings(resultMap, false)) {// 通過自動映射,查找合適的構造方法創建return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);}throw new ExecutorException("Do not know how to create an instance of " + resultType); }

完成了對映射結果對象的創建后,下面就會將一行記錄的各個列映射到該結果集對象的對應屬性中。在成功創建對象并且獲取到MetaObject之后,會調用shouldApplyAutomaticMappings方法檢測是否允許自動映射,如果允許則調用applyAutomaiticMappings方法對ResultMap未指定的列進行自動映射。

/*** 是否需要自動映射。** @param resultMap* @param isNested* @return*/ private boolean shouldApplyAutomaticMappings(ResultMap resultMap, boolean isNested) {if (resultMap.getAutoMapping() != null) {return resultMap.getAutoMapping();} else {if (isNested) {return AutoMappingBehavior.FULL == configuration.getAutoMappingBehavior();} else {return AutoMappingBehavior.NONE != configuration.getAutoMappingBehavior();}} }/*** 自動映射未指定的列* @param rsw* @param resultMap* @param metaObject* @param columnPrefix* @return* @throws SQLException*/ private boolean applyAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {// 查找需要自動映射的列List<UnMappedColumnAutoMapping> autoMapping = createAutomaticMappings(rsw, resultMap, metaObject, columnPrefix);boolean foundValues = false;if (!autoMapping.isEmpty()) {// 映射列不為空,一一映射for (UnMappedColumnAutoMapping mapping : autoMapping) {// 從resultSet獲取值final Object value = mapping.typeHandler.getResult(rsw.getResultSet(), mapping.column);if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !mapping.primitive)) {// gcode issue #377, call setter on nulls (value is not 'found')metaObject.setValue(mapping.property, value);}}}return foundValues; }

createAutomaticMappings方法負責為未映射的列查找對應的屬性,并將二者關聯起來封裝成UnMappedColumnAutoMapping對象。createAutomaticMappings方法的具體實現如下。

/*** 查找需要自動映射的列* @param rsw* @param resultMap* @param metaObject* @param columnPrefix* @return* @throws SQLException*/ private List<UnMappedColumnAutoMapping> createAutomaticMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, String columnPrefix) throws SQLException {final String mapKey = resultMap.getId() + ":" + columnPrefix;// 先從緩存中找List<UnMappedColumnAutoMapping> autoMapping = autoMappingsCache.get(mapKey);if (autoMapping == null) {autoMapping = new ArrayList<>();// 獲取未映射的列final List<String> unmappedColumnNames = rsw.getUnmappedColumnNames(resultMap, columnPrefix);for (String columnName : unmappedColumnNames) {// 默認列名就是屬性名String propertyName = columnName;// 列前綴不為空時處理。if (columnPrefix != null && !columnPrefix.isEmpty()) {// When columnPrefix is specified,// ignore columns without the prefix.if (columnName.toUpperCase(Locale.ENGLISH).startsWith(columnPrefix)) {propertyName = columnName.substring(columnPrefix.length());} else {continue;}}// 根據列名查找對應的屬性final String property = metaObject.findProperty(propertyName, configuration.isMapUnderscoreToCamelCase());// 屬性不為空并且有set方法if (property != null && metaObject.hasSetter(property)) {// 該列已經映射,不重復映射if (resultMap.getMappedProperties().contains(property)) {continue;}final Class<?> propertyType = metaObject.getSetterType(property);if (typeHandlerRegistry.hasTypeHandler(propertyType, rsw.getJdbcType(columnName))) {// 查找對應的TypeHandler對象final TypeHandler<?> typeHandler = rsw.getTypeHandler(propertyType, columnName);// 將該列添加到autoMapping集合中autoMapping.add(new UnMappedColumnAutoMapping(columnName, property, typeHandler, propertyType.isPrimitive()));} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, property, propertyType);}} else {configuration.getAutoMappingUnknownColumnBehavior().doAction(mappedStatement, columnName, (property != null) ? property : propertyName, null);}}// 存放到緩存autoMappingsCache.put(mapKey, autoMapping);}return autoMapping; }

通過applyAutomaiticMappings方法處理完自動映射之后,后續會通過applyPropertyMappings方法對ResultMap中指定的列進行映射,核心代碼如下。

/*** 根據配置去映射* @param rsw* @param resultMap* @param metaObject* @param lazyLoader* @param columnPrefix* @return* @throws SQLException*/ private boolean applyPropertyMappings(ResultSetWrapper rsw, ResultMap resultMap, MetaObject metaObject, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {// 獲取需要映射的列名final List<String> mappedColumnNames = rsw.getMappedColumnNames(resultMap, columnPrefix);boolean foundValues = false;// 獲取所有resultMappingfinal List<ResultMapping> propertyMappings = resultMap.getPropertyResultMappings();for (ResultMapping propertyMapping : propertyMappings) {// 獲取列名String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);if (propertyMapping.getNestedResultMapId() != null) {// 判斷該節點是否是對其他ResultMapping進行引用column = null;}// 場景1:column是{prop1=col1,prop2=col2}形式if (propertyMapping.isCompositeResult()// 場景2:基本類型的屬性映射|| (column != null && mappedColumnNames.contains(column.toUpperCase(Locale.ENGLISH)))// 場景3:多結果集處理|| propertyMapping.getResultSet() != null) {// 完成映射,得到屬性值Object value = getPropertyMappingValue(rsw.getResultSet(), metaObject, propertyMapping, lazyLoader, columnPrefix);// 獲取屬性名稱final String property = propertyMapping.getProperty();if (property == null) {continue;} else if (value == DEFERRED) {// DEFERRED指占位符對象foundValues = true;continue;}if (value != null) {foundValues = true;}if (value != null || (configuration.isCallSettersOnNulls() && !metaObject.getSetterType(property).isPrimitive())) {// gcode issue #377, call setter on nulls (value is not 'found')// 設置屬性值metaObject.setValue(property, value);}}}return foundValues; }

其中,映射操作是在getPropertyMappingValue方法中完成,具體代碼如下,

/*** 完成映射操作并獲取屬性值* @param rs* @param metaResultObject* @param propertyMapping* @param lazyLoader* @param columnPrefix* @return* @throws SQLException*/ private Object getPropertyMappingValue(ResultSet rs, MetaObject metaResultObject, ResultMapping propertyMapping, ResultLoaderMap lazyLoader, String columnPrefix)throws SQLException {if (propertyMapping.getNestedQueryId() != null) {// 存在嵌套查詢return getNestedQueryMappingValue(rs, metaResultObject, propertyMapping, lazyLoader, columnPrefix);} else if (propertyMapping.getResultSet() != null) {// 多結果集的處理addPendingChildRelation(rs, metaResultObject, propertyMapping);return DEFERRED;} else {final TypeHandler<?> typeHandler = propertyMapping.getTypeHandler();final String column = prependPrefix(propertyMapping.getColumn(), columnPrefix);// 使用typeHandler來獲取屬性值return typeHandler.getResult(rs, column);} }

到這里,已經得到了一個完整映射的結果對象,之后DefaultResultSetHandler會通過storeObject方法將該結果對象保存到合適的位置,這樣該行記錄就完成了。如果是嵌套映射或者嵌套查詢的結果對象則保存到父對象對應的屬性中,如果是簡單映射則保存到ResultHandler中。

/*** 保存映射結果* @param resultHandler* @param resultContext* @param rowValue* @param parentMapping* @param rs* @throws SQLException*/ private void storeObject(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue, ResultMapping parentMapping, ResultSet rs) throws SQLException {if (parentMapping != null) {// 嵌套映射,保存在父對象屬性中linkToParents(rs, parentMapping, rowValue);} else {// 普通映射,保存在ResultHandlercallResultHandler(resultHandler, resultContext, rowValue);} }private void callResultHandler(ResultHandler<?> resultHandler, DefaultResultContext<Object> resultContext, Object rowValue) {resultContext.nextResultObject(rowValue);((ResultHandler<Object>) resultHandler).handleResult(resultContext); }

至此,簡單映射的流程就介紹完了。
*************************************優雅的分割線 **********************************

分享一波:程序員賺外快-必看的巔峰干貨

如果以上內容對你覺得有用,并想獲取更多的賺錢方式和免費的技術教程

請關注微信公眾號:HB荷包

一個能讓你學習技術和賺錢方法的公眾號,持續更新
*************************************優雅的分割線 **********************************

總結

以上是生活随笔為你收集整理的Mybatis源码阅读(三):结果集映射3.1 —— ResultSetBuilder与简单映射的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

国产色婷婷精品综合在线手机播放 | 日韩三级中文字幕 | 久久久免费毛片 | 成人亚洲精品久久久久 | 国产精品一区二区三区视频免费 | 日韩伦理片hd | 久久人人97超碰精品888 | 99视频在线观看一区三区 | 黄a网 | 日韩高清无线码2023 | 免费观看久久 | 特及黄色片 | 国产精品久久久久久模特 | 一本一本久久a久久精品综合妖精 | 三级av免费 | 黄色在线免费观看网站 | av五月婷婷 | 国产精品免费在线观看视频 | 激情视频免费观看 | 西西www444 | 国产不卡免费av | 亚洲精品乱码久久久久久蜜桃91 | www.亚洲| 国产精品久久久久久五月尺 | 久久综合狠狠综合久久激情 | 久一久久 | 精品亚洲欧美一区 | 色片网站在线观看 | 日韩二区三区在线观看 | 欧美日韩3p| 黄色高清视频在线观看 | 91视频最新网址 | 91免费黄视频 | 91污在线观看 | 国产精品理论视频 | 成人性生交视频 | 91精品视频免费 | 9999在线 | 黄色av成人在线观看 | 国内一级片在线观看 | 国产视频一区在线 | 久久精品导航 | 国产亚洲精品久久久久久久久久久久 | 国产 日韩 欧美 自拍 | 国产精品久久久精品 | 中文字幕在线观看国产 | 精产嫩模国品一二三区 | 亚洲国产精品久久久久 | 日韩影视在线观看 | 国产成人黄色 | 99久久99久久精品免费 | 久久国产一二区 | 成人97视频一区二区 | 久99久在线视频 | 国产麻豆电影 | 日韩乱色精品一区二区 | 久精品在线观看 | 日韩精品一区二区免费 | 6080yy精品一区二区三区 | 视频直播国产精品 | 日韩视频中文 | 国产专区精品 | 日本婷婷色 | 国产精品国产三级国产专区53 | 天天做日日爱夜夜爽 | 91视频免费看网站 | 国产小视频你懂的在线 | 国产精品手机在线 | 中文字幕无吗 | 欧美日韩在线第一页 | 午夜av免费观看 | 91爱爱免费观看 | 国产一级电影在线 | 国产视频久久久久 | 免费视频资源 | 亚洲欧洲av| 美女视频一区 | 欧美日韩伦理一区 | 日韩,中文字幕 | 日日操天天操夜夜操 | 精品日韩视频 | 黄色大片免费播放 | 国产视频1区2区3区 久久夜视频 | 在线成人中文字幕 | 一级黄色在线视频 | 国产无套精品久久久久久 | www.天天草 | 亚洲精品网站 | 中文字幕av最新更新 | 黄色91免费观看 | 免费看黄色毛片 | 天天操夜夜操 | 亚洲天堂精品视频 | 久草在线视频新 | 国产成人a亚洲精品v | 国产第一二区 | 亚洲精品在线二区 | 在线观看免费视频你懂的 | 国产精品视频专区 | 99这里只有精品视频 | 日韩av一区二区在线 | 久精品在线 | 精品免费国产一区二区三区四区 | 国产精品乱码高清在线看 | 国产视频1 | 欧美日韩国产色综合一二三四 | 日批视频在线 | 亚洲成人网在线 | 免费av黄色 | 国产一级二级在线播放 | 91亚洲狠狠婷婷综合久久久 | 黄色一级大片在线免费看国产一 | 在线免费视频一区 | 蜜桃视频日韩 | 波多野结衣网址 | 国产黄a三级 | 国产香蕉视频在线播放 | 美女性爽视频国产免费app | 99超碰在线观看 | 免费在线看v | 国产成人免费观看 | 99精品在线视频播放 | 激情开心站 | 欧美极品少妇xbxb性爽爽视频 | 国产精品一区二区三区电影 | 亚洲在线网址 | 国产精品理论在线观看 | 免费高清无人区完整版 | 欧美作爱视频 | 中文字幕在线免费看线人 | 97超视频在线观看 | 亚洲精品视频在线播放 | 亚洲精品高清一区二区三区四区 | 日韩视频一 | 国产理伦在线 | 久草在线观看 | 手机看片久久 | 五月在线视频 | 亚洲一级在线观看 | 日韩特黄av | 欧美999| 久久激情综合网 | 一级片免费观看视频 | 亚洲免费成人av电影 | 日本中文字幕观看 | 婷婷伊人五月天 | 免费观看av| 开心色停停 | 国内精品久久久久久中文字幕 | 欧美一区在线看 | 国产高清免费在线观看 | 国产97在线观看 | 黄色国产精品 | 射久久 | 中文一二区| 人人澡人摸人人添学生av | 亚洲色图 校园春色 | 婷婷色九月 | 日韩一区二区三区不卡 | 亚洲国产理论片 | 奇米影视8888 | 亚洲国产精品va在线 | 欧美大片第1页 | 黄色毛片视频免费观看中文 | 久久久久久免费网 | 国产资源站| 麻豆免费在线视频 | 亚洲蜜桃av | 国产精品美女久久久久久2018 | 亚洲一区日韩在线 | 丁香六月在线观看 | 久久久免费观看完整版 | 最近最新mv字幕免费观看 | 伊人国产在线播放 | 国产成人av网站 | 99精品视频免费 | 欧美不卡视频在线 | 日韩av区| 天堂av高清| 91亚洲精品久久久蜜桃 | 国产精品免费久久久久影院仙踪林 | 国产很黄很色的视频 | 国产精品热视频 | 久久久91精品国产一区二区精品 | 欧美精品乱码99久久影院 | 色偷偷网站视频 | 亚州天堂| 免费黄色特级片 | 狠狠色狠狠色终合网 | 中文字幕欧美日韩va免费视频 | www.com.黄| 在线观看视频97 | 欧美国产日韩一区 | 久久久久久久精 | 亚洲最大激情中文字幕 | 人人澡人人澡人人 | 色婷婷综合成人av | 99色在线观看 | 人人草人人草 | 日韩电影精品 | 精品视频 | 欧美成人精品三级在线观看播放 | 久精品视频在线观看 | 亚洲 成人 一区 | 激情网五月婷婷 | 久久久久久久久久国产精品 | 久一久久 | 99热亚洲精品 | 在线三级播放 | 天天综合久久 | av 一区二区三区四区 | 国产精品专区一 | 97热视频 | 啪啪肉肉污av国网站 | 久久久久久高潮国产精品视 | 久久久99精品免费观看乱色 | 99精品网站 | 亚洲欧洲精品一区 | 日本不卡123区 | 久久伊人综合 | 国产黄色大片 | 久久爱综合 | 色中色亚洲 | 亚洲自拍偷拍色图 | 亚洲精品美女在线观看播放 | 成人在线视频网 | 欧美另类巨大 | 久久久久久美女 | 亚洲视频一 | 久久国产免费 | 在线观看黄av | 香蕉视频免费在线播放 | 在线观看日本高清mv视频 | 丁香在线视频 | 2000xxx影视 | 99热这里只有精品1 av中文字幕日韩 | 免费视频色 | 亚洲精品国产精品国自产观看 | 91欧美日韩国产 | 97精品超碰一区二区三区 | 日韩欧美大片免费观看 | 日韩免费中文字幕 | 人人揉人人揉人人揉人人揉97 | 久久精品视频国产 | 欧美一级电影 | 日韩精品久久久久久久电影竹菊 | 黄色精品一区二区 | 国产 亚洲 欧美 在线 | 深夜福利视频在线观看 | 国产色一区 | 狠狠色狠狠色综合系列 | 中文字幕 国产精品 | 日韩精品一区二区三区免费视频观看 | 日韩免费视频在线观看 | 天天射天天搞 | 亚洲精品在线免费 | 天天摸天天弄 | 久久精品一区二区 | 91福利国产在线观看 | 欧美另类高清 videos | 白丝av在线 | 亚洲精品女人久久久 | 丁香六月激情 | 91免费的视频在线播放 | 96av在线视频| 亚洲综合涩 | 欧美日韩高清不卡 | 婷婷五月在线视频 | 一级免费看视频 | 免费激情在线电影 | 色窝资源 | 成人黄色大片 | 视频 国产区| 精品久久免费看 | 成片人卡1卡2卡3手机免费看 | 久久久久久久久久久免费视频 | 特级西西444www高清大视频 | 国产伦理久久精品久久久久_ | 国产精品剧情 | 中文字幕第一页在线 | 国产精品原创在线 | 亚洲欧美视频一区二区三区 | 少妇bbb| 日韩手机在线 | 久草青青在线观看 | 成人资源站| 91传媒免费观看 | 久久av免费 | 欧美一级日韩三级 | 日日操网 | 国产精品日韩久久久久 | 国产片网站 | 免费看片成人 | 久久夜色电影 | 国产精品成人一区二区 | 国产成人久久精品亚洲 | 天天射天天搞 | 精品国产免费看 | 午夜 久久 tv | 成人免费观看完整版电影 | 美女黄视频免费 | 久久精品视频在线免费观看 | 免费久久99精品国产婷婷六月 | 91亚洲精品久久久蜜桃 | 成人免费在线观看电影 | 永久免费的av电影 | 日韩三级视频 | 中文字幕视频三区 | 中文字幕免费高清 | 国产精品99久久久久久小说 | 亚洲 中文 在线 精品 | 免费观看一级一片 | 亚洲精品在线视频网站 | 久久国产香蕉视频 | 日韩天天干 | 99爱精品视频 | 亚洲午夜精品久久久久久久久久久久 | 亚洲 欧美 国产 va在线影院 | 超碰在线观看97 | 免费观看视频的网站 | 色网免费观看 | 日韩区欠美精品av视频 | 亚洲精品日韩一区二区电影 | 午夜精品视频一区二区三区在线看 | 欧美日韩亚洲国产一区 | 亚洲国产av精品毛片鲁大师 | 激情五月六月婷婷 | 狠狠干中文字幕 | 激情综合啪啪 | 精品一区精品二区高清 | 综合五月婷婷 | 91av视频在线免费观看 | 国产亚洲视频系列 | 四虎成人精品 | 黄色app网站在线观看 | 97精品在线观看 | 西西人体4444www高清视频 | 激情久久伊人 | 国产一线二线三线性视频 | 国产精品久久久久久久久久久免费 | 国产精品久久久久久久久岛 | 日韩乱理 | 天天射天天干天天爽 | 中文字幕在线久一本久 | 精品色综合 | 国产精品成人av电影 | 国产亚洲欧美精品久久久久久 | 国产成人久久av | 亚洲日本三级 | 人人干干人人 | 免费国产亚洲视频 | 国产黄av | 久草在线资源观看 | 青春草免费在线视频 | 黄色小说18 | 在线免费黄色毛片 | 欧美一区二区视频97 | 欧美一级日韩免费不卡 | 日本黄色免费播放 | 色婷婷视频 | 久久久国产精品亚洲一区 | 日日夜夜干 | 国产中文字幕亚洲 | 日本韩国精品一区二区在线观看 | 亚洲国产av精品毛片鲁大师 | 久久激情影院 | 91九色蝌蚪视频网站 | 蜜臀久久99精品久久久酒店新书 | 成人免费观看网站 | 在线观看黄色免费视频 | 久久99久久99精品免费看小说 | 美女视频网站久久 | 亚洲日韩欧美一区二区在线 | 天天操天天添天天吹 | 欧美精品久久久久久久久久久 | 精品不卡视频 | a天堂最新版中文在线地址 久久99久久精品国产 | 亚洲精品视频一二三 | 国产高清绿奴videos | 中文字幕一区二区三区四区视频 | 国产成人精品综合久久久 | 91av在线免费视频 | 高清免费在线视频 | 久久成人国产精品 | 亚洲成人第一区 | 国产午夜一级毛片 | 狠狠的日 | 99在线视频网站 | 亚洲一区尤物 | 日韩在线观看视频一区二区三区 | 久久综合在线 | 狠狠色狠狠色合久久伊人 | japanesefreesex中国少妇 | 亚洲精品乱码久久 | 伊人亚洲综合网 | 91av影视| 久久综合免费视频 | 欧美色图亚洲图片 | 亚洲电影影音先锋 | 日日夜夜天天干 | 亚洲免费一级电影 | 亚洲欧美在线观看视频 | 国产精品99在线观看 | 一区二区三区高清在线 | 手机在线看a | 操老逼免费视频 | 亚洲热久久 | 日本久久精 | av一区二区三区在线 | 国产亚洲精品久久网站 | japanesexxx乱女另类 | 国产精品嫩草在线 | 亚洲 欧美 国产 va在线影院 | 中文字幕日韩国产 | 日本一区二区三区免费观看 | 精品久久久久久亚洲 | 激情电影影院 | 亚洲毛片一区二区三区 | 精品一区二区综合 | 天天天干天天天操 | 香蕉国产91 | 日韩免费观看一区二区 | 国产一级淫片免费看 | 欧美性视频网站 | 日本精品一 | 天天干天天干天天射 | 欧美日韩精品在线一区二区 | 欧美美女视频在线观看 | 男女视频国产 | 日本精品一区二区 | 日本午夜在线观看 | 久久久这里有精品 | 91九色视频在线 | 91麻豆精品久久久久久 | 免费看片在线观看 | 中文字幕在线观看视频免费 | 人人爽人人干 | 久久免费一级片 | 欧美十八| 亚洲欧洲美洲av | 亚洲在线视频观看 | 在线观看av中文字幕 | 久草在线 | 日韩电影中文,亚洲精品乱码 | 免费精品人在线二线三线 | 国产一级性生活 | 婷婷丁香狠狠爱 | 欧美激情综合五月色丁香 | 国产午夜精品一区二区三区 | 久久精品日本啪啪涩涩 | 国产成人精品亚洲精品 | 日韩va亚洲va欧美va久久 | 黄网站app在线观看免费视频 | 亚洲精品乱码久久久久久高潮 | 色福利网 | 91九色在线视频 | 日韩美在线观看 | 天堂va在线高清一区 | 97超级碰碰碰视频在线观看 | 97超碰.com| 999视频网 | 中文字幕在线字幕中文 | 欧美黑人性猛交 | 精品久久网站 | 国产精品免费大片视频 | 国产精品亚州 | 人人狠 | 黄色片网站免费 | 看国产黄色片 | 国产日产在线观看 | 中文字幕第一页在线视频 | 午夜精品久久久久久中宇69 | 麻豆高清免费国产一区 | 国产在线不卡 | 超级碰99| 国产 精品 资源 | 日韩免费观看高清 | 九九在线精品视频 | 亚洲精品女人 | 综合网天天射 | 视频一区二区三区视频 | 人人超在线公开视频 | 亚洲精品国偷拍自产在线观看蜜桃 | 久久精品系列 | 五月天综合激情网 | 精品久久久久久久久久久久久久久久久久 | 超碰公开在线 | 手机av电影在线 | 91 在线视频 | 99热9| 9在线观看免费 | 人人澡人人草 | 日批网站在线观看 | 免费观看国产视频 | 成人啪啪18免费游戏链接 | 国产在线色 | 视频精品一区二区三区 | av黄色免费在线观看 | 日韩av资源站 | 国产福利精品一区二区 | 国产精品99久久久久的智能播放 | 在线观看亚洲精品 | 成人av片免费观看app下载 | 国产亚洲精品久久久久久大师 | 欧美在线久久 | 日本韩国欧美在线观看 | 麻豆传媒视频在线 | 欧美色图亚洲图片 | 在线激情av电影 | 国产色婷婷精品综合在线手机播放 | 色播亚洲婷婷 | 久久av影院 | 亚洲精品免费观看 | 狠狠干五月天 | 成人国产精品久久久春色 | www.夜色321.com | 成人小视频在线 | 天天干夜夜擦 | 国产aa精品 | 久久精品视频免费播放 | 91日韩精品| 日韩特级毛片 | 精品国产免费人成在线观看 | 四虎最新入口 | 在线观看一区二区视频 | 偷拍视频一区 | 亚洲免费视频在线观看 | a级一a一级在线观看 | 午夜视频一区二区三区 | 精品人妖videos欧美人妖 | 青青视频一区 | 九九九九免费视频 | 国产小视频在线免费观看 | 黄色成人av在线 | 在线观看av中文字幕 | 91少妇精拍在线播放 | 日本视频久久久 | 嫩草av影院 | 亚洲精品在线观看不卡 | 久久精彩 | 青青河边草免费直播 | 在线观看精品 | 久久久久国产一区二区三区 | 日韩理论片 | 激情综合网色播五月 | 日韩av一区二区三区 | 免费国产一区二区视频 | 伊人伊成久久人综合网小说 | 国产视频一级 | 国产精品 日本 | 西西444www高清大胆 | 久久国产精品99久久人人澡 | 在线播放亚洲激情 | 国产91对白在线播 | 激情网色 | 日本久久久亚洲精品 | 欧美激情视频一二区 | 国产精品夜夜夜一区二区三区尤 | 在线亚洲午夜片av大片 | 亚州激情视频 | 狠狠操.com| 日韩电影在线观看中文字幕 | 在线成人免费电影 | 国产综合久久 | 一本一本久久a久久精品牛牛影视 | 久久欧美综合 | 国产精品第7页 | 日韩精品久久中文字幕 | 国产精品国产自产拍高清av | 中文字幕精品www乱入免费视频 | 精品国产乱码久久久久久1区2匹 | av 一区二区三区 | 超碰在线成人 | 亚洲不卡av一区二区三区 | 久久久久 免费视频 | 成人影视免费看 | 久久免费视频8 | 9幺看片| 99热手机在线观看 | 99久久久久 | 在线观看国产91 | 国产精品电影一区 | 97香蕉久久国产在线观看 | 婷婷av电影 | 欧美激情视频一区二区三区 | 午夜骚影| 婷婷在线视频观看 | 欧美在线视频第一页 | 深爱婷婷激情 | 国产午夜精品福利视频 | 欧美三级高清 | 国产美女网站视频 | 亚洲天堂网站视频 | 91在线精品秘密一区二区 | 亚洲免费不卡 | 欧美日韩另类在线观看 | 久久久久免费精品国产小说色大师 | 久久久久麻豆v国产 | 国产精品一区二区免费在线观看 | 中文区中文字幕免费看 | 日韩免费高清在线 | 四虎成人av | 91麻豆传媒 | 伊人亚洲精品 | 97超在线视频 | 国产视频精选 | 在线成人av| 最新日韩视频在线观看 | 日韩精品一区二区三区高清免费 | 亚州av成人 | 欧美精品久 | 国产黄色av影视 | 91亚洲精品久久久 | 麻豆精品91| 亚洲h在线播放在线观看h | 香蕉视频最新网址 | 亚洲理论视频 | 91av亚洲 | 999久久国精品免费观看网站 | 欧美 亚洲 另类 激情 另类 | 天天操天天干天天 | 国产精品一区二区三区四 | 久久精品国产一区 | 亚洲理论在线 | 国产麻豆成人传媒免费观看 | 午夜久久电影网 | 18女毛片| 日韩在线免费看 | 亚洲国产成人久久综合 | 日韩精品中文字幕一区二区 | 日韩一区二区免费在线观看 | 日韩专区中文字幕 | 一区二区三区免费在线观看视频 | 五月婷婷香蕉 | 99久久国产免费,99久久国产免费大片 | 亚洲成a人片在线www | 日韩高清久久 | 97精品视频在线播放 | 91人人爽人人爽人人精88v | 久久 在线| 午夜精品久久一牛影视 | 五月婷婷激情网 | 黄网站色欧美视频 | 色偷偷88888欧美精品久久久 | 亚洲成人蜜桃 | 狠狠躁夜夜躁人人爽超碰97香蕉 | 综合天天 | 亚洲国产经典视频 | 国产精品精品久久久久久 | 亚洲国产最新 | 在线亚洲小视频 | 美女黄久久 | 日韩精品极品视频 | 国产中文字幕在线免费观看 | 99热这里精品| 99久免费精品视频在线观看 | 特级大胆西西4444www | 蜜臀av夜夜澡人人爽人人桃色 | 亚洲国产中文字幕在线 | 国产视频导航 | 久久影院午夜论 | 黄在线免费看 | 99在线观看视频网站 | 人人狠狠 | 亚洲欧美在线观看视频 | 成年人国产精品 | 亚洲 欧洲 国产 日本 综合 | 久久se视频 | 日本在线观看一区二区 | 国产丝袜制服在线 | 久久久久久久久久久久久影院 | 亚洲天堂视频在线 | 久久男女视频 | 亚洲精品播放 | 久久久久国产精品免费网站 | 久久 亚洲视频 | 日韩精品影视 | 免费在线观看成人小视频 | 日韩精品一区二区三区在线视频 | 日韩有码中文字幕在线 | 免费观看成人 | 国产亚洲一级高清 | 人人爽人人爽人人片av免 | 久久婷婷影视 | 亚洲精品五月天 | 日日麻批40分钟视频免费观看 | 国产精品青草综合久久久久99 | av网站在线观看播放 | 国产视频一 | 午夜电影 电影 | 天天操狠狠操 | 国产成人精品综合 | 久久超| 国产69精品久久久久99尤 | 日韩精品一区二区三区在线播放 | 国产破处在线视频 | 97色资源 | 久久精品99国产精品亚洲最刺激 | 欧美黄色高清 | 少妇av网| 日韩精品一区二区三区第95 | 热九九精品 | 人人爽人人爽 | 亚洲精品在线一区二区 | 丝袜美腿在线 | 日韩精品免费专区 | 91亚洲在线 | 在线看黄网站 | 久久只有精品 | 中文视频在线播放 | 久久精品久久精品久久 | 国产一级免费观看 | 视频在线国产 | 久久久精品高清 | 国产精品一区二区三区免费看 | 亚洲aⅴ一区二区三区 | 激情久久影院 | 奇米导航 | 综合色中色 | 又黄又爽的视频在线观看网站 | 成人污视频在线观看 | 国产青青青| 激情深爱.com | 韩日av一区二区 | 曰韩精品 | 欧美亚洲一区二区在线 | 不卡国产视频 | 波多野结衣电影一区二区三区 | 午夜少妇av| 欧美午夜性生活 | 成人禁用看黄a在线 | 91av超碰| 狠狠色狠狠色综合系列 | 午夜美女av | 久久狠狠一本精品综合网 | 久草电影免费在线观看 | 国产日韩欧美在线免费观看 | 免费看污污视频的网站 | 精品自拍sae8—视频 | 黄色特一级 | 成人免费共享视频 | 国产精品久久久久久久久久三级 | 99在线热播精品免费 | 黄色大片视频网站 | 国产成人av电影在线 | 国产青草视频在线观看 | 国产色拍拍拍拍在线精品 | 日韩在线中文字幕视频 | 一级一级一片免费 | 欧美日韩在线视频观看 | 色网av | 国产黄色精品视频 | 二区三区在线 | 香蕉网站在线观看 | 99理论片| 欧美高清视频不卡网 | 黄色在线成人 | 91人人爽人人爽人人精88v | 91大神免费在线观看 | 97电影在线看视频 | 97热在线观看| 国产精品福利无圣光在线一区 | 99国产情侣在线播放 | 狠狠狠狠狠狠狠狠干 | 国产精品一区二区62 | 久久人人97超碰精品888 | 免费在线电影网址大全 | 国产精品免费大片视频 | 成年人黄色免费视频 | 亚洲三级av | 亚洲综合色丁香婷婷六月图片 | 欧美午夜理伦三级在线观看 | 国产精品1区2区在线观看 | 欧美日韩一区二区三区在线免费观看 | 狠狠躁夜夜av | 国产成人一区三区 | 丁香婷婷激情五月 | 天天se天天cao天天干 | 中文字幕欧美日韩va免费视频 | 综合在线亚洲 | 久久精彩| 一级特黄aaa大片在线观看 | 亚洲男人天堂a | 国产91综合一区在线观看 | 欧美久草视频 | 国产精品99久久久久人中文网介绍 | 午夜视频免费播放 | 亚洲永久国产精品 | 日韩动漫免费观看高清完整版在线观看 | 人人干干人人 | 中文字幕在线观看完整版 | 夜夜操网站 | 黄色av三级在线 | 国产精品久久毛片 | 人人搞人人搞 | 色资源二区在线视频 | 日韩精品一区二区三区不卡 | а天堂中文最新一区二区三区 | 91精品国产欧美一区二区成人 | 亚洲综合在线观看视频 | 天天干天天干天天色 | 久久国产成人午夜av影院宅 | 视频在线播放国产 | 激情五月综合网 | 国产探花 | 欧美性性网| 精品国产伦一区二区三区免费 | 亚洲韩国一区二区三区 | 手机在线中文字幕 | 中文字幕电影在线 | 久久精品视频免费观看 | 99re国产视频 | 欧美日韩精品在线观看视频 | 黄色一级免费 | 国产免费一区二区三区最新6 | 麻豆传媒在线免费看 | 日韩在线在线 | 美女激情影院 | 久久五月婷婷综合 | 在线观看免费av网站 | 国产在线91精品 | 久久精品站 | 成人国产精品久久久春色 | 日韩精品专区在线影院重磅 | 毛片在线网 | 九九热在线精品视频 | av天天色 | 成人午夜精品福利免费 | 久久y| 五月天久久狠狠 | 超碰97在线看| 一区二区三区在线观看免费视频 | 亚洲一区美女视频在线观看免费 | 国产综合婷婷 | 久久不卡免费视频 | av免费看av | 国产天天爽 | 奇米网777 | 欧美一区视频 | a视频免费在线观看 | 国产视频一区二区在线观看 | 麻豆视频在线观看免费 | 色婷婷激情电影 | 在线观看一级视频 | 免费av在线播放 | av三级在线播放 | 美女视频永久黄网站免费观看国产 | 国产美女视频免费观看的网站 | 国产精品免费视频观看 | 国产黄在线 | 欧美性春潮 | 国产精品一区一区三区 | 亚洲精品一区二区三区新线路 | 美女av电影| 综合色中文 | 91精品国产网站 | 国产精品a久久久久 | 在线a人v观看视频 | 色噜噜在线观看 | 国产又黄又硬又爽 | 久草在线免费在线观看 | 国产第一页精品 | 激情伊人五月天久久综合 | 欧美另类一二三四区 | 午夜影院先| av电影一区 | 视频二区在线 | 久久国内精品 | 亚洲精品色 | 成人黄大片视频在线观看 | 久草视频在线资源 | 99久久电影 | 日日夜夜中文字幕 | 五月花婷婷| 97高清视频 | 免费高清av在线看 | 欧洲亚洲激情 | 狠狠综合网| 成人午夜影院在线观看 | 黄色一级影院 | 色综合夜色一区 | 国产亚洲精品福利 | 国产成人一区二区在线观看 | 国产在线综合视频 | 涩涩在线 | 久久久这里有精品 | 日韩精品一区二区三区在线播放 | 日韩午夜精品 | 91网在线看 | 欧美精品一二 | 99国产精品久久久久久久久久 | 五月婷婷在线观看视频 | 日韩高清www| av大片免费在线观看 | 国产小视频91 | 婷婷丁香国产 | av黄色免费在线观看 | 精品电影一区 | 亚洲天堂网视频 | 中文字幕在线中文 | 日韩一区正在播放 | 99在线免费视频 | 香蕉视频在线免费 | 亚洲综合在线一区二区三区 | 在线a亚洲视频播放在线观看 | 久久久久久国产一区二区三区 | 久久久久久久久久久久久久电影 | 精品国产一区二区三区久久影院 | av三区在线 | 日日躁你夜夜躁你av蜜 | 中文字幕资源在线 | 超碰人人舔 | 啪啪资源| 九九免费在线观看视频 | a天堂最新版中文在线地址 久久99久久精品国产 | 蜜臀aⅴ精品一区二区三区 久久视屏网 | 国产精品综合在线 | 在线免费观看av网站 | 午夜视频免费播放 | 一区 二区电影免费在线观看 | 国产一区电影在线观看 | 亚洲三级在线免费观看 | 国产精品久久久久婷婷 | 国产在线中文字幕 | 日b视频在线观看网址 | 国产91电影在线观看 | 国产精品免费观看久久 | 91久久精| 欧美精品一区二区蜜臀亚洲 | 91亚洲综合| 亚洲精品午夜国产va久久成人 | 国产精品 视频 | 久久久久久久久久久免费视频 | 日韩国产欧美在线播放 | 亚洲久草网 | 日韩国产欧美在线播放 | 久久精品一区二区三区视频 | 深爱五月激情五月 | 色婷婷啪啪免费在线电影观看 | 日本aaa在线观看 | 婷婷丁香狠狠爱 | 久久精品5 | 久久久久日本精品一区二区三区 | 婷婷久久综合九色综合 | 久久国产精彩视频 | 精品一区二区精品 | 在线免费观看的av | 天天做日日做天天爽视频免费 | 日韩电影一区二区三区在线观看 | 蜜臀av性久久久久蜜臀aⅴ涩爱 | 成人黄色毛片视频 | 伊人伊成久久人综合网站 | 在线观看成人一级片 | 国产日韩欧美在线看 | 国产精品美女久久久网av | 日本一区二区不卡高清 | 一区二区三区日韩视频在线观看 | 国产精品麻豆三级一区视频 | 亚洲精品中文字幕视频 | 欧美va天堂在线电影 | 免费色av | 美国av片在线观看 | 亚洲一级二级三级 | 国产三级视频 | 成人黄色毛片 | 国产视频午夜 | 国产小视频免费观看 | 国产麻豆精品久久 | 99精品久久99久久久久 | 久草视频在线资源 | 91av在线国产 | 亚洲专区在线播放 | 91专区在线观看 | 日韩首页| 天天曰天天射 | 久久精品美女视频 | 久久国产精品久久精品 | 国产精品18久久久久久首页狼 | 91免费高清在线观看 | 精品久久久久国产 | 国产精品免费在线播放 | 国产专区日韩专区 | 在线免费观看av网站 | 人人干狠狠操 | 一区二区三区免费在线 | 欧美最新大片在线看 | 欧美一区二区三区四区夜夜大片 | 婷婷狠狠操 | 亚洲 欧美 91 | 999成人网| 免费v片| 久久国产高清视频 | 国产精品尤物视频 | av在观看| 国产一区二区播放 | 久久久99精品免费观看乱色 | 午夜精品久久久久久 | 午夜精品一区二区三区在线播放 |