- 浏览: 984951 次
文章分类
- 全部博客 (428)
- Hadoop (2)
- HBase (1)
- ELK (1)
- ActiveMQ (13)
- Kafka (5)
- Redis (14)
- Dubbo (1)
- Memcached (5)
- Netty (56)
- Mina (34)
- NIO (51)
- JUC (53)
- Spring (13)
- Mybatis (17)
- MySQL (21)
- JDBC (12)
- C3P0 (5)
- Tomcat (13)
- SLF4J-log4j (9)
- P6Spy (4)
- Quartz (12)
- Zabbix (7)
- JAVA (9)
- Linux (15)
- HTML (9)
- Lucene (0)
- JS (2)
- WebService (1)
- Maven (4)
- Oracle&MSSQL (14)
- iText (11)
- Development Tools (8)
- UTILS (4)
- LIFE (8)
最新评论
-
Donald_Draper:
Donald_Draper 写道刘落落cici 写道能给我发一 ...
DatagramChannelImpl 解析三(多播) -
Donald_Draper:
刘落落cici 写道能给我发一份这个类的源码吗Datagram ...
DatagramChannelImpl 解析三(多播) -
lyfyouyun:
请问楼主,执行消息发送的时候,报错:Transport sch ...
ActiveMQ连接工厂、连接详解 -
ezlhq:
关于 PollArrayWrapper 状态含义猜测:参考 S ...
WindowsSelectorImpl解析一(FdMap,PollArrayWrapper) -
flyfeifei66:
打算使用xmemcache作为memcache的客户端,由于x ...
Memcached分布式客户端(Xmemcached)
SqlSessionFactory初始化:http://donald-draper.iteye.com/blog/2331917
Mybatis加载解析Mapper(xml)文件第一讲:http://donald-draper.iteye.com/blog/2333125
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
在前面两篇中,我们谈到Mapper(xml)文件的加载解析,今天来看一下,当全局配置文件中Mapper的resource和url为空时,classs不为空时,如何处理Mapper xml,文件和class。
//Configuration
//MapperRegistry
//MapperProxyFactory,mapperInterface的代理工厂
//MapperProxy
//MapperMethod
从上可以看出Configuration添加MapperInterface,就是MapperRegistry注册到其
HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存;MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法。
现在回到MapperInterface,class的注解
//MapperAnnotationBuilder,MapperInterface的注解处理
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
configuration.addLoadedResource(resource);
//Configuration
//设置MapperBuilderAssistant的命名空间
assistant.setCurrentNamespace(type.getName());
//解析注解缓存配置信息,并添加的Configuration,Cache Set
parseCache();
//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
//CacheBuilder
//Configuration
//将缓存添加到Configuration的二级缓存中
从上的分析可以看出@CacheNamespace的解析,实际上是,获取@CacheNamespace的type对应的Class,@CacheNamespace的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>
//解析缓存参考注解
parseCacheRef();
//MapperBuilderAssistant,
从分析@CacheNamespaceRef的解析,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException;
//遍历所有方法,解析方法注解
parseStatement(method);
//处理Statement方法method
// 方法的@SelectKey,解析处理,下面是xml配置,以辅助理解
//根据SelectKeyAnnotation信息,获取KeyGenerator
//Configuration
现在回到
parseStatement(Method method)的ResultMap的处理
//解析method的@ResultMap
再来看
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver);
//MapperBuilderAssistant
//添加MappedStatement到Configuration
mappedStatements = new StrictMap("Mapped Statements collection");
//MappedStatement
从上可以看出解析@SelectKey信息,跟@SelectKey节点的属性信息,构建keyStatement,
并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,如果无@SelectKey,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据method方法注解信息和KeyGenerator,构造MapperStatement,
添加到configuration的mappedStatements的Map中并添加在configuration的keyGenerators-Map中
//遍历configuration的IncompleteMethods集合,重新解析MethodResolver
parsePendingMethods();
//MethodResolver
总结:
MapperInterface的解析,首先Configuration添加MapperInterface,实质上MapperRegistry注册到其HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存,MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法;加载mapInterface,package路径下的Mapper xml文件,如果未加载,则加载解析;@CacheNamespace的解析,实际上是,获取@CacheNamespace的type对应的Class,@CacheNamespace的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;@CacheNamespaceRef的解析,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,
不存在,则抛出IncompleteElementException;解析@SelectKey信息,跟@SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,如果无@SelectKey,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据method方法注解信息和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中并添加在configuration的keyGenerators-Map中。
//ParameterMap
//ResultMap
//BoundSql
//MetaObject
//SqlCommandType
//StatementTypes
//ResultSetType
Mybatis加载解析Mapper(xml)文件第一讲:http://donald-draper.iteye.com/blog/2333125
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
在前面两篇中,我们谈到Mapper(xml)文件的加载解析,今天来看一下,当全局配置文件中Mapper的resource和url为空时,classs不为空时,如何处理Mapper xml,文件和class。
private void mapperElement(XNode parent) throws Exception { if(parent != null) { for(Iterator i$ = parent.getChildren().iterator(); i$.hasNext();) { XNode child = (XNode)i$.next(); if("package".equals(child.getName())) { String mapperPackage = child.getStringAttribute("name"); configuration.addMappers(mapperPackage); } else { String resource = child.getStringAttribute("resource"); String url = child.getStringAttribute("url"); String mapperClass = child.getStringAttribute("class"); //根据配置的resource,解析Mapper if(resource != null && url == null && mapperClass == null) { ErrorContext.instance().resource(resource); //加载Mapper的resource文件 InputStream inputStream = Resources.getResourceAsStream(resource); 构建XMLMapperBuilder XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, resource, configuration.getSqlFragments()); mapperParser.parse(); } else if(resource == null && url != null && mapperClass == null) { ErrorContext.instance().resource(url); InputStream inputStream = Resources.getUrlAsStream(url); //url配置的解析,与resource相同 XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments()); mapperParser.parse(); } else //根据配置的class,解析Mapper if(resource == null && url == null && mapperClass != null) { Class mapperInterface = Resources.classForName(mapperClass); //mapperInterface信息添加到configuration configuration.addMapper(mapperInterface); } else { throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one."); } } } } }
//Configuration
public void addMapper(Class type) { mapperRegistry.addMapper(type); }
//MapperRegistry
public class MapperRegistry { public void addMapper(Class type) { boolean loadCompleted; if(!type.isInterface()) break MISSING_BLOCK_LABEL_125; if(hasMapper(type)) throw new BindingException((new StringBuilder()).append("Type ").append(type).append(" is already known to the MapperRegistry.").toString()); loadCompleted = false; //添加Class与MapperProxyFactory的对应关系 knownMappers.put(type, new MapperProxyFactory(type)); //构造Mapperclass注解Builder类 MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type); //解析注解 parser.parse(); loadCompleted = true; if(!loadCompleted) knownMappers.remove(type); break MISSING_BLOCK_LABEL_125; Exception exception; exception; if(!loadCompleted) knownMappers.remove(type); throw exception; } private Configuration config; //HashMap<Class,MapperProxyFactory> private final Map knownMappers = new HashMap(); }
//MapperProxyFactory,mapperInterface的代理工厂
public class MapperProxyFactory { public MapperProxyFactory(Class mapperInterface) { methodCache = new ConcurrentHashMap(); this.mapperInterface = mapperInterface; } protected Object newInstance(MapperProxy mapperProxy) { //代理生成实例 return Proxy.newProxyInstance(mapperInterface.getClassLoader(), new Class[] { mapperInterface }, mapperProxy); } public Object newInstance(SqlSession sqlSession) { MapperProxy mapperProxy = new MapperProxy(sqlSession, mapperInterface, methodCache); return newInstance(mapperProxy); } private final Class mapperInterface; private Map methodCache; }
//MapperProxy
public class MapperProxy implements InvocationHandler, Serializable { public MapperProxy(SqlSession sqlSession, Class mapperInterface, Map methodCache) { this.sqlSession = sqlSession; this.mapperInterface = mapperInterface; this.methodCache = methodCache; } public Object invoke(Object proxy, Method method, Object args[]) throws Throwable { if(java/lang/Object.equals(method.getDeclaringClass())) { return method.invoke(this, args); } else { MapperMethod mapperMethod = cachedMapperMethod(method); return mapperMethod.execute(sqlSession, args); } } private MapperMethod cachedMapperMethod(Method method) { MapperMethod mapperMethod = (MapperMethod)methodCache.get(method); if(mapperMethod == null) { mapperMethod = new MapperMethod(mapperInterface, method, sqlSession.getConfiguration()); methodCache.put(method, mapperMethod); } return mapperMethod; } private static final long serialVersionUID = -6424540398559729838L; private final SqlSession sqlSession; private final Class mapperInterface; //Map<Method,MapperMethod>,即二级缓存 private final Map methodCache; }
//MapperMethod
public class MapperMethod { //方法签名 public static class MethodSignature{ private final boolean returnsMany; private final boolean returnsMap; private final boolean returnsVoid; private final Class returnType; private final String mapKey; private final Integer resultHandlerIndex; private final Integer rowBoundsIndex; private final SortedMap params; private final boolean hasNamedParameters; public MethodSignature(Configuration configuration, Method method) throws BindingException { returnType = method.getReturnType(); returnsVoid = Void.TYPE.equals(returnType); returnsMany = configuration.getObjectFactory().isCollection(returnType) || returnType.isArray(); mapKey = getMapKey(method); returnsMap = mapKey != null; hasNamedParameters = hasNamedParams(method); rowBoundsIndex = getUniqueParamIndex(method, org/apache/ibatis/session/RowBounds); resultHandlerIndex = getUniqueParamIndex(method, org/apache/ibatis/session/ResultHandler); params = Collections.unmodifiableSortedMap(getParams(method, hasNamedParameters)); } } //statement类型,SqlCommand public static class SqlCommand { private final String name;//select|insert|update|delete节点的全局id private final SqlCommandType type; } //参数Map public static class ParamMap extends HashMap { public Object get(Object key) { if(!super.containsKey(key)) throw new BindingException((new StringBuilder()).append("Parameter '").append(key).append("' not found. Available parameters are ").append(keySet()).toString()); else return super.get(key); } private static final long serialVersionUID = -2212268410512043556L; public ParamMap() { } } //method执行方法 public Object execute(SqlSession sqlSession, Object args[]) { Object result; //插入 if(SqlCommandType.INSERT == command.getType()) { //将参数转换为SqlCommand对应的参数 Object param = method.convertArgsToSqlCommandParam(args); //执行插入,并包装返回结果 result = rowCountResult(sqlSession.insert(command.getName(), param)); } else //更新 if(SqlCommandType.UPDATE == command.getType()) { //执行更新,并包装返回结果 Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.update(command.getName(), param)); } else //删除 if(SqlCommandType.DELETE == command.getType()) { //执行删除,并包装返回结果 Object param = method.convertArgsToSqlCommandParam(args); result = rowCountResult(sqlSession.delete(command.getName(), param)); } else //查询 if(SqlCommandType.SELECT == command.getType()) { if(method.returnsVoid() && method.hasResultHandler()) { //无返回结果 executeWithResultHandler(sqlSession, args); result = null; } else if(method.returnsMany()) //返回结果为List result = executeForMany(sqlSession, args); else if(method.returnsMap()) { //返回结果为Map result = executeForMap(sqlSession, args); } else { //返回结果为Object Object param = method.convertArgsToSqlCommandParam(args); result = sqlSession.selectOne(command.getName(), param); } } else { throw new BindingException((new StringBuilder()).append("Unknown execution method for: ").append(command.getName()).toString()); } if(result == null && method.getReturnType().isPrimitive() && !method.returnsVoid()) throw new BindingException((new StringBuilder()).append("Mapper method '").append(command.getName()).append(" attempted to return null from a method with a primitive return type (").append(method.getReturnType()).append(").").toString()); else return result; } //包装返回结果 private Object rowCountResult(int rowCount) { Object result; if(method.returnsVoid()) result = null; else if(java/lang/Integer.equals(method.getReturnType()) || Integer.TYPE.equals(method.getReturnType())) result = Integer.valueOf(rowCount); else if(java/lang/Long.equals(method.getReturnType()) || Long.TYPE.equals(method.getReturnType())) result = Long.valueOf(rowCount); else if(java/lang/Boolean.equals(method.getReturnType()) || Boolean.TYPE.equals(method.getReturnType())) result = Boolean.valueOf(rowCount > 0); else throw new BindingException((new StringBuilder()).append("Mapper method '").append(command.getName()).append("' has an unsupported return type: ").append(method.getReturnType()).toString()); return result; } //无返回结果 private void executeWithResultHandler(SqlSession sqlSession, Object args[]) { MappedStatement ms = sqlSession.getConfiguration().getMappedStatement(command.getName()); if(Void.TYPE.equals(((ResultMap)ms.getResultMaps().get(0)).getType())) throw new BindingException((new StringBuilder()).append("method ").append(command.getName()).append(" needs either a @ResultMap annotation, a @ResultType annotation,").append(" or a resultType attribute in XML so a ResultHandler can be used as a parameter.").toString()); Object param = method.convertArgsToSqlCommandParam(args); if(method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); sqlSession.select(command.getName(), param, rowBounds, method.extractResultHandler(args)); } else { sqlSession.select(command.getName(), param, method.extractResultHandler(args)); } } //返回结果为List private Object executeForMany(SqlSession sqlSession, Object args[]) { Object param = method.convertArgsToSqlCommandParam(args); List result; if(method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.selectList(command.getName(), param, rowBounds); } else { result = sqlSession.selectList(command.getName(), param); } if(!method.getReturnType().isAssignableFrom(result.getClass())) { if(method.getReturnType().isArray()) return ((Object) (convertToArray(result))); else return convertToDeclaredCollection(sqlSession.getConfiguration(), result); } else { return result; } } //返回结果为Map private Map executeForMap(SqlSession sqlSession, Object args[]) { Object param = method.convertArgsToSqlCommandParam(args); Map result; if(method.hasRowBounds()) { RowBounds rowBounds = method.extractRowBounds(args); result = sqlSession.selectMap(command.getName(), param, method.getMapKey(), rowBounds); } else { result = sqlSession.selectMap(command.getName(), param, method.getMapKey()); } return result; } private final SqlCommand command;//method,对应的statement的描述 private final MethodSignature method;//方法签名 }
从上可以看出Configuration添加MapperInterface,就是MapperRegistry注册到其
HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,
生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存;MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法。
现在回到MapperInterface,class的注解
//MapperAnnotationBuilder,MapperInterface的注解处理
public class MapperAnnotationBuilder { private final Set sqlAnnotationTypes = new HashSet(); private final Set sqlProviderAnnotationTypes = new HashSet(); private Configuration configuration; private MapperBuilderAssistant assistant;//Mapper助手 private Class type;//MapperInterface Type public MapperAnnotationBuilder(Configuration configuration, Class type) { String resource = (new StringBuilder()).append(type.getName().replace('.', '/')).append(".java (best guess)").toString(); assistant = new MapperBuilderAssistant(configuration, resource); this.configuration = configuration; this.type = type; sqlAnnotationTypes.add(org/apache/ibatis/annotations/Select); sqlAnnotationTypes.add(org/apache/ibatis/annotations/Insert); sqlAnnotationTypes.add(org/apache/ibatis/annotations/Update); sqlAnnotationTypes.add(org/apache/ibatis/annotations/Delete); sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/SelectProvider); sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/InsertProvider); sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/UpdateProvider); sqlProviderAnnotationTypes.add(org/apache/ibatis/annotations/DeleteProvider); } //解析Mapper XML文件 public void parse() { String resource = type.toString(); if(!configuration.isResourceLoaded(resource)) { //如果configuration,未加载type对应的Mapper XML文件, //则加载对应的XML文件 //加载mapInterface,package路径下的Mapper xml文件 loadXmlResource(); //Configuration,添加Mapper xml文件资源id,到Set<String> loadedResources; //Key为class的完整名(com.mapper.userMapper) configuration.addLoadedResource(resource); //设置MapperBuilderAssistant的命名空间 assistant.setCurrentNamespace(type.getName()); //解析注解缓存配置信息,并添加的Configuration,Cache Set parseCache(); //解析缓存参考注解 parseCacheRef(); Method methods[] = type.getMethods(); Method arr$[] = methods; int len$ = arr$.length; for(int i$ = 0; i$ < len$; i$++) { Method method = arr$[i$]; try { //遍历所有方法,解析方法注解 parseStatement(method); } catch(IncompleteElementException e) { //如果缓存参考没有解决,则抛出IncompleteElementException,并将MethodResolver, //添加到configuration的LinkedList<MethodResolver> incompleteMethod中 configuration.addIncompleteMethod(new MethodResolver(this, method)); } } } //将方法从configuration的IncompleteMethods集合中移除 parsePendingMethods(); } } //如果configuration,未加载type对应的Mapper XML文件, //加载mapInterface,package路径下的Mapper xml文件 loadXmlResource(); private void loadXmlResource() { //如果configuration,未加载type对应的Mapper XML文件, if(!configuration.isResourceLoaded((new StringBuilder()).append("namespace:").append(type.getName()).toString())) { String xmlResource = (new StringBuilder()).append(type.getName().replace('.', '/')).append(".xml").toString(); InputStream inputStream = null; try { //加载包路径下的Mapper xml文件,文件名为type.getName().replace('.', '/').append(".xml").toString() //com.mapper.userMapper.class //com/mapper/userMapper.xml inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource); } if(inputStream != null) { //这个XML文件的解析,我们在上两篇文章已经讲过 XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName()); xmlParser.parse(); } } }
//Configuration,添加Mapper xml文件名到Set<String> loadedResources;
//其中key为class完整名,com.mapper.UserMapper
configuration.addLoadedResource(resource);
//Configuration
public void addLoadedResource(String resource) { loadedResources.add(resource); }
//设置MapperBuilderAssistant的命名空间
assistant.setCurrentNamespace(type.getName());
//MapperBuilderAssistant public class MapperBuilderAssistant extends BaseBuilder { private String currentNamespace;//缓存命名空间 private String resource;//Mapper xml文件url private Cache currentCache;//当前缓存 private boolean unresolvedCacheRef;//缓存引用是否解决 public MapperBuilderAssistant(Configuration configuration, String resource) { super(configuration); ErrorContext.instance().resource(resource); this.resource = resource; } //设置Mapper对应的命名空间 public void setCurrentNamespace(String currentNamespace) { if(currentNamespace == null) throw new BuilderException("The mapper element requires a namespace attribute to be specified."); if(this.currentNamespace != null && !this.currentNamespace.equals(currentNamespace)) { throw new BuilderException((new StringBuilder()).append("Wrong namespace. Expected '").append(this.currentNamespace).append("' but found '").append(currentNamespace).append("'.").toString()); } else { this.currentNamespace = currentNamespace; return; } } }
//解析注解缓存配置信息,并添加的Configuration,Cache Set
parseCache();
//解析CacheNamespace注解 private void parseCache() { CacheNamespace cacheDomain = (CacheNamespace)type.getAnnotation(org/apache/ibatis/annotations/CacheNamespace); if(cacheDomain != null) assistant.useNewCache(cacheDomain.implementation(), cacheDomain.eviction(), Long.valueOf(cacheDomain.flushInterval()), Integer.valueOf(cacheDomain.size()), cacheDomain.readWrite(), null); }
//MapperBuilderAssistant
//将缓存添加到Configuration的二级缓存中
public Cache useNewCache(Class typeClass, Class evictionClass, Long flushInterval, Integer size, boolean readWrite, Properties props) { //获取缓存类型 typeClass = (Class)valueOrDefault(typeClass, org/apache/ibatis/cache/impl/PerpetualCache); //获取缓存算法类型 evictionClass = (Class)valueOrDefault(evictionClass, org/apache/ibatis/cache/decorators/LruCache); //构建缓存 Cache cache = (new CacheBuilder(currentNamespace)).implementation(typeClass).addDecorator(evictionClass).clearInterval(flushInterval).size(size).readWrite(readWrite).properties(props).build(); //将缓存添加到Configuration的二级缓存中 configuration.addCache(cache); currentCache = cache; return cache; }
//CacheBuilder
public class CacheBuilder { private String id; private Class implementation;//缓存实现类 private List decorators;//缓存解码器 private Integer size; private Long clearInterval;//刷新间隔 private boolean readWrite;//是否可读写 private Properties properties; public CacheBuilder(String id) }
//Configuration
//将缓存添加到Configuration的二级缓存中
//StrictMap<currentNamespace,CacheBuilder> //caches = new StrictMap("Caches collection"); public void addCache(Cache cache) { caches.put(cache.getId(), cache); }
从上的分析可以看出@CacheNamespace的解析,实际上是,获取@CacheNamespace的type对应的Class,@CacheNamespace的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>
//解析缓存参考注解
parseCacheRef();
//解析CacheNamespaceRef注解 private void parseCacheRef() { CacheNamespaceRef cacheDomainRef = (CacheNamespaceRef)type.getAnnotation(org/apache/ibatis/annotations/CacheNamespaceRef); if(cacheDomainRef != null) assistant.useCacheRef(cacheDomainRef.value().getName()); }
//MapperBuilderAssistant,
public Cache useCacheRef(String namespace) { if(namespace == null) throw new BuilderException("cache-ref element requires a namespace attribute."); Cache cache; unresolvedCacheRef = true; //根据命名空间,从configuration而级缓存中,获取缓存 cache = configuration.getCache(namespace); if(cache == null) throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString()); //从这里可以看出,参考命名的缓存必须存在,否则抛出异常 currentCache = cache; unresolvedCacheRef = false; return cache; IllegalArgumentException e; e; throw new IncompleteElementException((new StringBuilder()).append("No cache for namespace '").append(namespace).append("' could be found.").toString(), e); }
从分析@CacheNamespaceRef的解析,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,不存在,则抛出IncompleteElementException;
//遍历所有方法,解析方法注解
parseStatement(method);
//处理Statement方法method
void parseStatement(Method method) { //获取Method参数类型 Class parameterTypeClass = getParameterType(method); //获取Method的LanguageDriver LanguageDriver languageDriver = getLanguageDriver(method); SqlSource sqlSource = getSqlSourceFromAnnotations(method, parameterTypeClass, languageDriver); if(sqlSource != null) { Options options = (Options)method.getAnnotation(org/apache/ibatis/annotations/Options); //构造mappedStatementId String mappedStatementId = (new StringBuilder()).append(type.getName()).append(".").append(method.getName()).toString(); Integer fetchSize = null; Integer timeout = null; //statementType,为PREPARED StatementType statementType = StatementType.PREPARED; //resultSetType为FORWARD_ONLY ResultSetType resultSetType = ResultSetType.FORWARD_ONLY; //获取Method的SQL类型 SqlCommandType sqlCommandType = getSqlCommandType(method); //是否是SELECT类型 boolean isSelect = sqlCommandType == SqlCommandType.SELECT; //是否刷新缓存,如果不是SELECT,则刷新缓存,否,不刷新缓存 boolean flushCache = !isSelect; //是否用缓存,SELECT则用缓存,否,不用缓存 boolean useCache = isSelect; //默认 keyProperty为id; String keyProperty = "id"; String keyColumn = null; KeyGenerator keyGenerator; //如果是SQL是INSERT类型,isUseGeneratedKeys属性获取对应的keyGenerator, //keyGenerator,这个我们在后文中,再讲 if(SqlCommandType.INSERT.equals(sqlCommandType)) { //获取@SelectKey信息 SelectKey selectKey = (SelectKey)method.getAnnotation(org/apache/ibatis/annotations/SelectKey); if(selectKey != null) { keyGenerator = handleSelectKeyAnnotation(selectKey, mappedStatementId, getParameterType(method), languageDriver); //获取keyProperty从@SelectKey keyProperty = selectKey.keyProperty(); } else if(options == null) { keyGenerator = ((KeyGenerator) (configuration.isUseGeneratedKeys() ? ((KeyGenerator) (new Jdbc3KeyGenerator())) : ((KeyGenerator) (new NoKeyGenerator())))); } else { keyGenerator = ((KeyGenerator) (options.useGeneratedKeys() ? ((KeyGenerator) (new Jdbc3KeyGenerator())) : ((KeyGenerator) (new NoKeyGenerator())))); keyProperty = options.keyProperty(); keyColumn = options.keyColumn(); } } else { keyGenerator = new NoKeyGenerator(); } if(options != null) { //根据Options注解信息,获取flushCache,useCache,fetchSize,timeout,statementType,resultSetType等信息 flushCache = options.flushCache(); useCache = options.useCache(); fetchSize = options.fetchSize() <= -1 && options.fetchSize() != -2147483648 ? null : Integer.valueOf(options.fetchSize()); timeout = options.timeout() <= -1 ? null : Integer.valueOf(options.timeout()); statementType = options.statementType(); resultSetType = options.resultSetType(); } String resultMapId = null; //获取ResultMap注解信息 ResultMap resultMapAnnotation = (ResultMap)method.getAnnotation(org/apache/ibatis/annotations/ResultMap); if(resultMapAnnotation != null) resultMapId = resultMapAnnotation.value(); else if(isSelect) //解析method的resultMap resultMapId = parseResultMap(method); //根据方法的注解信息,构建MappedStatement //并添加到configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement> assistant.addMappedStatement(mappedStatementId, sqlSource, statementType, sqlCommandType, fetchSize, timeout, null, parameterTypeClass, resultMapId, getReturnType(method), resultSetType, flushCache, useCache, false, keyGenerator, keyProperty, keyColumn, null, languageDriver); } } //获取Method参数类型 private Class getParameterType(Method method) { Class parameterType = null; Class parameterTypes[] = method.getParameterTypes(); for(int i = 0; i < parameterTypes.length; i++) { if(org/apache/ibatis/session/RowBounds.isAssignableFrom(parameterTypes[i])) continue; if(parameterType == null) parameterType = parameterTypes[i]; else parameterType = java/util/Map; } return parameterType; } //获取Method的LanguageDriver private LanguageDriver getLanguageDriver(Method method) { Lang lang = (Lang)method.getAnnotation(org/apache/ibatis/annotations/Lang); if(lang != null) { Class languageDriverClass = lang.value(); return configuration.getLanguageRegistry().getDriver(languageDriverClass); } else { return configuration.getLanguageRegistry().getDefaultDriver(); } } //获取Method的SQL类型 private SqlCommandType getSqlCommandType(Method method) { Class type = getSqlAnnotationType(method); if(type == null) { type = getSqlProviderAnnotationType(method); if(type == null) return SqlCommandType.UNKNOWN; if(type == org/apache/ibatis/annotations/SelectProvider) type = org/apache/ibatis/annotations/Select; else if(type == org/apache/ibatis/annotations/InsertProvider) type = org/apache/ibatis/annotations/Insert; else if(type == org/apache/ibatis/annotations/UpdateProvider) type = org/apache/ibatis/annotations/Update; else if(type == org/apache/ibatis/annotations/DeleteProvider) type = org/apache/ibatis/annotations/Delete; } return SqlCommandType.valueOf(type.getSimpleName().toUpperCase(Locale.ENGLISH)); }
// 方法的@SelectKey,解析处理,下面是xml配置,以辅助理解
<!-- 对应userDao中的insertUser方法, --> <insert id="insertUser" parameterType="com.dy.entity.User"> <!-- oracle等不支持id自增长的,可根据其id生成策略,先获取id --> <selectKey resultType="int" order="BEFORE" keyProperty="id"> select seq_user_id.nextval as id from dual </selectKey> insert into user(id, name, password, age, deleteFlag) values(#{id}, #{name}, #{password}, #{age}, #{deleteFlag}) </insert>
//根据SelectKeyAnnotation信息,获取KeyGenerator
private KeyGenerator handleSelectKeyAnnotation(SelectKey selectKeyAnnotation, String baseStatementId, Class parameterTypeClass, LanguageDriver languageDriver) { String id = (new StringBuilder()).append(baseStatementId).append("!selectKey").toString(); //keyProperty Type Class resultTypeClass = selectKeyAnnotation.resultType(); //statementType StatementType statementType = selectKeyAnnotation.statementType(); String keyProperty = selectKeyAnnotation.keyProperty(); boolean executeBefore = selectKeyAnnotation.before(); boolean useCache = false; KeyGenerator keyGenerator = new NoKeyGenerator(); Integer fetchSize = null;//抓取大小 Integer timeout = null;//超时时间 boolean flushCache = false;//是否刷新缓存 String parameterMap = null; String resultMap = null; ResultSetType resultSetTypeEnum = null; SqlSource sqlSource = buildSqlSourceFromStrings(selectKeyAnnotation.statement(), parameterTypeClass, languageDriver); SqlCommandType sqlCommandType = SqlCommandType.SELECT; //根据@SelectKey信息,构造MappedStatement,并添加到configuration中mappedStatements Map中 assistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, false, keyGenerator, keyProperty, null, null, languageDriver); id = assistant.applyCurrentNamespace(id, false); org.apache.ibatis.mapping.MappedStatement keyStatement = configuration.getMappedStatement(id, false); SelectKeyGenerator answer = new SelectKeyGenerator(keyStatement, executeBefore); //将SelectKeyGenerator的命名空间id与KeyGenerator映射关系,添加到Configuration configuration.addKeyGenerator(id, answer); return answer; } }
//Configuration
public void addKeyGenerator(String id, KeyGenerator keyGenerator) { //StrictMap<String,KeyGenerator> key为KeyGenerator的nameSpace id keyGenerators.put(id, keyGenerator); }
现在回到
parseStatement(Method method)的ResultMap的处理
//解析method的@ResultMap
private String parseResultMap(Method method) { Class returnType = getReturnType(method); ConstructorArgs args = (ConstructorArgs)method.getAnnotation(org/apache/ibatis/annotations/ConstructorArgs); Results results = (Results)method.getAnnotation(org/apache/ibatis/annotations/Results); TypeDiscriminator typeDiscriminator = (TypeDiscriminator)method.getAnnotation(org/apache/ibatis/annotations/TypeDiscriminator); //方法返回结果唯一id String resultMapId = generateResultMapName(method); //委托给applyResultMap方法 applyResultMap(resultMapId, returnType, argsIf(args), resultsIf(results), typeDiscriminator); return resultMapId; } private void applyResultMap(String resultMapId, Class returnType, Arg args[], Result results[], TypeDiscriminator discriminator) { List resultMappings = new ArrayList(); applyConstructorArgs(args, returnType, resultMappings); applyResults(results, returnType, resultMappings); Discriminator disc = applyDiscriminator(resultMapId, returnType, discriminator); //构造ResultMap,并将ResultMap映射关系添加到configuration assistant.addResultMap(resultMapId, returnType, null, disc, resultMappings, null); createDiscriminatorResultMaps(resultMapId, returnType, discriminator); } //解析@Results注解信息,根据注解信息,构造,并添加到resultMappings private void applyResults(Result results[], Class resultType, List resultMappings) { Result arr$[] = results; int len$ = arr$.length; for(int i$ = 0; i$ < len$; i$++) { Result result = arr$[i$]; ArrayList flags = new ArrayList(); if(result.id()) flags.add(ResultFlag.ID); org.apache.ibatis.mapping.ResultMapping resultMapping = assistant.buildResultMapping(resultType, nullOrEmpty(result.property()), nullOrEmpty(result.column()), result.javaType() != Void.TYPE ? result.javaType() : null, result.jdbcType() != JdbcType.UNDEFINED ? result.jdbcType() : null, hasNestedSelect(result) ? nestedSelectId(result) : null, null, null, null, result.typeHandler() != org/apache/ibatis/type/UnknownTypeHandler ? result.typeHandler() : null, flags); resultMappings.add(resultMapping); } } //返回ReturnType的Class private Class getReturnType(Method method) { Class returnType = method.getReturnType(); if(Void.TYPE.equals(returnType)) { ResultType rt = (ResultType)method.getAnnotation(org/apache/ibatis/annotations/ResultType); if(rt != null) returnType = rt.value(); } else if(java/util/Collection.isAssignableFrom(returnType)) { Type returnTypeParameter = method.getGenericReturnType(); if(returnTypeParameter instanceof ParameterizedType) { Type actualTypeArguments[] = ((ParameterizedType)returnTypeParameter).getActualTypeArguments(); if(actualTypeArguments != null && actualTypeArguments.length == 1) { returnTypeParameter = actualTypeArguments[0]; if(returnTypeParameter instanceof Class) returnType = (Class)returnTypeParameter; else if(returnTypeParameter instanceof ParameterizedType) returnType = (Class)((ParameterizedType)returnTypeParameter).getRawType(); else if(returnTypeParameter instanceof GenericArrayType) { Class componentType = (Class)((GenericArrayType)returnTypeParameter).getGenericComponentType(); returnType = Array.newInstance(componentType, 0).getClass(); } } } } else if(method.isAnnotationPresent(org/apache/ibatis/annotations/MapKey) && java/util/Map.isAssignableFrom(returnType)) { Type returnTypeParameter = method.getGenericReturnType(); if(returnTypeParameter instanceof ParameterizedType) { Type actualTypeArguments[] = ((ParameterizedType)returnTypeParameter).getActualTypeArguments(); if(actualTypeArguments != null && actualTypeArguments.length == 2) { returnTypeParameter = actualTypeArguments[1]; if(returnTypeParameter instanceof Class) returnType = (Class)returnTypeParameter; else if(returnTypeParameter instanceof ParameterizedType) returnType = (Class)((ParameterizedType)returnTypeParameter).getRawType(); } } } return returnType; }
再来看
builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType, fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass, resultSetTypeEnum, flushCache, useCache, resultOrdered, keyGenerator, keyProperty, keyColumn, databaseId, langDriver);
//MapperBuilderAssistant
public class MapperBuilderAssistant extends BaseBuilder { //添加MappedStatement到Configuration public MappedStatement addMappedStatement(String id, SqlSource sqlSource, StatementType statementType, SqlCommandType sqlCommandType, Integer fetchSize, Integer timeout, String parameterMap, Class parameterType, String resultMap, Class resultType, ResultSetType resultSetType, boolean flushCache, boolean useCache, boolean resultOrdered, KeyGenerator keyGenerator, String keyProperty, String keyColumn, String databaseId, LanguageDriver lang) { if(unresolvedCacheRef) { //如果缓存参考没有解决,则抛出IncompleteElementException throw new IncompleteElementException("Cache-ref not yet resolved"); } else { id = applyCurrentNamespace(id, false); boolean isSelect = sqlCommandType == SqlCommandType.SELECT; org.apache.ibatis.mapping.MappedStatement.Builder statementBuilder = new org.apache.ibatis.mapping.MappedStatement.Builder(configuration, id, sqlSource, sqlCommandType); //配置MappedStatement.Builder属性 statementBuilder.resource(resource); statementBuilder.fetchSize(fetchSize); statementBuilder.statementType(statementType); statementBuilder.keyGenerator(keyGenerator); statementBuilder.keyProperty(keyProperty); statementBuilder.keyColumn(keyColumn); statementBuilder.databaseId(databaseId); statementBuilder.lang(lang); statementBuilder.resultOrdered(resultOrdered); setStatementTimeout(timeout, statementBuilder); //设置Statement的parameterMap setStatementParameterMap(parameterMap, parameterType, statementBuilder); //设置Statement的resultMap setStatementResultMap(resultMap, resultType, resultSetType, statementBuilder); //设置Statement缓存信息 setStatementCache(isSelect, flushCache, useCache, currentCache, statementBuilder); //构建MappedStatement MappedStatement statement = statementBuilder.build(); //添加MappedStatement到Configuration configuration.addMappedStatement(statement); return statement; } } }
//添加MappedStatement到Configuration
mappedStatements = new StrictMap("Mapped Statements collection");
public void addMappedStatement(MappedStatement ms) { StrictMap<String,MappedStatement>,key为MappedStatement的id mappedStatements.put(ms.getId(), ms); }
//MappedStatement
public final class MappedStatement { public static class Builder { public MappedStatement build() { if(!$assertionsDisabled && mappedStatement.configuration == null) throw new AssertionError(); if(!$assertionsDisabled && mappedStatement.id == null) throw new AssertionError(); if(!$assertionsDisabled && mappedStatement.sqlSource == null) throw new AssertionError(); if(!$assertionsDisabled && mappedStatement.lang == null) { throw new AssertionError(); } else { mappedStatement.resultMaps = Collections.unmodifiableList(mappedStatement.resultMaps); return mappedStatement; } } private MappedStatement mappedStatement; static final boolean $assertionsDisabled = !org/apache/ibatis/mapping/MappedStatement.desiredAssertionStatus(); } public BoundSql getBoundSql(Object parameterObject) { BoundSql boundSql = sqlSource.getBoundSql(parameterObject); List parameterMappings = boundSql.getParameterMappings(); if(parameterMappings == null || parameterMappings.size() <= 0) boundSql = new BoundSql(configuration, boundSql.getSql(), parameterMap.getParameterMappings(), parameterObject); Iterator i$ = boundSql.getParameterMappings().iterator(); do { if(!i$.hasNext()) break; ParameterMapping pm = (ParameterMapping)i$.next(); String rmId = pm.getResultMapId(); if(rmId != null) { ResultMap rm = configuration.getResultMap(rmId); if(rm != null) hasNestedResultMaps |= rm.hasNestedResultMaps(); } } while(true); return boundSql; } private String resource; private Configuration configuration; private String id; private Integer fetchSize; private Integer timeout; private StatementType statementType; private ResultSetType resultSetType; private SqlSource sqlSource; private Cache cache; private ParameterMap parameterMap; private List resultMaps; private boolean flushCacheRequired; private boolean useCache; private boolean resultOrdered; private SqlCommandType sqlCommandType; private KeyGenerator keyGenerator; private String keyProperties[]; private String keyColumns[]; private boolean hasNestedResultMaps; private String databaseId; private Log statementLog; private LanguageDriver lang; }
从上可以看出解析@SelectKey信息,跟@SelectKey节点的属性信息,构建keyStatement,
并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,如果无@SelectKey,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据method方法注解信息和KeyGenerator,构造MapperStatement,
添加到configuration的mappedStatements的Map中并添加在configuration的keyGenerators-Map中
//遍历configuration的IncompleteMethods集合,重新解析MethodResolver
parsePendingMethods();
private void parsePendingMethods() { Collection incompleteMethods = configuration.getIncompleteMethods(); synchronized(incompleteMethods) { for(Iterator iter = incompleteMethods.iterator(); iter.hasNext();) try { ((MethodResolver)iter.next()).resolve(); iter.remove(); } catch(IncompleteElementException e) { } } }
//MethodResolver
public class MethodResolver { public MethodResolver(MapperAnnotationBuilder annotationBuilder, Method method) { this.annotationBuilder = annotationBuilder; this.method = method; } public void resolve() { annotationBuilder.parseStatement(method); } private final MapperAnnotationBuilder annotationBuilder; private Method method; }
总结:
MapperInterface的解析,首先Configuration添加MapperInterface,实质上MapperRegistry注册到其HashMap<Class,MapperProxyFactory>中,MapperProxyFactory是MapperInterface的代理,生成MapperInterface的MapperProxy代理实例,MapperProxy中利用Map<Method,MapperMethod>,实现二级缓存,MapperInterface执行DML实际上是,通过MapperProxy反射,调用MapperMethod的方法;加载mapInterface,package路径下的Mapper xml文件,如果未加载,则加载解析;@CacheNamespace的解析,实际上是,获取@CacheNamespace的type对应的Class,@CacheNamespace的eviction对应的缓存算法Class,以及刷新间隔,读写属性,构造CacheBuilder,并添加的configuration的二级缓存StrictMap<nameSpace,CacheBuilder>;@CacheNamespaceRef的解析,实际上,将cache和cache-ref的命名空间的映射关系添加到configuration中,并从configuration的获取cacheRefNamespace对应的Cache,如果cache-ref的cacheRefNamespace对应的缓存,
不存在,则抛出IncompleteElementException;解析@SelectKey信息,跟@SelectKey节点的属性信息,构建keyStatement,并添加configuration的mappedStatements的Map中,Map<id-nameSpace,MappedStatement>,根据keyStatement,构建SelectKeyGenerator,如果无@SelectKey,则根据statement节点的useGeneratedKeys属性和全局配置信息isUseGeneratedKeys与SqlCommandType.INSERT产生对应的KeyGenerator;根据method方法注解信息和KeyGenerator,构造MapperStatement,添加到configuration的mappedStatements的Map中并添加在configuration的keyGenerators-Map中。
//ParameterMap
public class ParameterMap { public static class Builder { public ParameterMap build() { //获取不可修改的parameterMappings parameterMap.parameterMappings = Collections.unmodifiableList(parameterMap.parameterMappings); return parameterMap; } } private String id; private Class type; private List parameterMappings; }
//ResultMap
public class ResultMap { private String id; private Class type; private List resultMappings; private List idResultMappings; private List constructorResultMappings; private List propertyResultMappings; private Set mappedColumns; private Discriminator discriminator; private boolean hasNestedResultMaps; private boolean hasNestedQueries; private Boolean autoMapping; public static class Builder { public ResultMap build() { if(resultMap.id == null) throw new IllegalArgumentException("ResultMaps must have an id"); resultMap.mappedColumns = new HashSet(); resultMap.idResultMappings = new ArrayList(); resultMap.constructorResultMappings = new ArrayList(); resultMap.propertyResultMappings = new ArrayList(); Iterator i$ = resultMap.resultMappings.iterator(); do { if(!i$.hasNext()) break; ResultMapping resultMapping = (ResultMapping)i$.next(); resultMap.hasNestedQueries = resultMap.hasNestedQueries || resultMapping.getNestedQueryId() != null; resultMap.hasNestedResultMaps = resultMap.hasNestedResultMaps || resultMapping.getNestedResultMapId() != null; String column = resultMapping.getColumn(); if(column != null) resultMap.mappedColumns.add(column.toUpperCase(Locale.ENGLISH)); else if(resultMapping.isCompositeResult()) { Iterator i$ = resultMapping.getComposites().iterator(); do { if(!i$.hasNext()) break; ResultMapping compositeResultMapping = (ResultMapping)i$.next(); String compositeColumn = compositeResultMapping.getColumn(); if(compositeColumn != null) resultMap.mappedColumns.add(compositeColumn.toUpperCase(Locale.ENGLISH)); } while(true); } if(resultMapping.getFlags().contains(ResultFlag.CONSTRUCTOR)) resultMap.constructorResultMappings.add(resultMapping); else resultMap.propertyResultMappings.add(resultMapping); if(resultMapping.getFlags().contains(ResultFlag.ID)) resultMap.idResultMappings.add(resultMapping); } while(true); if(resultMap.idResultMappings.isEmpty()) resultMap.idResultMappings.addAll(resultMap.resultMappings); resultMap.resultMappings = Collections.unmodifiableList(resultMap.resultMappings); resultMap.idResultMappings = Collections.unmodifiableList(resultMap.idResultMappings); resultMap.constructorResultMappings = Collections.unmodifiableList(resultMap.constructorResultMappings); resultMap.propertyResultMappings = Collections.unmodifiableList(resultMap.propertyResultMappings); resultMap.mappedColumns = Collections.unmodifiableSet(resultMap.mappedColumns); return resultMap; } } }
//BoundSql
public class BoundSql { private String sql; private List parameterMappings; private Object parameterObject; private Map additionalParameters; private MetaObject metaParameters; public BoundSql(Configuration configuration, String sql, List parameterMappings, Object parameterObject) { this.sql = sql; this.parameterMappings = parameterMappings; this.parameterObject = parameterObject; additionalParameters = new HashMap(); metaParameters = configuration.newMetaObject(additionalParameters); } }
//MetaObject
public class MetaObject { private Object originalObject; private ObjectWrapper objectWrapper; private ObjectFactory objectFactory; private ObjectWrapperFactory objectWrapperFactory; //设置MetaObject的name属性的值为value public void setValue(String name, Object value) { PropertyTokenizer prop = new PropertyTokenizer(name); if(prop.hasNext()) { MetaObject metaValue = metaObjectForProperty(prop.getIndexedName()); if(metaValue == SystemMetaObject.NULL_META_OBJECT) { if(value == null && prop.getChildren() != null) return; metaValue = objectWrapper.instantiatePropertyValue(name, prop, objectFactory); } metaValue.setValue(prop.getChildren(), value); } else { objectWrapper.set(prop, value); } } }
//SqlCommandType
public final class SqlCommandType extends Enum { public static final SqlCommandType UNKNOWN; public static final SqlCommandType INSERT; public static final SqlCommandType UPDATE; public static final SqlCommandType DELETE; public static final SqlCommandType SELECT; private static final SqlCommandType $VALUES[]; static { UNKNOWN = new SqlCommandType("UNKNOWN", 0); INSERT = new SqlCommandType("INSERT", 1); UPDATE = new SqlCommandType("UPDATE", 2); DELETE = new SqlCommandType("DELETE", 3); SELECT = new SqlCommandType("SELECT", 4); $VALUES = (new SqlCommandType[] { UNKNOWN, INSERT, UPDATE, DELETE, SELECT }); } }
//StatementTypes
public final class StatementType extends Enum { public static final StatementType STATEMENT; public static final StatementType PREPARED; public static final StatementType CALLABLE; private static final StatementType $VALUES[]; static { STATEMENT = new StatementType("STATEMENT", 0); PREPARED = new StatementType("PREPARED", 1); CALLABLE = new StatementType("CALLABLE", 2); $VALUES = (new StatementType[] { STATEMENT, PREPARED, CALLABLE }); } }
//ResultSetType
public final class ResultSetType extends Enum { public static final ResultSetType FORWARD_ONLY; public static final ResultSetType SCROLL_INSENSITIVE; public static final ResultSetType SCROLL_SENSITIVE; private int value; private static final ResultSetType $VALUES[]; static { FORWARD_ONLY = new ResultSetType("FORWARD_ONLY", 0, 1003); SCROLL_INSENSITIVE = new ResultSetType("SCROLL_INSENSITIVE", 1, 1004); SCROLL_SENSITIVE = new ResultSetType("SCROLL_SENSITIVE", 2, 1005); $VALUES = (new ResultSetType[] { FORWARD_ONLY, SCROLL_INSENSITIVE, SCROLL_SENSITIVE }); } }
发表评论
-
Mybatis缓存实现
2016-12-07 10:36 983SqlSessionFactory初始化:http://don ... -
DefaultSqlSession第三讲-事务提交,回滚,关闭SqlSession,清除缓存
2016-11-20 11:07 5715上面两篇讲过query和update及flushStateme ... -
DefaultSqlSession第二讲-更新,刷新Statement
2016-11-20 11:06 635上一篇文章中,我们讲到DefaultSqlSession的查询 ... -
DefaultSqlSession第一讲query解析
2016-11-20 11:06 1632上一篇文章:我们说过DefaultSqlSession,Def ... -
Mybatis的SqlSession解析
2016-11-20 11:02 2566在前文中,Mybatis使用教程中,有下面一段代码: Sql ... -
Mybatis的Reflector解析
2016-11-18 12:53 2166Mybatis的MetaObject解析:http://don ... -
Mybatis的MetaObject解析
2016-11-18 11:40 9585SqlSessionFactory初始化:http://don ... -
mybatis 动态标签语句的解析(BoundSql)
2016-10-30 09:48 5767SqlSessionFactory初始化:http://don ... -
Mybatis的Environment解析详解
2016-10-29 18:28 1998SqlSessionFactory初始化:http://don ... -
Mybatis加载解析Mapper(xml)文件第二讲
2016-10-25 21:30 4807SqlSessionFactory初始化:http://don ... -
Mybatis加载解析Mapper(xml)文件第一讲
2016-10-25 16:51 6202SqlSessionFactory初始化:http://don ... -
SqlSessionFactory初始化
2016-10-20 15:38 2461mybatis 使用教程:http://donald-drap ... -
mybatis 使用教程
2016-10-14 09:03 914Myeclispe下mybatis generator的使 ... -
Spring+Mybatis多数据源的实现
2016-09-21 18:15 3097浅谈Spring事务隔离级别:http://www.cnblo ... -
mybaitis CDATA 防止字符被解析
2016-08-17 18:45 727在使用mybatis 时我们sql是写在xml 映射文件中,如 ... -
Myeclispe下mybatis generator的使用
2016-07-05 18:05 1380准备:下载附件包解压到myeclispe的dropins文件夹 ...
相关推荐
3. **配置Mybatis**:在项目的Mybatis配置文件(mybatis-config.xml)中,需要引入刚刚生成的mapper.xml文件,使得Mybatis能够找到并解析它们。 4. **编写mapper接口**:虽然逆向工具会生成基础的mapper接口和实现...
2. **Java实体类(Entity Class)**:在MyBatis中,实体类是Java对象,它们代表数据库中的表。MBG可以根据数据库表的字段自动生成这些类,每个字段对应类的一个属性,方便进行对象-关系映射。 3. **Mapper接口...
本文将详细介绍如何将Spring、MyBatis、通用Mapper与分页插件进行集成。 首先,我们需要理解每个组件的作用: 1. Spring:这是一个全面的开源应用框架,提供依赖注入(DI)、面向切面编程(AOP)以及各种企业级...
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperFactoryBean"> <property name="mapperInterface" value="com.example.mapper.UserMapper"/> ``` 6. 使用MapperScannerConfigurer: 当项目...
为了提高开发效率,MyBatis提供了一种自动生成Mapper工具,可以自动化生成实体类、Mapper接口以及对应的XML文件,极大地减少了开发者的工作量。 首先,我们需要理解MyBatis的Mapper接口。Mapper接口是业务逻辑与SQL...
MyBatis Generator是MyBatis框架的一个插件,通过解析数据库表结构,可以自动生成Java源代码,包括实体类、Mapper接口和XML映射文件。这些生成的代码可以帮助开发者快速搭建基于MyBatis的数据访问层,避免手动编写...
本文将详细解析"mybatis联表查询mapper.xml"这一主题,包括如何在Mapper XML文件中实现主表与副表的一对多关联查询,以及涉及的实体类和DAO层的设计。 首先,我们要理解MyBatis中的Mapper接口和Mapper XML文件的...
Mybatis mapper接口动态代理开发步骤解析 Mybatis 是一个流行的Java持久层框架,它提供了一个灵活的方式来访问数据库。其中,Mapper 接口动态代理是 Mybatis 的一个重要特性,它允许开发者使用接口来定义数据库操作...
Mybatis Generator是一个代码生成工具,它可以自动生成实体类、Mapper接口和Mapper XML文件,大大减轻了开发工作量。使用步骤如下: 1. **配置GeneratorConfig.xml**:在该文件中设置数据库连接信息、生成的代码...
首先,当我们使用`SqlSession.getMapper()`方法来获取一个Mapper接口的实例时,例如`BookMapper bookMapper = SqlSession().getMapper(BookMapper.class)`,MyBatis是如何找到对应的mapper.xml文件并绑定接口方法的...
例如,当用户在EasyUI表格中触发操作时,可以通过jQuery发送AJAX请求到Spring MVC的Controller,Controller根据请求调用MyBatis的Mapper接口执行数据库操作,然后将处理结果转换成JSON格式返回给前端。前端接收到...
逆向工程(Reverse Engineering)在MyBatis中的应用主要是指自动生成MyBatis的Mapper接口、Mapper XML配置文件以及对应的实体类,极大地简化了开发过程,减少了手动编写这些重复代码的工作量。 MyBatis逆向工程的...
mybatis也能方向生成代码,能方向生成实体类(po)、mapper接口和Mapper接口映射文件,能减少我们代码的工作量。详细步骤如下 1、下载mybatis生成架包工具MyBatis_Generator_1.3.1.zip,解压架包把features、plugins...
"Mybatis自动生成实体类以及Mapper文件"是Mybatis的一个实用特性,能够显著提高开发效率,减少手动创建代码的工作量。 首先,我们需要理解Mybatis Generator(MBG)的角色。MBG是一个代码生成工具,它可以基于...
public class MybatisRedisCache implements Cache { // 读写锁 private final ReadWriteLock readWriteLock = new ReentrantReadWriteLock(true); // 使用springboot自动注入RedisTemplate @Autowired ...
<bean id="userMapper" class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.mapper"/> <!-- 也可以指定Mapper接口的接口类 --> <!-- ...
在这个项目中,开发者会学习到如何配置Mybatis的SqlSessionFactory,创建Mapper接口和XML配置文件,以及如何在Servlet中执行SQL查询并利用PageInfo对象来封装分页信息。 【标签】 "Mybatis" 指的是Mybatis框架,它...
数据源通常是连接MySQL数据库的配置,SqlSessionFactory用于创建SqlSession,Mapper接口则对应MyBatis的XML配置文件中的SQL语句。 ```xml <!-- 数据源配置 --> <bean id="dataSource" class="org.spring...
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.springmybatis.Mapper"/> ``` `basePackage`属性指定了Mapper接口所在的包路径,系统会在此路径下...
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.example.demo.mapper" /> ``` **3. 配置Mybatis** Mybatis的核心配置文件`mybatis-config.xml`...