Bladeren bron

支持 curd 二级缓存处理

青苗 9 jaren geleden
bovenliggende
commit
a87c0d56bc

+ 7 - 0
mybatis-plus/pom.xml

@@ -40,6 +40,7 @@
 		<ojdbc14.version>10.2.0.5.0</ojdbc14.version>
 		<ojdbc14.version>10.2.0.5.0</ojdbc14.version>
 		<servlet-api.version>2.5</servlet-api.version>
 		<servlet-api.version>2.5</servlet-api.version>
 		<spring.version>4.2.5.RELEASE</spring.version>
 		<spring.version>4.2.5.RELEASE</spring.version>
+		<mybatis-ehcache.version>1.0.3</mybatis-ehcache.version>
 	</properties>
 	</properties>
 
 
 	<dependencies>
 	<dependencies>
@@ -83,6 +84,12 @@
 			<version>${spring.version}</version>
 			<version>${spring.version}</version>
 			<scope>provided</scope>
 			<scope>provided</scope>
 		</dependency>
 		</dependency>
+		<dependency>
+		    <groupId>org.mybatis.caches</groupId>
+		    <artifactId>mybatis-ehcache</artifactId>
+		    <version>${mybatis-ehcache.version}</version>
+			<scope>test</scope>
+		</dependency>
 
 
 		<!-- test begin -->
 		<!-- test begin -->
 		<dependency>
 		<dependency>

+ 3 - 40
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisConfiguration.java

@@ -15,17 +15,12 @@
  */
  */
 package com.baomidou.mybatisplus;
 package com.baomidou.mybatisplus;
 
 
-import java.util.Set;
 import java.util.logging.Logger;
 import java.util.logging.Logger;
 
 
-import org.apache.ibatis.io.ResolverUtil;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.mapping.MappedStatement;
 import org.apache.ibatis.scripting.LanguageDriver;
 import org.apache.ibatis.scripting.LanguageDriver;
 import org.apache.ibatis.session.Configuration;
 import org.apache.ibatis.session.Configuration;
-import org.apache.ibatis.session.SqlSession;
 
 
-import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
-import com.baomidou.mybatisplus.mapper.BaseMapper;
 import com.baomidou.mybatisplus.mapper.DBType;
 import com.baomidou.mybatisplus.mapper.DBType;
 
 
 /**
 /**
@@ -60,10 +55,12 @@ public class MybatisConfiguration extends Configuration {
 	 * 2、加载sqlProvider中的SQL<br>
 	 * 2、加载sqlProvider中的SQL<br>
 	 * 3、xmlSql 与 sqlProvider不能包含相同的SQL<br>
 	 * 3、xmlSql 与 sqlProvider不能包含相同的SQL<br>
 	 * <br>
 	 * <br>
-	 * 调整后的SQL优先级:xmlSql > sqlProvider > crudSql <br>
+	 * 调整后的SQL优先级:xmlSql > sqlProvider > curdSql <br>
 	 */
 	 */
 	@Override
 	@Override
 	public void addMappedStatement(MappedStatement ms) {
 	public void addMappedStatement(MappedStatement ms) {
+		logger.fine(" addMappedStatement: " + ms.getId());
+		System.out.println(ms.getId());
 		if (this.mappedStatements.containsKey(ms.getId())) {
 		if (this.mappedStatements.containsKey(ms.getId())) {
 			/*
 			/*
 			 * 说明已加载了xml中的节点; 忽略mapper中的SqlProvider数据
 			 * 说明已加载了xml中的节点; 忽略mapper中的SqlProvider数据
@@ -89,38 +86,4 @@ public class MybatisConfiguration extends Configuration {
 		return languageRegistry.getDriver(MybatisXMLLanguageDriver.class);
 		return languageRegistry.getDriver(MybatisXMLLanguageDriver.class);
 	}
 	}
 
 
-	@Override
-	public <T> T getMapper(Class<T> type, SqlSession sqlSession) {
-		return super.getMapper(type, sqlSession);
-	}
-
-	/**
-	 * 重新 addMapper 方法
-	 */
-	@Override
-	public <T> void addMapper(Class<T> type) {
-		super.addMapper(type);
-
-		if (!BaseMapper.class.isAssignableFrom(type)) {
-			return;
-		}
-
-		/* 自动注入 SQL */
-		new AutoSqlInjector(this, DB_TYPE).inject(type);
-	}
-
-	@Override
-	public void addMappers(String packageName) {
-		this.addMappers(packageName, Object.class);
-	}
-
-	@Override
-	public void addMappers(String packageName, Class<?> superType) {
-		ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<Class<?>>();
-		resolverUtil.find(new ResolverUtil.IsA(superType), packageName);
-		Set<Class<? extends Class<?>>> mapperSet = resolverUtil.getClasses();
-		for (Class<?> mapperClass : mapperSet) {
-			this.addMapper(mapperClass);
-		}
-	}
 }
 }

+ 4 - 3
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisXMLConfigBuilder.java

@@ -23,7 +23,6 @@ import javax.sql.DataSource;
 
 
 import org.apache.ibatis.builder.BaseBuilder;
 import org.apache.ibatis.builder.BaseBuilder;
 import org.apache.ibatis.builder.BuilderException;
 import org.apache.ibatis.builder.BuilderException;
-import org.apache.ibatis.builder.xml.XMLMapperBuilder;
 import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
 import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
 import org.apache.ibatis.datasource.DataSourceFactory;
 import org.apache.ibatis.datasource.DataSourceFactory;
 import org.apache.ibatis.executor.ErrorContext;
 import org.apache.ibatis.executor.ErrorContext;
@@ -371,13 +370,15 @@ public class MybatisXMLConfigBuilder extends BaseBuilder {
 					if (resource != null && url == null && mapperClass == null) {
 					if (resource != null && url == null && mapperClass == null) {
 						ErrorContext.instance().resource(resource);
 						ErrorContext.instance().resource(resource);
 						InputStream inputStream = Resources.getResourceAsStream(resource);
 						InputStream inputStream = Resources.getResourceAsStream(resource);
-						XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource,
+						//TODO
+						MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, resource,
 								configuration.getSqlFragments());
 								configuration.getSqlFragments());
 						mapperParser.parse();
 						mapperParser.parse();
 					} else if (resource == null && url != null && mapperClass == null) {
 					} else if (resource == null && url != null && mapperClass == null) {
 						ErrorContext.instance().resource(url);
 						ErrorContext.instance().resource(url);
 						InputStream inputStream = Resources.getUrlAsStream(url);
 						InputStream inputStream = Resources.getUrlAsStream(url);
-						XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url,
+						//TODO
+						MybatisXMLMapperBuilder mapperParser = new MybatisXMLMapperBuilder(inputStream, configuration, url,
 								configuration.getSqlFragments());
 								configuration.getSqlFragments());
 						mapperParser.parse();
 						mapperParser.parse();
 					} else if (resource == null && url == null && mapperClass != null) {
 					} else if (resource == null && url == null && mapperClass != null) {

+ 431 - 0
mybatis-plus/src/main/java/com/baomidou/mybatisplus/MybatisXMLMapperBuilder.java

@@ -0,0 +1,431 @@
+/**
+ * Copyright (c) 2011-2014, hubin (jobob@qq.com).
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+package com.baomidou.mybatisplus;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+import org.apache.ibatis.builder.BaseBuilder;
+import org.apache.ibatis.builder.BuilderException;
+import org.apache.ibatis.builder.CacheRefResolver;
+import org.apache.ibatis.builder.IncompleteElementException;
+import org.apache.ibatis.builder.MapperBuilderAssistant;
+import org.apache.ibatis.builder.ResultMapResolver;
+import org.apache.ibatis.builder.xml.XMLMapperEntityResolver;
+import org.apache.ibatis.builder.xml.XMLStatementBuilder;
+import org.apache.ibatis.cache.Cache;
+import org.apache.ibatis.executor.ErrorContext;
+import org.apache.ibatis.io.Resources;
+import org.apache.ibatis.mapping.Discriminator;
+import org.apache.ibatis.mapping.ParameterMapping;
+import org.apache.ibatis.mapping.ParameterMode;
+import org.apache.ibatis.mapping.ResultFlag;
+import org.apache.ibatis.mapping.ResultMap;
+import org.apache.ibatis.mapping.ResultMapping;
+import org.apache.ibatis.parsing.XNode;
+import org.apache.ibatis.parsing.XPathParser;
+import org.apache.ibatis.session.Configuration;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.TypeHandler;
+
+import com.baomidou.mybatisplus.mapper.AutoSqlInjector;
+import com.baomidou.mybatisplus.mapper.BaseMapper;
+
+/**
+ * <p>
+ * org.apache.ibatis.builder.xml.XMLMapperBuilder
+ * </p>
+ * <p>
+ * injector curdSql
+ * </p>
+ * 
+ * @author Clinton Begin hubin
+ * @Date 2016-06-13
+ */
+public class MybatisXMLMapperBuilder extends BaseBuilder {
+
+  private XPathParser parser;
+  private MapperBuilderAssistant builderAssistant;
+  private Map<String, XNode> sqlFragments;
+  private String resource;
+
+  @Deprecated
+  public MybatisXMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
+    this(reader, configuration, resource, sqlFragments);
+    this.builderAssistant.setCurrentNamespace(namespace);
+  }
+
+  @Deprecated
+  public MybatisXMLMapperBuilder(Reader reader, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
+    this(new XPathParser(reader, true, configuration.getVariables(), new XMLMapperEntityResolver()),
+        configuration, resource, sqlFragments);
+  }
+
+  public MybatisXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments, String namespace) {
+    this(inputStream, configuration, resource, sqlFragments);
+    this.builderAssistant.setCurrentNamespace(namespace);
+  }
+
+  public MybatisXMLMapperBuilder(InputStream inputStream, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
+    this(new XPathParser(inputStream, true, configuration.getVariables(), new XMLMapperEntityResolver()),
+        configuration, resource, sqlFragments);
+  }
+
+  private MybatisXMLMapperBuilder(XPathParser parser, Configuration configuration, String resource, Map<String, XNode> sqlFragments) {
+    super(configuration);
+    this.builderAssistant = new MapperBuilderAssistant(configuration, resource);
+    this.parser = parser;
+    this.sqlFragments = sqlFragments;
+    this.resource = resource;
+  }
+
+  public void parse() {
+    if (!configuration.isResourceLoaded(resource)) {
+      configurationElement(parser.evalNode("/mapper"));
+      configuration.addLoadedResource(resource);
+      bindMapperForNamespace();
+    }
+
+    parsePendingResultMaps();
+    parsePendingChacheRefs();
+    parsePendingStatements();
+  }
+
+  public XNode getSqlFragment(String refid) {
+    return sqlFragments.get(refid);
+  }
+
+  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");
+      }
+      builderAssistant.setCurrentNamespace(namespace);
+      cacheRefElement(context.evalNode("cache-ref"));
+      cacheElement(context.evalNode("cache"));
+      parameterMapElement(context.evalNodes("/mapper/parameterMap"));
+      resultMapElements(context.evalNodes("/mapper/resultMap"));
+      sqlElement(context.evalNodes("/mapper/sql"));
+      buildStatementFromContext(context.evalNodes("select|insert|update|delete"));
+    } catch (Exception e) {
+      throw new BuilderException("Error parsing Mapper XML. Cause: " + e, e);
+    }
+  }
+
+  private void buildStatementFromContext(List<XNode> list) {
+    if (configuration.getDatabaseId() != null) {
+      buildStatementFromContext(list, configuration.getDatabaseId());
+    }
+    buildStatementFromContext(list, null);
+  }
+
+  private void buildStatementFromContext(List<XNode> list, String requiredDatabaseId) {
+    for (XNode context : list) {
+      final XMLStatementBuilder statementParser = new XMLStatementBuilder(configuration, builderAssistant, context, requiredDatabaseId);
+      try {
+        statementParser.parseStatementNode();
+      } catch (IncompleteElementException e) {
+        configuration.addIncompleteStatement(statementParser);
+      }
+    }
+  }
+
+  private void parsePendingResultMaps() {
+    Collection<ResultMapResolver> incompleteResultMaps = configuration.getIncompleteResultMaps();
+    synchronized (incompleteResultMaps) {
+      Iterator<ResultMapResolver> iter = incompleteResultMaps.iterator();
+      while (iter.hasNext()) {
+        try {
+          iter.next().resolve();
+          iter.remove();
+        } catch (IncompleteElementException e) {
+          // ResultMap is still missing a resource...
+        }
+      }
+    }
+  }
+
+  private void parsePendingChacheRefs() {
+    Collection<CacheRefResolver> incompleteCacheRefs = configuration.getIncompleteCacheRefs();
+    synchronized (incompleteCacheRefs) {
+      Iterator<CacheRefResolver> iter = incompleteCacheRefs.iterator();
+      while (iter.hasNext()) {
+        try {
+          iter.next().resolveCacheRef();
+          iter.remove();
+        } catch (IncompleteElementException e) {
+          // Cache ref is still missing a resource...
+        }
+      }
+    }
+  }
+
+  private void parsePendingStatements() {
+    Collection<XMLStatementBuilder> incompleteStatements = configuration.getIncompleteStatements();
+    synchronized (incompleteStatements) {
+      Iterator<XMLStatementBuilder> iter = incompleteStatements.iterator();
+      while (iter.hasNext()) {
+        try {
+          iter.next().parseStatementNode();
+          iter.remove();
+        } catch (IncompleteElementException e) {
+          // Statement is still missing a resource...
+        }
+      }
+    }
+  }
+
+  private void cacheRefElement(XNode context) {
+    if (context != null) {
+      configuration.addCacheRef(builderAssistant.getCurrentNamespace(), context.getStringAttribute("namespace"));
+      CacheRefResolver cacheRefResolver = new CacheRefResolver(builderAssistant, context.getStringAttribute("namespace"));
+      try {
+        cacheRefResolver.resolveCacheRef();
+      } catch (IncompleteElementException e) {
+        configuration.addIncompleteCacheRef(cacheRefResolver);
+      }
+    }
+  }
+
+  private void cacheElement(XNode context) throws Exception {
+    if (context != null) {
+      String type = context.getStringAttribute("type", "PERPETUAL");
+      Class<? extends Cache> typeClass = typeAliasRegistry.resolveAlias(type);
+      String eviction = context.getStringAttribute("eviction", "LRU");
+      Class<? extends Cache> evictionClass = typeAliasRegistry.resolveAlias(eviction);
+      Long flushInterval = context.getLongAttribute("flushInterval");
+      Integer size = context.getIntAttribute("size");
+      boolean readWrite = !context.getBooleanAttribute("readOnly", false);
+      boolean blocking = context.getBooleanAttribute("blocking", false);
+      Properties props = context.getChildrenAsProperties();
+      builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, blocking, props);
+    }
+  }
+
+  private void parameterMapElement(List<XNode> list) throws Exception {
+    for (XNode parameterMapNode : list) {
+      String id = parameterMapNode.getStringAttribute("id");
+      String type = parameterMapNode.getStringAttribute("type");
+      Class<?> parameterClass = resolveClass(type);
+      List<XNode> parameterNodes = parameterMapNode.evalNodes("parameter");
+      List<ParameterMapping> parameterMappings = new ArrayList<ParameterMapping>();
+      for (XNode parameterNode : parameterNodes) {
+        String property = parameterNode.getStringAttribute("property");
+        String javaType = parameterNode.getStringAttribute("javaType");
+        String jdbcType = parameterNode.getStringAttribute("jdbcType");
+        String resultMap = parameterNode.getStringAttribute("resultMap");
+        String mode = parameterNode.getStringAttribute("mode");
+        String typeHandler = parameterNode.getStringAttribute("typeHandler");
+        Integer numericScale = parameterNode.getIntAttribute("numericScale");
+        ParameterMode modeEnum = resolveParameterMode(mode);
+        Class<?> javaTypeClass = resolveClass(javaType);
+        JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
+        @SuppressWarnings("unchecked")
+        Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
+        ParameterMapping parameterMapping = builderAssistant.buildParameterMapping(parameterClass, property, javaTypeClass, jdbcTypeEnum, resultMap, modeEnum, typeHandlerClass, numericScale);
+        parameterMappings.add(parameterMapping);
+      }
+      builderAssistant.addParameterMap(id, parameterClass, parameterMappings);
+    }
+  }
+
+  private void resultMapElements(List<XNode> list) throws Exception {
+    for (XNode resultMapNode : list) {
+      try {
+        resultMapElement(resultMapNode);
+      } catch (IncompleteElementException e) {
+        // ignore, it will be retried
+      }
+    }
+  }
+
+  private ResultMap resultMapElement(XNode resultMapNode) throws Exception {
+    return resultMapElement(resultMapNode, Collections.<ResultMapping> emptyList());
+  }
+
+  private ResultMap resultMapElement(XNode resultMapNode, List<ResultMapping> additionalResultMappings) throws Exception {
+    ErrorContext.instance().activity("processing " + resultMapNode.getValueBasedIdentifier());
+    String id = resultMapNode.getStringAttribute("id",
+        resultMapNode.getValueBasedIdentifier());
+    String type = resultMapNode.getStringAttribute("type",
+        resultMapNode.getStringAttribute("ofType",
+            resultMapNode.getStringAttribute("resultType",
+                resultMapNode.getStringAttribute("javaType"))));
+    String extend = resultMapNode.getStringAttribute("extends");
+    Boolean autoMapping = resultMapNode.getBooleanAttribute("autoMapping");
+    Class<?> typeClass = resolveClass(type);
+    Discriminator discriminator = null;
+    List<ResultMapping> resultMappings = new ArrayList<ResultMapping>();
+    resultMappings.addAll(additionalResultMappings);
+    List<XNode> resultChildren = resultMapNode.getChildren();
+    for (XNode resultChild : resultChildren) {
+      if ("constructor".equals(resultChild.getName())) {
+        processConstructorElement(resultChild, typeClass, resultMappings);
+      } else if ("discriminator".equals(resultChild.getName())) {
+        discriminator = processDiscriminatorElement(resultChild, typeClass, resultMappings);
+      } else {
+        List<ResultFlag> flags = new ArrayList<ResultFlag>();
+        if ("id".equals(resultChild.getName())) {
+          flags.add(ResultFlag.ID);
+        }
+        resultMappings.add(buildResultMappingFromContext(resultChild, typeClass, flags));
+      }
+    }
+    ResultMapResolver resultMapResolver = new ResultMapResolver(builderAssistant, id, typeClass, extend, discriminator, resultMappings, autoMapping);
+    try {
+      return resultMapResolver.resolve();
+    } catch (IncompleteElementException  e) {
+      configuration.addIncompleteResultMap(resultMapResolver);
+      throw e;
+    }
+  }
+
+  private void processConstructorElement(XNode resultChild, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
+    List<XNode> argChildren = resultChild.getChildren();
+    for (XNode argChild : argChildren) {
+      List<ResultFlag> flags = new ArrayList<ResultFlag>();
+      flags.add(ResultFlag.CONSTRUCTOR);
+      if ("idArg".equals(argChild.getName())) {
+        flags.add(ResultFlag.ID);
+      }
+      resultMappings.add(buildResultMappingFromContext(argChild, resultType, flags));
+    }
+  }
+
+  private Discriminator processDiscriminatorElement(XNode context, Class<?> resultType, List<ResultMapping> resultMappings) throws Exception {
+    String column = context.getStringAttribute("column");
+    String javaType = context.getStringAttribute("javaType");
+    String jdbcType = context.getStringAttribute("jdbcType");
+    String typeHandler = context.getStringAttribute("typeHandler");
+    Class<?> javaTypeClass = resolveClass(javaType);
+    @SuppressWarnings("unchecked")
+    Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
+    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
+    Map<String, String> discriminatorMap = new HashMap<String, String>();
+    for (XNode caseChild : context.getChildren()) {
+      String value = caseChild.getStringAttribute("value");
+      String resultMap = caseChild.getStringAttribute("resultMap", processNestedResultMappings(caseChild, resultMappings));
+      discriminatorMap.put(value, resultMap);
+    }
+    return builderAssistant.buildDiscriminator(resultType, column, javaTypeClass, jdbcTypeEnum, typeHandlerClass, discriminatorMap);
+  }
+
+  private void sqlElement(List<XNode> list) throws Exception {
+    if (configuration.getDatabaseId() != null) {
+      sqlElement(list, configuration.getDatabaseId());
+    }
+    sqlElement(list, null);
+  }
+
+  private void sqlElement(List<XNode> list, String requiredDatabaseId) throws Exception {
+    for (XNode context : list) {
+      String databaseId = context.getStringAttribute("databaseId");
+      String id = context.getStringAttribute("id");
+      id = builderAssistant.applyCurrentNamespace(id, false);
+      if (databaseIdMatchesCurrent(id, databaseId, requiredDatabaseId)) {
+        sqlFragments.put(id, context);
+      }
+    }
+  }
+  
+  private boolean databaseIdMatchesCurrent(String id, String databaseId, String requiredDatabaseId) {
+    if (requiredDatabaseId != null) {
+      if (!requiredDatabaseId.equals(databaseId)) {
+        return false;
+      }
+    } else {
+      if (databaseId != null) {
+        return false;
+      }
+      // skip this fragment if there is a previous one with a not null databaseId
+      if (this.sqlFragments.containsKey(id)) {
+        XNode context = this.sqlFragments.get(id);
+        if (context.getStringAttribute("databaseId") != null) {
+          return false;
+        }
+      }
+    }
+    return true;
+  }
+
+  private ResultMapping buildResultMappingFromContext(XNode context, Class<?> resultType, List<ResultFlag> flags) throws Exception {
+    String property = context.getStringAttribute("property");
+    String column = context.getStringAttribute("column");
+    String javaType = context.getStringAttribute("javaType");
+    String jdbcType = context.getStringAttribute("jdbcType");
+    String nestedSelect = context.getStringAttribute("select");
+    String nestedResultMap = context.getStringAttribute("resultMap",
+        processNestedResultMappings(context, Collections.<ResultMapping> emptyList()));
+    String notNullColumn = context.getStringAttribute("notNullColumn");
+    String columnPrefix = context.getStringAttribute("columnPrefix");
+    String typeHandler = context.getStringAttribute("typeHandler");
+    String resultSet = context.getStringAttribute("resultSet");
+    String foreignColumn = context.getStringAttribute("foreignColumn");
+    boolean lazy = "lazy".equals(context.getStringAttribute("fetchType", configuration.isLazyLoadingEnabled() ? "lazy" : "eager"));
+    Class<?> javaTypeClass = resolveClass(javaType);
+    @SuppressWarnings("unchecked")
+    Class<? extends TypeHandler<?>> typeHandlerClass = (Class<? extends TypeHandler<?>>) resolveClass(typeHandler);
+    JdbcType jdbcTypeEnum = resolveJdbcType(jdbcType);
+    return builderAssistant.buildResultMapping(resultType, property, column, javaTypeClass, jdbcTypeEnum, nestedSelect, nestedResultMap, notNullColumn, columnPrefix, typeHandlerClass, flags, resultSet, foreignColumn, lazy);
+  }
+  
+  private String processNestedResultMappings(XNode context, List<ResultMapping> resultMappings) throws Exception {
+    if ("association".equals(context.getName())
+        || "collection".equals(context.getName())
+        || "case".equals(context.getName())) {
+      if (context.getStringAttribute("select") == null) {
+        ResultMap resultMap = resultMapElement(context, resultMappings);
+        return resultMap.getId();
+      }
+    }
+    return null;
+  }
+
+  private void bindMapperForNamespace() {
+    String namespace = builderAssistant.getCurrentNamespace();
+    if (namespace != null) {
+      Class<?> boundType = null;
+      try {
+        boundType = Resources.classForName(namespace);
+      } catch (ClassNotFoundException e) {
+        //ignore, bound type is not required
+      }
+      if (boundType != null) {
+        if (!configuration.hasMapper(boundType)) {
+          // Spring may not know the real resource name so we set a flag
+          // to prevent loading again this resource from the mapper interface
+          // look at MapperAnnotationBuilder#loadXmlResource
+          configuration.addLoadedResource("namespace:" + namespace);
+          configuration.addMapper(boundType);
+        }
+        //TODO 注入 CURD 动态 SQL
+		if (BaseMapper.class.isAssignableFrom(boundType)) {
+			new AutoSqlInjector(configuration, MybatisConfiguration.DB_TYPE).inject(builderAssistant, boundType);
+		}
+      }
+    }
+  }
+
+}

+ 10 - 7
mybatis-plus/src/main/java/com/baomidou/mybatisplus/mapper/AutoSqlInjector.java

@@ -50,7 +50,7 @@ public class AutoSqlInjector {
 
 
 	private Configuration configuration;
 	private Configuration configuration;
 
 
-	private MapperBuilderAssistant assistant;
+	private MapperBuilderAssistant builderAssistant;
 	
 	
 	private DBType dbType = DBType.MYSQL;
 	private DBType dbType = DBType.MYSQL;
 	
 	
@@ -66,10 +66,8 @@ public class AutoSqlInjector {
 	/**
 	/**
 	 * 注入单点 crudSql
 	 * 注入单点 crudSql
 	 */
 	 */
-	public void inject(Class<?> mapperClass) {
-		assistant = new MapperBuilderAssistant(configuration, mapperClass.getName().replaceAll("\\.", "/"));
-		assistant.setCurrentNamespace(mapperClass.getName());
-
+	public void inject(MapperBuilderAssistant builderAssistant, Class<?> mapperClass) {
+		this.builderAssistant = builderAssistant;
 		Class<?> modelClass = extractModelClass(mapperClass);
 		Class<?> modelClass = extractModelClass(mapperClass);
 		TableInfo table = TableInfoHelper.getTableInfo(modelClass);
 		TableInfo table = TableInfoHelper.getTableInfo(modelClass);
 
 
@@ -561,8 +559,13 @@ public class AutoSqlInjector {
 			System.err.println("{" + statementName + "} Has been loaded by XML or SqlProvider, ignoring the injection of the SQL.");
 			System.err.println("{" + statementName + "} Has been loaded by XML or SqlProvider, ignoring the injection of the SQL.");
 			return null;
 			return null;
 		}
 		}
-		return assistant.addMappedStatement(id, sqlSource, StatementType.PREPARED, sqlCommandType, null, null, null,
-				parameterClass, null, resultType, null, false, true, false, keyGenerator, keyProperty, keyColumn,
+		/* 缓存逻辑处理 */
+		boolean isSelect = false;
+		if (sqlCommandType == SqlCommandType.SELECT) {
+			isSelect = true;
+		}
+		return builderAssistant.addMappedStatement(id, sqlSource, StatementType.PREPARED, sqlCommandType, null, null, null,
+				parameterClass, null, resultType, null, !isSelect, isSelect, false, keyGenerator, keyProperty, keyColumn,
 				configuration.getDatabaseId(), new MybatisXMLLanguageDriver(), null);
 				configuration.getDatabaseId(), new MybatisXMLLanguageDriver(), null);
 	}
 	}
 
 

+ 8 - 0
mybatis-plus/src/test/java/com/baomidou/mybatisplus/test/mysql/UserMapperTest.java

@@ -74,6 +74,14 @@ public class UserMapperTest {
 		 */
 		 */
 		int rlt = userMapper.insertInjector(new User(1L, "1", 1, 1));
 		int rlt = userMapper.insertInjector(new User(1L, "1", 1, 1));
 		System.err.println("--------- insertInjector --------- " + rlt);
 		System.err.println("--------- insertInjector --------- " + rlt);
+		
+		/**
+		 * ehcache 缓存测试
+		 */
+		User cacheUser = userMapper.selectOne(new User(1L, 1));
+		print(cacheUser);
+		cacheUser = userMapper.selectOne(new User(1L, 1));
+		print(cacheUser);
 
 
 		/**
 		/**
 		 * 插入
 		 * 插入

+ 27 - 0
mybatis-plus/src/test/resources/ehcache.xml

@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
+	<!--
+	name:Cache的唯一标识
+	maxElementsInMemory:内存中最大缓存对象数
+	maxElementsOnDisk:磁盘中最大缓存对象数,若是0表示无穷大
+	eternal:Element是否永久有效,一但设置了,timeout将不起作用
+	overflowToDisk:配置此属性,当内存中Element数量达到maxElementsInMemory时,Ehcache将会Element写到磁盘中
+	timeToIdleSeconds:设置Element在失效前的允许闲置时间。仅当element不是永久有效时使用,可选属性,默认值是0,也就是可闲置时间无穷大
+	timeToLiveSeconds:设置Element在失效前允许存活时间。最大时间介于创建时间和失效时间之间。仅当element不是永久有效时使用,默认是0.,也就是element存活时间无穷大 
+	diskPersistent:是否缓存虚拟机重启期数据
+	diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔,默认是120秒
+	diskSpoolBufferSizeMB:这个参数设置DiskStore(磁盘缓存)的缓存区大小。默认是30MB。每个Cache都应该有自己的一个缓冲区
+	 memoryStoreEvictionPolicy:当达到maxElementsInMemory限制时,Ehcache将会根据指定的策略去清理内存。默认策略是LRU(最近最少使用)。你可以设置为FIFO(先进先出)或是LFU(较少使用) 
+	
+	备注: 持久化到硬盘的路径由虚拟机参数"java.io.tmpdir"决定.
+	例如, 在windows中, 会在此路径下
+	C:\Documents and Settings\li\Local Settings\Temp
+	在linux中, 通常会在: /tmp 下
+	System.out.println(System.getProperty("java.io.tmpdir"));
+	
+	-->
+	
+	<diskStore path="java.io.tmpdir" />
+	<defaultCache maxElementsInMemory="0" eternal="false"
+		timeToIdleSeconds="0" timeToLiveSeconds="0" overflowToDisk="false" />
+</ehcache>

+ 5 - 1
mybatis-plus/src/test/resources/mysql/UserMapper.xml

@@ -2,12 +2,16 @@
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 <mapper namespace="com.baomidou.mybatisplus.test.mysql.UserMapper">
 <mapper namespace="com.baomidou.mybatisplus.test.mysql.UserMapper">
 
 
+	<!-- ehcache 缓存配置, 输出日志 http://www.mybatis.org/ehcache-cache/ -->
+	<cache type="org.mybatis.caches.ehcache.LoggingEhcache" />
+
 	<delete id="deleteAll">
 	<delete id="deleteAll">
 		DELETE FROM USER
 		DELETE FROM USER
 	</delete>
 	</delete>
 
 
 	<!-- 建议字段,采用驼峰命名方法,不然很麻烦 -->
 	<!-- 建议字段,采用驼峰命名方法,不然很麻烦 -->
 	<select id="selectListRow" resultType="User">
 	<select id="selectListRow" resultType="User">
-		select test_id AS id,name,age,test_type AS testType from user
+		select test_id AS
+		id,name,age,test_type AS testType from user
 	</select>
 	</select>
 </mapper>
 </mapper>