`
Donald_Draper
  • 浏览: 979885 次
社区版块
存档分类
最新评论

mybatis 动态标签语句的解析(BoundSql)

阅读更多
SqlSessionFactory初始化:http://donald-draper.iteye.com/2331917
Mybatis加载解析Mapper(xml)文件第一讲:http://donald-draper.iteye.com/blog/2333125
Mybatis加载解析Mapper(xml)文件第二讲:http://donald-draper.iteye.com/blog/2333191
Mybatis 解析Mapper(class):http://donald-draper.iteye.com/blog/2333293
Mybatis的Environment解析详解:http://donald-draper.iteye.com/blog/2334133
解析Mapper xml文件中的select|insert|update|delete节点
public class XMLStatementBuilder extends BaseBuilder
{

    private MapperBuilderAssistant builderAssistant;
    private XNode context;
    private String requiredDatabaseId;
  public void parseStatementNode()
    {
       select|insert|update|delete节点的lang属性
       String lang = context.getStringAttribute("lang");
       LanguageDriver langDriver = getLanguageDriver(lang);
       SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);
    }
}

来看这一句
LanguageDriver langDriver = getLanguageDriver(lang);


//返回LanguageDriver
private LanguageDriver getLanguageDriver(String lang)
    {
        Class langClass;
        if(lang == null)
        {
            //如果statement节点的lang属性为空,则返回默认的DefaultDriverClass         
	    langClass = configuration.getLanguageRegistry().getDefaultDriverClass();
        } else
        {
            langClass = resolveClass(lang);
            configuration.getLanguageRegistry().register(langClass);
        }
        if(langClass == null)
            langClass = configuration.getLanguageRegistry().getDefaultDriverClass();
        return configuration.getLanguageRegistry().getDriver(langClass);
   }

//configuration,返回LanguageDriverRegistry
 public LanguageDriverRegistry getLanguageRegistry()
    {
        return languageRegistry;
    }

//LanguageDriverRegistry
 
  public class LanguageDriverRegistry
{
    private final Map LANGUAGE_DRIVER_MAP = new HashMap();
    private Class defaultDriverClass;
    public void register(Class cls)
    {
        if(cls == null)
            throw new IllegalArgumentException("null is not a valid Language Driver");
        if(!org/apache/ibatis/scripting/LanguageDriver.isAssignableFrom(cls))
            throw new ScriptingException((new StringBuilder()).append(cls.getName()).append(" does not implements ").append(org/apache/ibatis/scripting/LanguageDriver.getName()).toString());
        LanguageDriver driver = (LanguageDriver)LANGUAGE_DRIVER_MAP.get(cls);
        if(driver == null)
            try
            {
                driver = (LanguageDriver)cls.newInstance();
                LANGUAGE_DRIVER_MAP.put(cls, driver);
            }
    }
    public Class getDefaultDriverClass()
    {
        return defaultDriverClass;
    }
}

从默认的configuration的构造方法中,我们可以看,DefaultDriverClass为XMLLanguageDriver

languageRegistry.setDefaultDriverClass(org/apache/ibatis/scripting/xmltags/XMLLanguageDriver);


下面来看一下,LangDriver如何创建SqlSource,而LangDriver为XMLLanguageDriver
SqlSource sqlSource = langDriver.createSqlSource(configuration, context, parameterTypeClass);

//XMLLanguageDriver
public class XMLLanguageDriver
    implements LanguageDriver
{
    //根据configuration,和statement节点和参数类型来创建SqlSource
    public SqlSource createSqlSource(Configuration configuration, XNode script, Class parameterType)
    {
        //构建statement节点解析器
        XMLScriptBuilder builder = new XMLScriptBuilder(configuration, script);
        return builder.parseScriptNode();
    }
}

来看XMLScriptBuilder根据statement节点,创建SqlSource
public class XMLScriptBuilder extends BaseBuilder
{
    private XNode context;//statement节点
    private Map nodeHandlers = new HashMap() {
        private static final long serialVersionUID = 7123056019193266281L;
        final XMLScriptBuilder this$0;     
            {
                this$0 = XMLScriptBuilder.this;
                super();
		//statement的节点的子节点where,forEach,if等处理器
                put("trim", new TrimHandler());
                put("where", new WhereHandler());
                put("set", new SetHandler());
                put("foreach", new ForEachHandler());
                put("if", new IfHandler());
                put("choose", new ChooseHandler());
                put("when", new IfHandler());
                put("otherwise", new OtherwiseHandler());
                put("bind", new BindHandler());
            }
    };
    //IF节点处理器
     private class IfHandler
        implements NodeHandler
    {

        public void handleNode(XNode nodeToHandle, List targetContents)
        {
            List contents = parseDynamicTags(nodeToHandle);
            MixedSqlNode mixedSqlNode = new MixedSqlNode(contents);
            String test = nodeToHandle.getStringAttribute("test");
            IfSqlNode ifSqlNode = new IfSqlNode(mixedSqlNode, test);
            targetContents.add(ifSqlNode);
        }
    }
     private static interface NodeHandler
    {

        public abstract void handleNode(XNode xnode, List list);
    }
    //解析statement节点
    public SqlSource parseScriptNode()
    {
        //解析statement节点的动态标签
        List contents = parseDynamicTags(context);
        MixedSqlNode rootSqlNode = new MixedSqlNode(contents);
	//构建动态sql语句源,DynamicSqlSource
        SqlSource sqlSource = new DynamicSqlSource(configuration, rootSqlNode);
        return sqlSource;
    }
    //解析statement节点的动态标签
    private List parseDynamicTags(XNode node)
    {
        List contents = new ArrayList();
        NodeList children = node.getNode().getChildNodes();
        for(int i = 0; i < children.getLength(); i++)
        {
            XNode child = node.newXNode(children.item(i));
            String nodeName = child.getNode().getNodeName();
            if(child.getNode().getNodeType() == 4 || child.getNode().getNodeType() == 3)
            {
                String data = child.getStringBody("");
                contents.add(new TextSqlNode(data));
                continue;
            }
            if(child.getNode().getNodeType() != 1 || "selectKey".equals(nodeName))
                continue;
            NodeHandler handler = (NodeHandler)nodeHandlers.get(nodeName);
            if(handler == null)
                throw new BuilderException((new StringBuilder()).append("Unknown element <").append(nodeName).append("> in SQL statement.").toString());
            handler.handleNode(child, contents);
        }
        return contents;
    }
}

//DynamicSqlSource
public class DynamicSqlSource
    implements SqlSource
{
    private Configuration configuration;
    private SqlNode rootSqlNode;

    public DynamicSqlSource(Configuration configuration, SqlNode rootSqlNode)
    {
        this.configuration = configuration;
        this.rootSqlNode = rootSqlNode;
    }
    public BoundSql getBoundSql(Object parameterObject)
    {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);
	//创建SqlSourceBuilder
        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
        Class parameterType = ((Class) (parameterObject != null ? parameterObject.getClass() : java/lang/Object));
        //解析statement节点,并返回sqlSource
	SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        java.util.Map.Entry entry;
        for(Iterator i$ = context.getBindings().entrySet().iterator(); i$.hasNext(); boundSql.setAdditionalParameter((String)entry.getKey(), entry.getValue()))
            entry = (java.util.Map.Entry)i$.next();

        return boundSql;
    }
}

sql语句构建器
//SqlSourceBuilder
public class SqlSourceBuilder extends BaseBuilder
{
   private static class ParameterMappingTokenHandler extends BaseBuilder
 public SqlSourceBuilder(Configuration configuration)
    {
        super(configuration);
    }

    public SqlSource parse(String originalSql, Class parameterType, Map additionalParameters)
    {
        ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType, additionalParameters);
         //创建sql语句解析器
	GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);
	//解析sql
        String sql = parser.parse(originalSql);
	//返回StaticSqlSource
        return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
    }
    private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";
}


//创建sql参数解析器,
GenericTokenParser parser = new GenericTokenParser("#{", "}", handler);

//解析sql
String sql = parser.parse(originalSql);

//GenericTokenParser
public class GenericTokenParser
{
    private final String openToken;//参数开始标志
    private final String closeToken;//参数解析标志
    private final TokenHandler handler;//ParameterMappingTokenHandler,参数hanler
    public GenericTokenParser(String openToken, String closeToken, TokenHandler handler)
    {
        this.openToken = openToken;
        this.closeToken = closeToken;
        this.handler = handler;
    }
    //解析statement中的sql语句
    public String parse(String text)
    {
        StringBuilder builder = new StringBuilder();
        if(text != null && text.length() > 0)
        {
            char src[] = text.toCharArray();
            int offset = 0;
            for(int start = text.indexOf(openToken, offset); start > -1; start = text.indexOf(openToken, offset))
            {
                if(start > 0 && src[start - 1] == '\\')
                {
                    builder.append(src, offset, start - 1).append(openToken);
                    offset = start + openToken.length();
                    continue;
                }
                int end = text.indexOf(closeToken, start);
                if(end == -1)
                {
                    builder.append(src, offset, src.length - offset);
                    offset = src.length;
                } else
                {
                    builder.append(src, offset, start - offset);
                    offset = start + openToken.length();
                    String content = new String(src, offset, end - offset);
                    builder.append(handler.handleToken(content));
                    offset = end + closeToken.length();
                }
            }

            if(offset < src.length)
                builder.append(src, offset, src.length - offset);
        }
        return builder.toString();
    }
}

//StaticSqlSource
public class StaticSqlSource
    implements SqlSource
{
    
    private String sql;
    private List parameterMappings;
    private Configuration configuration;
    //构造静态的SqlSource根据configuration,sql,parameterMappings
    public StaticSqlSource(Configuration configuration, String sql, List parameterMappings)
    {
        this.sql = sql;
        this.parameterMappings = parameterMappings;
        this.configuration = configuration;
    }
    //构建BoundSql
    public BoundSql getBoundSql(Object parameterObject)
    {
        return new BoundSql(configuration, sql, parameterMappings, parameterObject);
    }
}

//sql包装类
public class BoundSql
{
    private String sql;//执行SQL,prepare
    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);
    }
}

//MappedStatement
public final class MappedStatement
{
    public static class Builder{}
    private String resource;
    private Configuration configuration;
    private String id;
    private Integer fetchSize;
    private Integer timeout;
    private StatementType statementType;//默认为Prepare,call - 》CallStatement
    private ResultSetType resultSetType;
    private SqlSource sqlSource;//sql语句产生器
    private Cache cache;//缓存类型
    private ParameterMap parameterMap;
    private List resultMaps;
    private boolean flushCacheRequired;
    private boolean useCache;//是否用缓存
    private boolean resultOrdered;
    private SqlCommandType sqlCommandType;//命令类型,Select,delete,update,insert
    private KeyGenerator keyGenerator;//主键生成器
    private String keyProperties[];
    private String keyColumns[];
    private boolean hasNestedResultMaps;
    private String databaseId;
    private Log statementLog;
    private LanguageDriver lang;//statement节点解析Drive,默认为XMLLanguageDriver
    //
    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;
    }
}

//获取sql的包装类,关键在MappedStatement的这3个LanguageDriver,SqlSource,Configuration参数
总结:
MappedStatement这Mapper文件中,每个select,insert,update,delete子节点的包装,从MappedStatement,获取sql的包装类BoundSql,主要根据这三个参数LanguageDriver,SqlSource,Configuration;在Configuration的构造函数,
我们可以看出LanguageDriver默认的,为XMLLanguageDriver,XMLLanguageDriver创建SqlSource时,由XMLScriptBuilder去解析具体的select|insert|update|delete节点信息,XMLScriptBuilder中有各种动态标签的处理器,如if,where,foreach等;
XMLScriptBuilder将具体动态标签语句,委托给DynamicSqlSource去处理,而DynamicSqlSource将具体的动态sql的解析,拼接委托
给SqlSourceBuilder,SqlSourceBuilder通过参数类型映射处理器ParameterMappingTokenHandler和参数解析器GenericTokenParser去除里;ParameterMappingTokenHandler主要处理参数与jdbc type的映射ParameterMappings,GenericTokenParser主要处理sql语句中参数的解析,拼接 sql,然后根据configuration, sql,ParameterMappings构造StaticSqlSource;
其实DynamicSqlSource获取BoundSql,解析动态标签及语句,转化为StaticSqlSource,实际上是,由StaticSqlSource,创建BoundSql


附:
//LanguageDriver
public interface LanguageDriver
{
    public abstract ParameterHandler createParameterHandler(MappedStatement mappedstatement, Object obj, BoundSql boundsql);
    public abstract SqlSource createSqlSource(Configuration configuration, XNode xnode, Class class1);
    public abstract SqlSource createSqlSource(Configuration configuration, String s, Class class1);
}

//ParameterMappingTokenHandler
private static class ParameterMappingTokenHandler extends BaseBuilder
        implements TokenHandler
    {

        public List getParameterMappings()
        {
            return parameterMappings;
        }
        //将参数类型添加到parameterMappings,返回占位符
        public String handleToken(String content)
        {
            parameterMappings.add(buildParameterMapping(content));
            return "?";
        }
        //获取参数的ParameterMapping
        private ParameterMapping buildParameterMapping(String content)
        {
            org.apache.ibatis.mapping.ParameterMapping.Builder builder;
            Class javaType;
            String typeHandlerAlias;
label0:
            {
                Map propertiesMap = parseParameterMapping(content);
                String property = (String)propertiesMap.get("property");
                Class propertyType;
                if(metaParameters.hasGetter(property))
                    propertyType = metaParameters.getGetterType(property);
                else
                if(typeHandlerRegistry.hasTypeHandler(parameterType))
                    propertyType = parameterType;
                else
                if(JdbcType.CURSOR.name().equals(propertiesMap.get("jdbcType")))
                    propertyType = java/sql/ResultSet;
                else
                if(property != null)
                {
                    MetaClass metaClass = MetaClass.forClass(parameterType);
                    if(metaClass.hasGetter(property))
                        propertyType = metaClass.getGetterType(property);
                    else
                        propertyType = java/lang/Object;
                } else
                {
                    propertyType = java/lang/Object;
                }
                builder = new org.apache.ibatis.mapping.ParameterMapping.Builder(configuration, property, propertyType);
                javaType = propertyType;
                typeHandlerAlias = null;
                String name;
label1:
                do
                {
                    for(Iterator i$ = propertiesMap.entrySet().iterator(); i$.hasNext();)
                    {
                        java.util.Map.Entry entry = (java.util.Map.Entry)i$.next();
                        name = (String)entry.getKey();
                        String value = (String)entry.getValue();
                        if("javaType".equals(name))
                        {
                            javaType = resolveClass(value);
                            builder.javaType(javaType);
                        } else
                        if("jdbcType".equals(name))
                            builder.jdbcType(resolveJdbcType(value));
                        else
                        if("mode".equals(name))
                            builder.mode(resolveParameterMode(value));
                        else
                        if("numericScale".equals(name))
                            builder.numericScale(Integer.valueOf(value));
                        else
                        if("resultMap".equals(name))
                            builder.resultMapId(value);
                        else
                        if("typeHandler".equals(name))
                        {
                            typeHandlerAlias = value;
                        } else
                        {
                            if(!"jdbcTypeName".equals(name))
                                continue label1;
                            builder.jdbcTypeName(value);
                        }
                    }

                    break label0;
                } while("property".equals(name));
                if("expression".equals(name))
                    throw new BuilderException("Expression based parameters are not supported yet");
                else
                    throw new BuilderException((new StringBuilder()).append("An invalid property '").append(name).append("' was found in mapping #{").append(content).append("}.  Valid properties are ").append("javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName").toString());
            }
            if(typeHandlerAlias != null)
                builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
            return builder.build();
        }

        private Map parseParameterMapping(String content)
        {
            return ParameterExpressionParser.parse(content);
            BuilderException ex;
            ex;
            throw ex;
            ex;
            throw new BuilderException((new StringBuilder()).append("Parsing error was found in mapping #{").append(content).append("}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} ").toString(), ex);
        }

        private List parameterMappings;
        private Class parameterType;
        private MetaObject metaParameters;

        public ParameterMappingTokenHandler(Configuration configuration, Class parameterType, Map additionalParameters)
        {
            super(configuration);
            parameterMappings = new ArrayList();
            this.parameterType = parameterType;
            metaParameters = configuration.newMetaObject(additionalParameters);
        }
}

//MixedSqlNode
public class MixedSqlNode
    implements SqlNode
{
    private List contents;
    public MixedSqlNode(List contents)
    {
        this.contents = contents;
    }
    public boolean apply(DynamicContext context)
    {
        SqlNode sqlNode;
        for(Iterator i$ = contents.iterator(); i$.hasNext(); sqlNode.apply(context))
            sqlNode = (SqlNode)i$.next();

        return true;
    }
}

//SqlNode
public interface SqlNode
{
    public abstract boolean apply(DynamicContext dynamiccontext);
}

//DynamicContext
public class DynamicContext
{
   public static final String PARAMETER_OBJECT_KEY = "_parameter";
    public static final String DATABASE_ID_KEY = "_databaseId";
    private final ContextMap bindings;
    private final StringBuilder sqlBuilder = new StringBuilder();
    private int uniqueNumber;

    static 
    {
        OgnlRuntime.setPropertyAccessor(org/apache/ibatis/scripting/xmltags/DynamicContext$ContextMap, new ContextAccessor());
    }
     public String getSql()
    {
        return sqlBuilder.toString().trim();
    }
     static class ContextMap extends HashMap
    {

        public Object get(Object key)
        {
            String strKey = (String)key;
            if(super.containsKey(strKey))
                return super.get(strKey);
            if(parameterMetaObject != null)
            {
                Object object = parameterMetaObject.getValue(strKey);
                if(object != null)
                    super.put(strKey, object);
                return object;
            } else
            {
                return null;
            }
        }
        private static final long serialVersionUID = 2977601501966151582L;
        private MetaObject parameterMetaObject;

        public ContextMap(MetaObject parameterMetaObject)
        {
            this.parameterMetaObject = parameterMetaObject;
        }
    }
}
分享到:
评论

相关推荐

    Mybatis源码研究之BoundSql.pdf

    通过对`BoundSql`源码的研究,我们可以更加深入地理解MyBatis是如何处理SQL语句及其参数的。`BoundSql` 不仅是MyBatis执行数据库操作的重要组件,也是理解和掌握MyBatis框架的关键之一。希望本文能帮助读者更好地...

    myBatis执行流程全解析1

    2. **SQL语句解析**: - `XMLStatementBuilder`解析SQL语句节点,构建`MappedStatement`对象,其中包含了SQL的ID、参数类型、返回类型、SQL源等信息。 - `SqlSourceBuilder`进一步解析动态SQL,将静态和动态部分...

    MyBatis 执行动态 SQL语句详解

    MyBatis 在解析这些动态 SQL 时,会基于 `DynamicSqlSource` 类生成 `BoundSql` 对象,该对象包含了最终的 SQL 语句和参数信息,确保了 SQL 的正确执行。 总结来说,MyBatis 动态 SQL 提供了一种灵活的方式来根据...

    MyBatis语句规范化拦截器1

    本话题主要探讨如何编写一个MyBatis语句规范化拦截器,防止因条件错误导致的批量操作对数据库造成不可逆转的影响。 ### 1. 目的 规范化的SQL语句可以避免因程序员的疏忽或者错误导致的数据误删或误改。例如,未加...

    mybatis-3.5.3.pdf

    MyBatis 提供了强大的动态 SQL 功能,通过 `&lt;if&gt;`, `&lt;choose&gt;`, `&lt;when&gt;`, `&lt;otherwise&gt;`, `&lt;where&gt;`, `&lt;set&gt;`, `&lt;foreach&gt;` 等标签,可以在 XML 文件中编写条件语句,实现 SQL 语句的动态生成,适应不同的查询需求...

    Mybatis下动态sql中##和$$的区别讲解

    首先,我们需要了解的是,Mybatis在对SQL语句进行预编译之前,会对SQL语句进行动态解析,解析为一个BoundSql对象。在动态SQL解析阶段,#{ }和${ }会有不同的表现。#{ }:解析为一个JDBC预编译语句(prepared ...

    阿里巴巴P7架构师纯手工打造MyBatis源码——1小时解密底层源码.txt

    2. **创建BoundSql**:解析SQL语句,生成`BoundSql`对象。 3. **参数处理**:根据传入的参数值设置`BoundSql`中的参数。 4. **执行器处理**:调用`Executor`执行SQL语句。 5. **结果处理**:处理执行结果,将其转换...

    解析Mybatis判断表达式源码分析

    它提供了 getBoundSql 方法,该方法将参数对象转换为 BoundSql 对象,并将 SQL 语句动态地拼接起来。 SqlNode 接口 SqlNode 接口是 Mybatis 中的一个重要接口,它定义了 SQL 语句节点的行为。SqlNode 接口有多个...

    MyBatis源码包

    通过阅读源码,开发者可以深入理解MyBatis的工作原理,学习如何设计和实现一个高效的ORM框架,以及如何处理SQL语句的动态生成与执行。 描述中提到的"Eclipse中点击Open Source导入源码",意味着我们可以使用Eclipse...

    mybatis interceptor

    // 获取BoundSql对象,其中包含了SQL语句和参数 BoundSql boundSql = mappedStatement.getBoundSql((Object) invocation.getArgs()[3]); // ... 分页逻辑 ... } } ``` 2. **识别分页查询**:我们需要判断当前...

    java-ORM框架Mybatis源码分析

    在执行SQL前,MyBatis需要将XML中的SQL语句和结果集映射解析为`MappedStatement`对象,这一步由`Configuration`类完成。`MappedStatement`包含了完整的SQL语句、参数映射信息和结果集映射信息。通过`BoundSql`,...

    mybatis使用拦截器实现分页操作

    除了上述基本的实现方式,还可以考虑结合MyBatis的`ExecutorType.SIMPLE`或`ExecutorType.BATCH`执行器,以及`boundSql`对象来优化分页性能。例如,可以避免在`SIMPLE`模式下对每个分页请求都进行数据库连接的创建和...

    mybatis 自定义分页插件.rar

    拦截器是MyBatis动态代理机制的一部分,它允许我们在执行SQL语句之前或之后插入一些额外的操作。在分页插件的场景下,我们可以利用拦截器在执行查询前计算页码和每页大小,然后动态修改原始的SQL语句,使其包含分页...

    ibatis UPDATE 动态XML与insert

    MyBatis通过`SqlSourceBuilder`和`BoundSql`等类解析XML中的动态元素,并在运行时构建出实际的SQL语句。而"工具"则可能意味着我们可以结合其他开发工具,如IDE插件或日志工具,来辅助调试和优化这些动态SQL。 至于...

    后端开发框架 MyBatis四大核心对象之ParameterHandler.pdf

    - 它的主要作用在于处理动态传入的参数,并将其正确地绑定到SQL语句中,从而实现SQL语句的动态化。 2. **重要性**: - ParameterHandler对于提高SQL执行效率至关重要,因为它能够避免硬编码SQL语句中的参数,使得...

    mybatis3 物理分页源代码

    在Mybatis中,拦截器扮演着关键角色,它允许我们在特定的执行点(如SQL语句的准备、执行等)插入自定义的行为。`Interceptor`接口提供了`intercept`方法,这个方法会在目标方法执行前后被调用,使得我们可以对原方法...

    Mybatis多对多关联映射源码

    - `org.apache.ibatis.builder.xml.XMLMapperBuilder`: 这是解析XML映射文件的关键类,其中的`parseNestedResultMap()`方法处理`&lt;resultMap&gt;`标签,包含了多对多映射的解析逻辑。 - `org.apache.ibatis.mapping....

    Mybatis拦截器实现分页

    在拦截器中,我们需要解析SQL,找出原始的查询语句并添加分页条件。通常,我们可以通过`RowBounds`参数来获取分页信息。`RowBounds`对象包含了起始行和每页记录数,我们可以利用这些信息构造新的SQL。 ```java ...

    Mybatis分页插件- PageHelper

    - **3.4.1版本**:此版本修复了一个关键的bug,即当`SqlParser`解析SQL失败时可能会返回不包含`count(*)`的SQL,从而导致查询失败的问题。 - **3.4.0版本**:增加了对`@SelectProvider`注解的支持,并进行了大量内部...

Global site tag (gtag.js) - Google Analytics