MyBatis Source Code Series Nine: Dynamic SQL Processing

MyBatis Source Code Series Nine: Dynamic SQL Processing

Foreword

In previous articles, we have learned MyBatis configuration file parsing, SQL mapping file parsing, creation of SqlSessionFactory, working principle of SqlSession, implementation of Executor, transaction management and plug-in mechanism of MyBatis, etc. This article will delve into the processing of dynamic SQL in MyBatis.

Dynamic SQL is a powerful feature of MyBatis, which allows us to dynamically generate SQL statements according to different conditions, so as to achieve flexible query and update operations. MyBatis provides a wealth of tags and functions to support the writing of dynamic SQL, such as if, choose, when, otherwise, foreach, etc.

In this article, we will analyze the processing process of dynamic SQL in MyBatis in detail, and explain it in combination with the source code to help readers understand its implementation principle in depth.

Processing process of dynamic SQL

When MyBatis parses the SQL statement, it will generate the final SQL statement according to the conditions according to the dynamic SQL labels and functions in the configuration file. Let’s analyze the processing of dynamic SQL.

1. Parse the SQL statement

First, MyBatis will parse the SQL statement and divide it into static part and dynamic part. The static part is a fixed SQL statement, while the dynamic part contains various dynamic labels and functions.

2. Create SqlSource object

Next, MyBatis will create the corresponding SqlSource object according to the parsed SQL statement. The SqlSource object is responsible for the generation of the final SQL statement.

3. Parse dynamic SQL

In the process of parsing dynamic SQL, MyBatis will judge according to the conditions of dynamic labels and functions, and decide whether to include the corresponding SQL statement fragment. According to different conditions, there can be the following situations:

  • If the condition is true, it means that the condition is met, and the corresponding SQL statement fragment is included in the final SQL statement.
  • If the condition is false, it means that the condition is not met, and the corresponding SQL statement fragment is ignored and not included in the final SQL statement.

During parsing, MyBatis will recursively process nested dynamic labels and functions until the final SQL statement is generated.

4. Binding parameters

Finally, MyBatis will associate the information of the bound parameters with the generated final SQL statement to generate the final executable SQL statement.

The realization principle of dynamic SQL

After understanding the processing process of dynamic SQL, let’s analyze its implementation principle in depth through source code analysis.

In the source code of MyBatis, the processing of dynamic SQL is mainly concentrated in `org.apache.ibatis.scripting

In some classes under the .xmltags package. Among them, SqlNode interface and DynamicContext class are the core.

SqlNode interface

The SqlNode interface defines the behavior of the dynamic SQL node, and it has a method apply for applying the dynamic SQL node to the DynamicContext context.

Let’s take a look at the source code of the SqlNode interface:

public interface SqlNode {<!-- -->
  boolean apply(DynamicContext context);
}

DynamicContext class

The DynamicContext class is the context object of dynamic SQL, which contains the final generated SQL statement, information about binding parameters, etc.

The following is a simplified version of the DynamicContext class:

public class DynamicContext {<!-- -->
  private StringBuilder sqlBuilder = new StringBuilder();
  private Map<String, Object> bindings = new HashMap<>();
  
  public void appendSql(String sqlFragment) {<!-- -->
    sqlBuilder.append(sqlFragment);
    sqlBuilder.append(" ");
  }
  
  // Other methods omit...
}

In the process of parsing dynamic SQL, the DynamicContext object will be passed to each dynamic SQL node, and each node can add its own SQL statement fragment to DynamicContext.

Analytic process of dynamic SQL

The parsing process of dynamic SQL is a recursive process. Let’s take the if tag as an example to introduce the parsing process of dynamic SQL.

1. Analysis of if tag

The if tag is a conditional judgment tag commonly used in dynamic SQL, and its analysis is in charge of the IfSqlNode class.

Here is a simplified version of the IfSqlNode class:

public class IfSqlNode implements SqlNode {<!-- -->
  private ExpressionEvaluator evaluator;
  private String test;
  private SqlNode contents;
  
  public IfSqlNode(SqlNode contents, String test) {<!-- -->
    this.contents = contents;
    this.test = test;
    evaluator = new ExpressionEvaluator();
  }
  
  public boolean apply(DynamicContext context) {<!-- -->
    if (evaluator.evaluateBoolean(test, context.getBindings())) {<!-- -->
      contents.apply(context);
      return true;
    }
    return false;
  }
  
  // Other methods omit...
}

In the apply method, first evaluate the test expression through the ExpressionEvaluator object to determine whether the condition is met. If the condition is true, apply the SQL statement in contents to the DynamicContext context.

2. Analysis process of dynamic SQL

The parsing process of dynamic SQL is a recursive process, which is in charge of the MixedSqlNode class. The MixedSqlNode class is a composite node that can contain multiple child nodes, and each child node can be a dynamic SQL label or a static SQL text.

The following is a simplified version of the MixedSqlNode class:

public class MixedSqlNode implements SqlNode {<!-- -->
  private List<SqlNode> contents;
  
  public MixedSqlNode(List<SqlNode> contents) {<!-- -->
    this.contents = contents;
  }
  
  public boolean apply(DynamicContext context) {<!-- -->
    for (SqlNode sqlNode : contents) {<!-- -->
      sqlNode.apply(context);
    }
    return true;
  }
  
  // other

Method omitted...
}

In the apply method, MixedSqlNode will sequentially apply each child node to the DynamicContext context.

Source code analysis

The above is a brief introduction to the processing process and implementation principle of dynamic SQL. Next, we will analyze the source code to understand it in depth.

Let’s take parsing the if tag as an example to trace the calling process of the source code:

  1. The parseDynamicTags method of the XMLScriptBuilder class parses dynamic tags;
  2. In the parseDynamicTags method, create the IfSqlNode object through the createSqlNode method;
  3. The apply method of the IfSqlNode object calls the evaluateBoolean method of the ExpressionEvaluator object to judge the condition;
  4. If the condition is true, apply the contents of the IfSqlNode object to the DynamicContext context;
  5. The apply method of the MixedSqlNode class applies the child node to the DynamicContext context;
  6. Additional dynamic tags are processed recursively until the final SQL statement is generated.

Through the analysis of the source code, we can have a clearer understanding of the processing and implementation principles of dynamic SQL.

Summary

In this article, we explained in detail the processing and implementation principles of dynamic SQL in MyBatis. Dynamic SQL is a powerful feature of MyBatis. Through the flexible use of dynamic labels and functions, different SQL statements can be generated according to different conditions to achieve flexible query and update operations.

By analyzing the source code, we have a deep understanding of the dynamic SQL parsing process and the implementation of key classes. The SqlNode interface and the DynamicContext class are the core of dynamic SQL processing. They work together to realize the parsing and generation of dynamic SQL.

After mastering the processing and implementation principles of dynamic SQL, we can use MyBatis more flexibly for database operations, improving development efficiency and code quality.

Source code download URL

  • MyBatis official website: https://mybatis.org/
  • MyBatis GitHub repository: https://github.com/mybatis/mybatis-3

You can download the latest MyBatis source code from the official website or GitHub repository for learning and research.

The above is the content of this article, hoping to help readers understand the processing of dynamic SQL in MyBatis. If you have any questions or suggestions, please leave a message for discussion. thanks for reading!

【Reference source code】

  1. org.apache.ibatis.scripting.xmltags.SqlNode
  2. org.apache.ibatis.scripting.xmltags.DynamicContext
  3. org.apache.ibatis.scripting.xmltags.IfSqlNode
  4. org.apache.ibatis.scripting.xmltags.MixedSqlNode
  5. org.apache.ibatis.builder.xml.XMLScriptBuilder
  6. org.apache.ibatis.scripting.xmltags.ExpressionEvaluator