MyBatis Start: mapperstatement Create

Source: Internet
Author: User

Reference: http://blog.csdn.net/ashan_li/article/details/50351080

Mappedstatement description

A Mappedstatement object corresponds to a Select/update/insert/delete node in the mapper configuration file, primarily describing an SQL statement. Its properties are

The id attribute in the node is added to the namespace  private String ID;  Take the private Integer fetchsize directly from the node attribute  ;  Take the private Integer timeout directly from the node attribute  ;  Private StatementType StatementType;  Private ResultsetType ResultsetType;  Corresponds to a SQL statement  private sqlsource Sqlsource;    Each statement is on a cache, if any.  private cache cache;  This is out of date  private Parametermap parametermap;  Private list<resultmap> resultmaps;  Private Boolean flushcacherequired;  Private Boolean UseCache;  Private Boolean resultordered;  Type of SQL, Select/update/insert/detete  private sqlcommandtype sqlcommandtype;  Private Keygenerator Keygenerator;  Private string[] keyproperties;  Private string[] KeyColumns;    Whether there is a  private Boolean hasnestedresultmaps inside the map;  Private String databaseId;  Private Log Statementlog;  Private Languagedriver Lang;  

  

Mapper is an interface that declares the method of the persistence layer, while the corresponding XML of the mapper configuration determines the content of the execution of the method and determines the behavior of the persistence layer method. When MyBatis is started, these XML files containing SQL are parsed and wrapped into mapperstatement objects, and the mapperstatement is registered to the global configuration object, followed by an in-depth understanding of the implementation of the Code.

private void Mapperelement (xnode parent) throws Exception {if (parent! = null) {for (XNode child:parent.ge Tchildren ()) {if ("package". Equals (Child.getname ())) {String mapperpackage = child.getstringattribut            E ("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 (). Resourc              E (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<?> Mapperint              Erface = Resources.classforname (Mapperclass);            Configuration.addmapper (Mapperinterface);  } else {throw new Builderexception ("A mapper element may be only specify a URL, resource or class, and not more   than one. ");}}}}

  

As you can see from the source code, when configuring mapper, you can configure the package to be familiar and register all of the interfaces. You can also load an XML file from a resource, such as a hard disk, on a network. The registration process is done through the Registrar mapperregistry. The registered container is a map,map<class<?> mapperproxyfactory<?>> knownmappers = new Hashmap<class<?> Mapperproxyfactory<?>> ();.

Key is the full class name of the Mapper interface, and value is the Proxy factory for mapper. After the registration is completed, the parse XML file operation is also done.

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's the type is added before the parser was run        //Otherwise the binding may automatically be attemp Ted 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);        }    }}  }

  

The following is the parsed code

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 know the real resource name so we check a flag    //To prevent LO Ading again a resource twice    //This flag are set at Xmlmapperbuilder#bindmapperfornamespace    if (!configuration.is Resourceloaded ("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 X Mlmapperbuilder (InputStream, Assistant.getconfiguration (), Xmlresource, configuration.getsqlfragments (), Type.getname ());        Xmlparser.parse ();}}}    

  

MyBatis replaces the "." In the full class name of the Mapper, replacing it with "/", and then adding the suffix ". xml" to the XML resource path, and then determining if the XML has been loaded, without loading the XML file, The elements in the XML are then parsed using the Xmlmapperbuilder builder.


public void Parse () {    if (!configuration.isresourceloaded (Resource)) {      ConfigurationElement (parser.evalnode ("/mapper"));      Configuration.addloadedresource (Resource);      Bindmapperfornamespace ();    }      Parsependingresultmaps ();    Parsependingchacherefs ();    Parsependingstatements ();  }  

  

Resource is the construction parameter that creates the builder, Type.getclass (), which is the type of mapper. After judging and then not loading the mapper, start parsing the mapper node in the XML file.

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

  

When parsing, set the namespace first. Then parse the Cache-ref element, which can use a cache of other namespaces. There is a relationship on the configuration object that Cacherefmap uses to maintain the reference cache. and references to other namespaces refer to the Currcache property of the helper class. If the namespace that is pointed to is not yet loaded, an exception is thrown, and an unhandled cache reference Chcheref is added to the configuration object.

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

  

Parse the cache element, you can use the Type property to configure the custom cache, otherwise use the default perpetual. Then register the cache class with the alias registrar. Next registers the cache's recycle algorithm, cache size, expiration time, whether read-only properties. The helper class then creates a specific cache object from the reflection. Then register to the configuration global object.

private void Cacheelement (XNode context) throws Exception {    if (context! = null) {      String type = context.getstring Attribute ("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);    }  }  

  

The next step is to parse Parametermap, the new version has not been recommended to configure this property, belongs to the old method.

The

parameter map mappings have been deprecated, but result set mappings are also useful. The next step is to parse resultmap. Parsing Resultmap has many elements, and after parsing is completed, a result processor object Resultmapresolver is created based on the mapping relationship resolved to handle the type conversion of columns and properties when the database is manipulated.

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", result    Mapnode.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 (re      Sultchild, 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, Discriminat    Or, resultmappings, automapping);    try {return resultmapresolver.resolve ();      } catch (Incompleteelementexception e) {configuration.addincompleteresultmap (resultmapresolver);    Throw e;   }  }

  

Parse to continue parsing SQL fragments, which are used to reuse SQL. The helper class will precede the ID of the SQL fragment with the current namespace and a point to distinguish it from other namespaces. The SQL fragment is then loaded onto the Sqlfragments object of the configuration global object to save.

private void Sqlelement (list<xnode> List, String Requireddatabaseid) throws Exception {for    (xnode Context:lis T) {      String databaseId = Context.getstringattribute ("DatabaseId");      String id = context.getstringattribute ("id");      id = builderassistant.applycurrentnamespace (ID, false);      if (Databaseidmatchescurrent (ID, databaseId, Requireddatabaseid)) Sqlfragments.put (ID, context);    }  }  

  

The last is the play, parse and delete to change the node, create statement object. The same is done by creating a statement object from the builder's schema, which includes the global configuration information, the current namespace helper, the XML configuration information, and the database 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);}}}    

  

The first is to parse the various attributes of the XML file and then process the <include> and <selectKey> fragments. Take the corresponding SQL fragment from the refID in the include tag to the global configuration. Based on the configuration information for Selectkey, create a mapperstatement, add it to the global configuration, and then remove the Selectkey node.

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, Buil    Derassistant);      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, parame Termap, Parametertypeclass, Resultmap, ResULttypeclass, Resultsettypeenum, Flushcache, UseCache, resultordered, Keygenerator, Keyproperty, KeyColumn,  DatabaseId, Langdriver, resultsets);   }

  

The next action is also based on the configured properties, and then the Mappedstatement object is created by the builder. And added to the configuration global object.

MyBatis Start: mapperstatement Create

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.