日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

MyBatis启动:MapperStatement创建

發(fā)布時(shí)間:2023/11/27 生活经验 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 MyBatis启动:MapperStatement创建 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

參考:http://blog.csdn.net/ashan_li/article/details/50351080

MappedStatement說(shuō)明

一個(gè)MappedStatement對(duì)象對(duì)應(yīng)Mapper配置文件中的一個(gè)select/update/insert/delete節(jié)點(diǎn),主要描述的是一條SQL語(yǔ)句。其屬性有

//節(jié)點(diǎn)中的id屬性加要命名空間  
private String id;  
//直接從節(jié)點(diǎn)屬性中取  
private Integer fetchSize;  
//直接從節(jié)點(diǎn)屬性中取  
private Integer timeout;  
private StatementType statementType;  
private ResultSetType resultSetType;  
//對(duì)應(yīng)一條SQL語(yǔ)句  
private SqlSource sqlSource;  //每條語(yǔ)句都對(duì)就一個(gè)緩存,如果有的話。  
private Cache cache;  
//這個(gè)已經(jīng)過(guò)時(shí)了  
private ParameterMap parameterMap;  
private List<ResultMap> resultMaps;  
private boolean flushCacheRequired;  
private boolean useCache;  
private boolean resultOrdered;  
//SQL的類型,select/update/insert/detete  
private SqlCommandType sqlCommandType;  
private KeyGenerator keyGenerator;  
private String[] keyProperties;  
private String[] keyColumns;  //是否有內(nèi)映射  
private boolean hasNestedResultMaps;  
private String databaseId;  
private Log statementLog;  
private LanguageDriver lang;  
private String[] resultSets; 

  

Mapper是接口,用來(lái)聲明持久層的方法,而Mapper配置對(duì)應(yīng)的XML,決定了方法的執(zhí)行的內(nèi)容,決定持久層方法的行為。在MyBatis啟 動(dòng)時(shí),會(huì)解析這些包含SQL的XML文件,并將其包裝成為MapperStatement對(duì)象,并將MapperStatement注冊(cè)到全局的 configuration對(duì)象上,接下來(lái)就深入的了解代碼的實(shí)現(xiàn)。

?

private void mapperElement(XNode parent) throws Exception {  if (parent != null) {  for (XNode child : parent.getChildren()) {  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");  if (resource != null && url == null && mapperClass == null) {  ErrorContext.instance().resource(resource);  InputStream inputStream = Resources.getResourceAsStream(resource);  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);  XMLMapperBuilder mapperParser = new XMLMapperBuilder(inputStream, configuration, url, configuration.getSqlFragments());  mapperParser.parse();  } else if (resource == null && url == null && mapperClass != null) {  Class<?> mapperInterface = Resources.classForName(mapperClass);  configuration.addMapper(mapperInterface);  } else {  throw new BuilderException("A mapper element may only specify a url, resource or class, but not more than one.");  }  }  }  }  }  

  

從 源碼中就可以看出,配置Mapper時(shí),可以配置package熟悉,注冊(cè)包下所有的接口。還可以從資源中比如硬盤上,網(wǎng)絡(luò)中,去加載XML文件。注冊(cè)過(guò) 程是通過(guò)注冊(cè)器MapperRegistry來(lái)完成的。注冊(cè)的容器是一個(gè)map,Map<Class<?>, MapperProxyFactory<?>> knownMappers = new HashMap<Class<?>, MapperProxyFactory<?>>();。

?

key是mapper的接口完整類名,value是mapper的代理工廠。注冊(cè)完成后,還要做解析XML文件操作。

?

public <T> void addMapper(Class<T> type) {  if (type.isInterface()) {  if (hasMapper(type)) {  throw new BindingException("Type " + type + " is already known to the MapperRegistry.");  }  boolean loadCompleted = false;  try {  knownMappers.put(type, new MapperProxyFactory<T>(type));  // It's important that the type is added before the parser is run  // otherwise the binding may automatically be attempted by the  // mapper parser. If the type is already known, it won't try.  MapperAnnotationBuilder parser = new MapperAnnotationBuilder(config, type);  parser.parse();  loadCompleted = true;  } finally {  if (!loadCompleted) {  knownMappers.remove(type);  }  }  }  
}

  

??

下面 是解析的代碼

?

public void parse() {  String resource = type.toString();  if (!configuration.isResourceLoaded(resource)) {  loadXmlResource();  configuration.addLoadedResource(resource);  assistant.setCurrentNamespace(type.getName());  parseCache();  parseCacheRef();  Method[] methods = type.getMethods();  for (Method method : methods) {  try {  parseStatement(method);  } catch (IncompleteElementException e) {  configuration.addIncompleteMethod(new MethodResolver(this, method));  }  }  }  parsePendingMethods();  }  

  

private void loadXmlResource() {  // Spring may not know the real resource name so we check a flag  // to prevent loading again a resource twice  // this flag is set at XMLMapperBuilder#bindMapperForNamespace  if (!configuration.isResourceLoaded("namespace:" + type.getName())) {  String xmlResource = type.getName().replace('.', '/') + ".xml";  InputStream inputStream = null;  try {  inputStream = Resources.getResourceAsStream(type.getClassLoader(), xmlResource);  } catch (IOException e) {  // ignore, resource is not required  }  if (inputStream != null) {  XMLMapperBuilder xmlParser = new XMLMapperBuilder(inputStream, assistant.getConfiguration(), xmlResource, configuration.getSqlFragments(), type.getName());  xmlParser.parse();  }  }  
}  

  

?

MyBatis通過(guò)替換mapper完整類名中的“.”,替換成為“/”,然后加上后綴“.xml”,拼成XML資源路徑,然后判斷是否已加載過(guò)XML,沒(méi)有的話加載XML文件,然后使用xmlMapperBuilder建造者解析XML中的元素。


public void parse() {  if (!configuration.isResourceLoaded(resource)) {  configurationElement(parser.evalNode("/mapper"));  configuration.addLoadedResource(resource);  bindMapperForNamespace();  }  parsePendingResultMaps();  parsePendingChacheRefs();  parsePendingStatements();  
}  

  

resource是創(chuàng)建建造者的構(gòu)造參數(shù),type.getClass(),就是mapper的類型。判斷然后還沒(méi)有加載mapper,就開始解析XML文件中的mapper節(jié)點(diǎn)。

?

private void configurationElement(XNode context) {  try {  String namespace = context.getStringAttribute("namespace");  if (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);  }  }  

  

?

解 析時(shí),先設(shè)置命名空間。然后解析cache-ref元素,可以使用其他命名空間的的緩存。在configuration對(duì)象上有一個(gè) cacheRefMap用來(lái)維護(hù)引用緩存的關(guān)系。并且引用其他命名空間的引用指向助手類的currCache屬性上。如果被指向的命名空間還未加載,則拋 出異常,并且往configuration對(duì)象上添加未處理的緩存引用chcheRef。

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);  }  }  
}  

  

?

解析緩存元素,可以使用type屬性配置自定義的緩存,否則使用默認(rèn) 的PERPETUAL。然后用別名注冊(cè)器注冊(cè)緩存類。接下來(lái)注冊(cè)緩存的回收算法,緩存大小,過(guò)期時(shí)間,是否只讀等屬性。然后由助手類通過(guò)反射創(chuàng)建一個(gè)具體 的Cache對(duì)象。然后注冊(cè)到configuration全局對(duì)象上。

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);  Properties props = context.getChildrenAsProperties();  builderAssistant.useNewCache(typeClass, evictionClass, flushInterval, size, readWrite, props);  }  
}  

  

?

下一步是解析parameterMap,新版中已經(jīng)不推薦配置這個(gè)屬性了,屬于老方法。

參數(shù)Map映射已經(jīng)被淘汰,但是結(jié)果集映射還很有用。接下來(lái)就是解析 resultMap。解析resultMap的元素比較多,解析完成后,還會(huì)根據(jù)解析到的映射關(guān)系創(chuàng)建一個(gè)結(jié)果處理器對(duì)象 resultMapResolver,后面對(duì)數(shù)據(jù)庫(kù)操作時(shí),用來(lái)處理列和屬性的類型轉(zhuǎn)換。

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 {  ArrayList<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;  }  
}  

  

?

解析來(lái)繼續(xù)解析SQL片段,用來(lái)復(fù)用的SQL。助手類會(huì)將SQL片段的ID前面加上當(dāng)前命名空間和一個(gè)點(diǎn),用來(lái)和其他命名空間區(qū)別開。然后將SQL片段加載到configuration全局對(duì)象的sqlFragments對(duì)象上保存。

?

?

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);  }  
}  

  

?

最后是重頭戲,解析增刪改查節(jié)點(diǎn),創(chuàng)建Statement對(duì)象。同樣是通過(guò)建造者模式來(lái)創(chuàng)建語(yǔ)句對(duì)象,建造者的構(gòu)造參數(shù)包括全局配置信息,當(dāng)前命名空間助手,XML配置信息和數(shù)據(jù)庫(kù)ID。

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);  }  }  
}  

  

?

首先還是解析XML文件的各個(gè)屬性,然后處理<include>和<selectKey>片段。根據(jù)include標(biāo)簽中的refid到全局配置中取對(duì)應(yīng)的SQL片段。根據(jù)selectKey的配置信息,創(chuàng)建一個(gè)MapperStatement,并且添加到全局配置中,然后移除selectKey節(jié)點(diǎn)。

public void parseStatementNode() {  String id = context.getStringAttribute("id");  String databaseId = context.getStringAttribute("databaseId");  if (!databaseIdMatchesCurrent(id, databaseId, this.requiredDatabaseId)) return;  Integer fetchSize = context.getIntAttribute("fetchSize");  Integer timeout = context.getIntAttribute("timeout");  String parameterMap = context.getStringAttribute("parameterMap");  String parameterType = context.getStringAttribute("parameterType");  Class<?> parameterTypeClass = resolveClass(parameterType);  String resultMap = context.getStringAttribute("resultMap");  String resultType = context.getStringAttribute("resultType");  String lang = context.getStringAttribute("lang");  LanguageDriver langDriver = getLanguageDriver(lang);  Class<?> resultTypeClass = resolveClass(resultType);  String resultSetType = context.getStringAttribute("resultSetType");  StatementType statementType = StatementType.valueOf(context.getStringAttribute("statementType", StatementType.PREPARED.toString()));  ResultSetType resultSetTypeEnum = resolveResultSetType(resultSetType);  String nodeName = context.getNode().getNodeName();  SqlCommandType sqlCommandType = SqlCommandType.valueOf(nodeName.toUpperCase(Locale.ENGLISH));  boolean isSelect = sqlCommandType == SqlCommandType.SELECT;  boolean flushCache = context.getBooleanAttribute("flushCache", !isSelect);  boolean useCache = context.getBooleanAttribute("useCache", isSelect);  boolean resultOrdered = context.getBooleanAttribute("resultOrdered", false);  // Include Fragments before parsing  XMLIncludeTransformer includeParser = new XMLIncludeTransformer(configuration, builderAssistant);  includeParser.applyIncludes(context.getNode());  // Parse selectKey after includes and remove them.  processSelectKeyNodes(id, parameterTypeClass, langDriver);  // Parse the SQL (pre: <selectKey> and <include> were parsed and removed)  SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);  String resultSets = context.getStringAttribute("resultSets");  String keyProperty = context.getStringAttribute("keyProperty");  String keyColumn = context.getStringAttribute("keyColumn");  KeyGenerator keyGenerator;  String keyStatementId = id + SelectKeyGenerator.SELECT_KEY_SUFFIX;  keyStatementId = builderAssistant.applyCurrentNamespace(keyStatementId, true);  if (configuration.hasKeyGenerator(keyStatementId)) {  keyGenerator = configuration.getKeyGenerator(keyStatementId);  } else {  keyGenerator = context.getBooleanAttribute("useGeneratedKeys",  configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType))  ? new Jdbc3KeyGenerator() : new NoKeyGenerator();  }  builderAssistant.addMappedStatement(id, sqlSource, statementType, sqlCommandType,  fetchSize, timeout, parameterMap, parameterTypeClass, resultMap, resultTypeClass,  resultSetTypeEnum, flushCache, useCache, resultOrdered,   keyGenerator, keyProperty, keyColumn, databaseId, langDriver, resultSets);  
}  

  

?

接下來(lái)的操作,也是根據(jù)配置的屬性,然后通過(guò)建造者創(chuàng)建mappedStatement對(duì)象。并添加到configuration全局對(duì)象上。

轉(zhuǎn)載于:https://www.cnblogs.com/qlqwjy/p/7866982.html

總結(jié)

以上是生活随笔為你收集整理的MyBatis启动:MapperStatement创建的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。