mybatis的解析和运行原理1

         如果只是学会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对象。




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值