mybatis的解析和运行原理1

来源:互联网 发布:php图书管理系统 编辑:程序博客网 时间:2024/05/20 05:54

         如果只是学会mybatis的使用,那么在之前的博客中对mybatis一些基本的使用已经做了比较详细的说明了。但是在开发中,对于很多东西我们需要知道原理,才能对源码进行修改,写出更好的代码,对mybatis理解的更加深入,做到知其然并知其所以然。之前的博客:http://blog.csdn.net/j903829182/article/details/73382280

       接下来是对mybatis的底层设计和实现原理做一些研究。mybatis的运行分为两部分,第一部分是读取配置文件缓存到Configuration对象,用以创建SqlSessionFactory,第二部分是SqlSession的执行过程。相对而言,SqlSessionFactory的创建比较容易理解,而SqlSession的执行过程就不是那么简单了,它将包括许多辅助的技术,我们先讨论反射技术和动态代理技术,这是揭示mybatis底层架构的基础。

      当我们掌握了mybatis的运行原理以后,我们就可以知道mybatis是怎么运行的,这是后面学习插件技术的基础。

一,涉及的技术难点简介

         我们知道Mapper仅仅是一个接口,而不是包含逻辑的实现类,一个接口是没办法执行的,那么它是怎么运行的呢?其实很显然Mapper产生了代理类,这个代理类是Mybatis为我们创建的,为此先学习下代理。
      首先,代理有一个代理模式。所谓的代理模式就是在原有的服务上多加一个占位,通过这个占位去控制服务的访问。一般而言,动态代理分为两种,一种是基于JDK反射机制提供的代理,另外一种是CGLIB代理。在JKD提供的代理,我们必须要提供接口,而CGLIB则不需要提供接口,在mybatis里面两种动态技术都已经使用了。在学习之前先学习下反射技术。
1,反射技术
      在java中反射在很多地方都有用到,下面来实现一个简单反射的例子。

package com.jack.reflect;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;/** * create by jack 2017/12/18 */public class ReflectService {    /**     * 服务方法     * @param name     */    public void sayHello(String name){        System.out.println("hello , "+name);    }    public static void main(String[] args) {        try {            //通过反射创建ReflectService对象            Object service = Class.forName(ReflectService.class.getName()).newInstance();            //获取服务方法-sayHello            Method method = service.getClass().getMethod("sayHello",String.class);            //反射调用方法            method.invoke(service, "jack");            System.out.println(service.getClass());        } catch (InstantiationException e) {            e.printStackTrace();        } catch (IllegalAccessException e) {            e.printStackTrace();        } catch (ClassNotFoundException e) {            e.printStackTrace();        } catch (NoSuchMethodException e) {            e.printStackTrace();        } catch (InvocationTargetException e) {            e.printStackTrace();        }    }}

         上面的代码通过反射技术去创建ReflectService对象,获取方法后通过反射调用。

          反射调用的最大好处是配置性大大提高了,就如同spring ioc容器一样,我们可以给很多配置设置参数,使得java应用程序能够顺利运行起来,大大提高了java的灵活性和可配置性,降低了模块之间的耦合。


2,JDK动态代理

       JDK的动态代理,是由JDK的java.lang.reflect.*包提供支持的,我们需要完成下面两步:

1)编写服务的类和接口,这个是真正的服务提供者,在JDK代理中接口是必须的。

2)编写代理类,提供邦定和代理方法

       JDK的代理最大的缺点是需要提供接口,而mybatis的Mapper就是一个接口,它采用的就是JDK的动态代理。下面先给出一个服务接口:

package com.jack.service;/** * create by jack 2017/12/18 */public interface HelloService {    public void sayHello(String name);}

     然后是一个实现类,代码如下:

package com.jack.impl;import com.jack.service.HelloService;/** * create by jack 2017/12/18 */public class HelloServiceImpl implements HelloService{    public void sayHello(String name) {        System.out.println("hello , "+name);    }}

      下面我们编写一个代理类,提供真实对象的绑定和代理方法。代理类的要求是实现InvocationHandler接口的代理方法,当一个对象被绑定后,执行其方法的时候就会进入到代理方法里,代码如下:

package com.jack.proxy;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;/** * create by jack 2017/12/18 */public class HelloServiceProxy implements InvocationHandler{    /**     * 真实服务对象     */    private Object target;    /**     *通过代理对象调用方法首先进入这个方法     * @param proxy  代理对象     * @param method  被调用方法     * @param args    方法的参数     * @return     * @throws Throwable     */    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {        System.out.println("-----------这是JDK动态代理---------------");        Object result = null;        //反射方法前调用        System.out.println("我准备说hello......");        //执行方法,相当于调用HelloServiceImpl类的sayHello方法        result = method.invoke(target, args);        //反射方法后调用        System.out.println("我说过hello了");        return result;    }    /**     *绑定一个委托对象并返回一个代理类     * @param target     * @return     */    public Object bind(Object target) {        this.target = target;        //取得代理对象,jdk代理需要提供接口        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);    }}




//取得代理对象,jdk代理需要提供接口
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);

     上面这段代码让JDK产生了一个代理对象。这个代理对象有三个参数:第一个参数是类加载器,第二个参数是接口(代理对象挂在哪个接口下),第三个参数是this代表当前HelloServiceProxy类,换句话说是使用HelloServiceProxy的代理方法作为对象的代理执行者。

     一旦绑定后,在进入代理对象方法调用的时候就会到HelloServiceProxy的代理方法上,代理方法有三个参数:第一个proxy是代理对象,第二是当前调用的那个方法,第三个是方法的参数。比如说,现在HelloServiceImpl对象(obj)用bind方法绑定后,返回其占位,我们再调用proxy.sayHello()方法,那么它就会进入到HelloServiceProxy的invoke()方法。而invoke参数中第一个便是代理对象proxy,方法便是sayHello。

      我们已经用HelloServiceProxy类的属性target保存了真实的服务对象,那么我们可以通过反射技术调度真实对象的方法。

      result = method.invoke(target,args);

      这里我们演示了JDK动态代理的实现,并且在调用方法前后都可以加入我们想要的东西。mybatis在使用Mapper的时候也是这样做的。

      下面我们测试下动态代理,代码如下:

package com.jack.test;import com.jack.impl.HelloServiceImpl;import com.jack.proxy.HelloServiceProxy;import com.jack.service.HelloService;/** * create by jack 2017/12/18 */public class HelloServiceMain {    public static void main(String[] args) {        //创建实现代理接口对象        HelloServiceProxy HelloHandler = new HelloServiceProxy();        //获取代理对象        HelloService proxy = (HelloService) HelloHandler.bind(new HelloServiceImpl());        //方法调用        proxy.sayHello("jack");    }}

    运行测试代码,输出如下:

-----------这是JDK动态代理---------------我准备说hello......hello , jack我说过hello了Process finished with exit code 0


3,CGLIB动态代理

      JDK提供的动态代理存在一个缺陷,就是你必须提供接口才可以使用,为了克服这个缺陷,我们可以使用开源框架CGLIB,它是一种流行的动态代理。

       下面我们看看如何使用CGLIB动态代理。HelloService和HelloServiceImpl类都不需要改变,但是我们要实现CGLIB的代理类。要实现CGLIB实现代理,首先需要引入cglib包,引入代码如下:

<!-- https://mvnrepository.com/artifact/cglib/cglib -->        <dependency>            <groupId>cglib</groupId>            <artifactId>cglib</artifactId>            <version>3.2.5</version>        </dependency>


它的实现MethodInterceptor的代理方法如下:

package com.jack.impl;import net.sf.cglib.proxy.Enhancer;import net.sf.cglib.proxy.MethodInterceptor;import net.sf.cglib.proxy.MethodProxy;import java.lang.reflect.Method;/** * create by jack 2017/12/18 */public class HelloServiceCgLib implements MethodInterceptor {    private Object target;    /**     * 创建代理对象     * @param target     * @return     */    public Object getInstance(Object target){        this.target = target;        Enhancer enhancer = new Enhancer();        enhancer.setSuperclass(this.target.getClass());        //回调方法        enhancer.setCallback(this);        //创建代理对象        return  enhancer.create();    }    /**     * 回调方法     * @param object     * @param method     * @param objects     * @param methodProxy     * @return     * @throws Throwable     */    public Object intercept(Object object, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {        System.out.println("------------我是CGLIB的动态代理--------------");        //反射方法前调用        System.out.println("我准备说hello");        Object returnObj = methodProxy.invokeSuper(object, objects);        //反射方法后调用        System.out.println("我说过hello了");        return returnObj;    }}

     测试cglib动态代理的代码如下:

package com.jack.test;import com.jack.impl.HelloServiceCgLib;import com.jack.impl.HelloServiceImpl;/** * create by jack 2017/12/18 */public class CgLibMain {    public static void main(String[] args) {        HelloServiceCgLib cgLib = new HelloServiceCgLib();        HelloServiceImpl proxyImpl = (HelloServiceImpl) cgLib.getInstance(new HelloServiceImpl());        proxyImpl.sayHello("jack");    }}

    这样便实现了CGLIB的动态代理。在mybatis中通常在延迟加载的时候才会用到CGLIB的动态代理。有了这些基础,我们就可以更好的了解mybatis的解析和运行过程了。


源码地址:https://github.com/wj903829182/mybatis_study1



二,构建SqlSessionFactory过程

     SqlSessionFactory是Mybatis的核心类之一,其最重要的功能就是提供创建Mybatis的核心接口SqlSession,所以我们需要先创建SqlSessionFactory,为此我们需要提供配置文件和相关的参数。而mybatis是一个复杂的系统,采用构造模式去创建SqlSessionFactory,我们可以通过SqlSessionFactoryBuilder去构建。构建分为两步。

      第一步:通过org.apache.ibatis.builder.xml.XMLConfigBuilder解析配置的XML文件,读取配置参数,并将读取的数据存入这个org.apache.ibatis.session.Configuration类中。注意,mybatis几乎所有的配置都是存在这里的。

      第二步:使用Configuration对象去创建SqlSessionFactory。mybatis中的SqlSessionFactory是一个接口,而不是实现类,为此mybatis提供了一个默认的SqlSessionFactory实现类,我们一般都会使用org.apache.ibatis.session.defaults.DefaultSqlSessionFactory。注意,在大部分情况下我们都没有必要自己去创建新的SqlSessionFactory的实现类。

     这种创建的方式就是一种Builder模式。对于复杂的对象而言,直接使用构造方法构建是由困难的,这会导致大量的逻辑放在构造方法中,由于对象的复杂性,在构建的时候,我们更希望一步步的来构建它,从而降低其复杂性。这个时候使用一个参数类总领全局,例如,Configuration类,然后分步构建,例如,DefaultSqlSessionFactory类,就可以构建一个复杂的对象,例如,SqlSessionFactory,这种方式值得学习。


1,构建Configuration

         在SqlSessionFactory构建中,Configuration是最重要的,它的作用如下:

1)读入配置文件,包括基础配置的xml文件和映射器的xml文件。

2)初始化基础配置,比如mybatis的别名等,一些重要的类对象,例如,插件,映射器,ObjectFactory和typeHandler对象。

3)提供单例,为后续创建SessionFactory服务并提供配置的参数。

4)执行一些重要的对象方法,初始化配置信息。

      Confinguration不会是一个很简单的类,mybatis的配置信息都会来自于此。Configuration是通过XMLConfigBuilder去构建的。首先mybatis会读出所有xml配置信息。然后,将这些信息保存到Configuration类的单例中。它会做如下初始化:

1)properties全局参数

2)settings设置

3)typeAliases别名

4)typeHandler类型处理器

5)ObjectFactory对象

6)plugin插件

7)environment环境

8)DatabaseIdProvider数据库标识

9)Mapper映射器


2,映射器的内部组成

      一般而言,一个映射器是由三个部分组成:

1)MappedStatement,它保存映射器的一个结点(select|insert|delete|update)。包括许多我们配置的sql,sql的id,缓存信息,resultMap,parameterType,resultType,languageDriver等重要配置内容。

2)SqlSource,它是提供BoundSql对象的地方,它是MappedStatement的一个属性。

3)BoundSql,它是建立SQL和参数的地方。它有3个常用的属性:SQL,parameterObject,parameterMappings

      上面几个都是映射器的重要内容,也是mybatis的核心内容。在插件的应用中常常会用到它们。映射器的解析过程是比较复杂的,但是在大部分的情况下,我们并不需要去理会解析和组装SQL的规则,因为大部分的插件只要做很小的改变即可,无需做很大的改变。大的改变可能导致重写这些内容。所以一般我们主要关注参数和SQL。

       下面看看映射器的内部组成,如下:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.apache.ibatis.mapping;import java.util.ArrayList;import java.util.Collections;import java.util.Iterator;import java.util.List;import org.apache.ibatis.cache.Cache;import org.apache.ibatis.executor.keygen.Jdbc3KeyGenerator;import org.apache.ibatis.executor.keygen.KeyGenerator;import org.apache.ibatis.executor.keygen.NoKeyGenerator;import org.apache.ibatis.logging.Log;import org.apache.ibatis.logging.LogFactory;import org.apache.ibatis.scripting.LanguageDriver;import org.apache.ibatis.session.Configuration;public final class MappedStatement {    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<ResultMap> 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;    private String[] resultSets;    MappedStatement() {    }    public KeyGenerator getKeyGenerator() {        return this.keyGenerator;    }    public SqlCommandType getSqlCommandType() {        return this.sqlCommandType;    }    public String getResource() {        return this.resource;    }    public Configuration getConfiguration() {        return this.configuration;    }    public String getId() {        return this.id;    }    public boolean hasNestedResultMaps() {        return this.hasNestedResultMaps;    }    public Integer getFetchSize() {        return this.fetchSize;    }    public Integer getTimeout() {        return this.timeout;    }    public StatementType getStatementType() {        return this.statementType;    }    public ResultSetType getResultSetType() {        return this.resultSetType;    }    public SqlSource getSqlSource() {        return this.sqlSource;    }    public ParameterMap getParameterMap() {        return this.parameterMap;    }    public List<ResultMap> getResultMaps() {        return this.resultMaps;    }    public Cache getCache() {        return this.cache;    }    public boolean isFlushCacheRequired() {        return this.flushCacheRequired;    }    public boolean isUseCache() {        return this.useCache;    }    public boolean isResultOrdered() {        return this.resultOrdered;    }    public String getDatabaseId() {        return this.databaseId;    }    public String[] getKeyProperties() {        return this.keyProperties;    }    public String[] getKeyColumns() {        return this.keyColumns;    }    public Log getStatementLog() {        return this.statementLog;    }    public LanguageDriver getLang() {        return this.lang;    }    public String[] getResultSets() {        return this.resultSets;    }    /** @deprecated */    @Deprecated    public String[] getResulSets() {        return this.resultSets;    }    public BoundSql getBoundSql(Object parameterObject) {        BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject);        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();        if (parameterMappings == null || parameterMappings.isEmpty()) {            boundSql = new BoundSql(this.configuration, boundSql.getSql(), this.parameterMap.getParameterMappings(), parameterObject);        }        Iterator var4 = boundSql.getParameterMappings().iterator();        while(var4.hasNext()) {            ParameterMapping pm = (ParameterMapping)var4.next();            String rmId = pm.getResultMapId();            if (rmId != null) {                ResultMap rm = this.configuration.getResultMap(rmId);                if (rm != null) {                    this.hasNestedResultMaps |= rm.hasNestedResultMaps();                }            }        }        return boundSql;    }    private static String[] delimitedStringToArray(String in) {        return in != null && in.trim().length() != 0 ? in.split(",") : null;    }    public static class Builder {        private MappedStatement mappedStatement = new MappedStatement();        public Builder(Configuration configuration, String id, SqlSource sqlSource, SqlCommandType sqlCommandType) {            this.mappedStatement.configuration = configuration;            this.mappedStatement.id = id;            this.mappedStatement.sqlSource = sqlSource;            this.mappedStatement.statementType = StatementType.PREPARED;            this.mappedStatement.parameterMap = (new org.apache.ibatis.mapping.ParameterMap.Builder(configuration, "defaultParameterMap", (Class)null, new ArrayList())).build();            this.mappedStatement.resultMaps = new ArrayList();            this.mappedStatement.sqlCommandType = sqlCommandType;            this.mappedStatement.keyGenerator = (KeyGenerator)(configuration.isUseGeneratedKeys() && SqlCommandType.INSERT.equals(sqlCommandType) ? Jdbc3KeyGenerator.INSTANCE : NoKeyGenerator.INSTANCE);            String logId = id;            if (configuration.getLogPrefix() != null) {                logId = configuration.getLogPrefix() + id;            }            this.mappedStatement.statementLog = LogFactory.getLog(logId);            this.mappedStatement.lang = configuration.getDefaultScriptingLanguageInstance();        }        public MappedStatement.Builder resource(String resource) {            this.mappedStatement.resource = resource;            return this;        }        public String id() {            return this.mappedStatement.id;        }        public MappedStatement.Builder parameterMap(ParameterMap parameterMap) {            this.mappedStatement.parameterMap = parameterMap;            return this;        }        public MappedStatement.Builder resultMaps(List<ResultMap> resultMaps) {            this.mappedStatement.resultMaps = resultMaps;            Iterator var2 = resultMaps.iterator();            while(var2.hasNext()) {                ResultMap resultMap = (ResultMap)var2.next();                this.mappedStatement.hasNestedResultMaps = this.mappedStatement.hasNestedResultMaps || resultMap.hasNestedResultMaps();            }            return this;        }        public MappedStatement.Builder fetchSize(Integer fetchSize) {            this.mappedStatement.fetchSize = fetchSize;            return this;        }        public MappedStatement.Builder timeout(Integer timeout) {            this.mappedStatement.timeout = timeout;            return this;        }        public MappedStatement.Builder statementType(StatementType statementType) {            this.mappedStatement.statementType = statementType;            return this;        }        public MappedStatement.Builder resultSetType(ResultSetType resultSetType) {            this.mappedStatement.resultSetType = resultSetType;            return this;        }        public MappedStatement.Builder cache(Cache cache) {            this.mappedStatement.cache = cache;            return this;        }        public MappedStatement.Builder flushCacheRequired(boolean flushCacheRequired) {            this.mappedStatement.flushCacheRequired = flushCacheRequired;            return this;        }        public MappedStatement.Builder useCache(boolean useCache) {            this.mappedStatement.useCache = useCache;            return this;        }        public MappedStatement.Builder resultOrdered(boolean resultOrdered) {            this.mappedStatement.resultOrdered = resultOrdered;            return this;        }        public MappedStatement.Builder keyGenerator(KeyGenerator keyGenerator) {            this.mappedStatement.keyGenerator = keyGenerator;            return this;        }        public MappedStatement.Builder keyProperty(String keyProperty) {            this.mappedStatement.keyProperties = MappedStatement.delimitedStringToArray(keyProperty);            return this;        }        public MappedStatement.Builder keyColumn(String keyColumn) {            this.mappedStatement.keyColumns = MappedStatement.delimitedStringToArray(keyColumn);            return this;        }        public MappedStatement.Builder databaseId(String databaseId) {            this.mappedStatement.databaseId = databaseId;            return this;        }        public MappedStatement.Builder lang(LanguageDriver driver) {            this.mappedStatement.lang = driver;            return this;        }        public MappedStatement.Builder resultSets(String resultSet) {            this.mappedStatement.resultSets = MappedStatement.delimitedStringToArray(resultSet);            return this;        }        /** @deprecated */        @Deprecated        public MappedStatement.Builder resulSets(String resultSet) {            this.mappedStatement.resultSets = MappedStatement.delimitedStringToArray(resultSet);            return this;        }        public MappedStatement build() {            assert this.mappedStatement.configuration != null;            assert this.mappedStatement.id != null;            assert this.mappedStatement.sqlSource != null;            assert this.mappedStatement.lang != null;            this.mappedStatement.resultMaps = Collections.unmodifiableList(this.mappedStatement.resultMaps);            return this.mappedStatement;        }    }}

       SqlSource是MappedStatement的一个属性,

public BoundSql getBoundSql(Object parameterObject) {        BoundSql boundSql = this.sqlSource.getBoundSql(parameterObject);        List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();        if (parameterMappings == null || parameterMappings.isEmpty()) {            boundSql = new BoundSql(this.configuration, boundSql.getSql(), this.parameterMap.getParameterMappings(), parameterObject);        }        Iterator var4 = boundSql.getParameterMappings().iterator();        while(var4.hasNext()) {            ParameterMapping pm = (ParameterMapping)var4.next();            String rmId = pm.getResultMapId();            if (rmId != null) {                ResultMap rm = this.configuration.getResultMap(rmId);                if (rm != null) {                    this.hasNestedResultMaps |= rm.hasNestedResultMaps();                }            }        }        return boundSql;    }

      上面的方法是MappedStatement的一个方法,SqlSource是一个接口,它的作用是根据参数和其他的规则组装SQL,包括动态sql。对于参数和sql而言,主要的规则都反映在BoundSql类对象上,在插件中往往需要拿到它进而可以拿到运行的sql和参数规则,做出适当的修改,来满足我们特殊的需求。

      BoundSql会提供3个主要的属性:parameterMappings,parameterObject和sql,源码如下:

//// Source code recreated from a .class file by IntelliJ IDEA// (powered by Fernflower decompiler)//package org.apache.ibatis.mapping;import java.util.HashMap;import java.util.List;import java.util.Map;import org.apache.ibatis.reflection.MetaObject;import org.apache.ibatis.reflection.property.PropertyTokenizer;import org.apache.ibatis.session.Configuration;public class BoundSql {    private final String sql;    private final List<ParameterMapping> parameterMappings;    private final Object parameterObject;    private final Map<String, Object> additionalParameters;    private final MetaObject metaParameters;    public BoundSql(Configuration configuration, String sql, List<ParameterMapping> parameterMappings, Object parameterObject) {        this.sql = sql;        this.parameterMappings = parameterMappings;        this.parameterObject = parameterObject;        this.additionalParameters = new HashMap();        this.metaParameters = configuration.newMetaObject(this.additionalParameters);    }    public String getSql() {        return this.sql;    }    public List<ParameterMapping> getParameterMappings() {        return this.parameterMappings;    }    public Object getParameterObject() {        return this.parameterObject;    }    public boolean hasAdditionalParameter(String name) {        String paramName = (new PropertyTokenizer(name)).getName();        return this.additionalParameters.containsKey(paramName);    }    public void setAdditionalParameter(String name, Object value) {        this.metaParameters.setValue(name, value);    }    public Object getAdditionalParameter(String name) {        return this.metaParameters.getValue(name);    }}

 1)其中parameterObject为参数本身。我们可以传递简单对象,POJO,Map或者@Param注解的参数,由于它在插件中相当常用,需要细细研究。

2)传递简单对象(包括int,String,float,double等),比如当我们传递int类型时,Mybatis会把参数变为Integer对象传递,类型的long,String,float,double也是如此。

3)如果传递的是POJO或者Map,那么这个parameterObject就是你传入的POJO或者Map不变。

4)当然我们也可以传递多个参数,如果没有@Param注解,那么mybatis就会把parameterObject变为一个Map<String,Object>对象,其键值的关系是按顺序来规划的类似于这样的形式{"1":p1,"2":p2,"3":p3..........,"param1":p1,"param2":p2......},所以在编写的时候我们都可以使用#{param1}或者#{1}去引用第一个参数。

5)如果我们使用@Param注解,那么mybatis就会把parameterObject也会变成一个Map<String,Object>对象,类似于没有@Param注解,只是把其数字的键值对应置换为了@Param注解的键值。比如我们注解@Param("key1") String p1,@Param("key2") int p2,@Param("key3") Role p3,那么这个parameterObject对象就是一个Map<String,Object>,它的键值包含:{"key1":p1,"key2":p2,"key3":p3,"param1":p1,"param2":p2,"param3":p3}


6)parameterMappings,它是一个List,每一个元素都是ParameterMapping的对象。这个对象会描述我们的参数。参数包括属性,名称,表达式,javaType,jdbcType,typeHandler等重要信息,我们一般不需要去改变它。通过它可以实现参数和SQL的结合,以便PreparedStatement能够通过它找到parameterObject对象的属性并设置参数,使得查询准确运行。

7)sql属性就是我们书写在映射器里面的一条sql,在大多数的时候无需修改它,只有在插件的情况下,我们可以根据需要进行改写。改写sql将是一件危险的事情,务必小心谨慎。


3,构建SqlSessionFactory

       有了Configuration对象构建SqlSessionFactory就很简单了,我们只要写很简单的代码就可以了:

   sqlSessionFactory = new SqlSessionFactoryBuilder().builder(inputStream);

     mybatis会根据Configuration的配置读取所配置的信息,构建SqlSessionFactory对象。




原创粉丝点击