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:
- The
parseDynamicTags
method of theXMLScriptBuilder
class parses dynamic tags; - In the
parseDynamicTags
method, create theIfSqlNode
object through thecreateSqlNode
method; - The
apply
method of theIfSqlNode
object calls theevaluateBoolean
method of theExpressionEvaluator
object to judge the condition; - If the condition is true, apply the
contents
of theIfSqlNode
object to theDynamicContext
context; - The
apply
method of theMixedSqlNode
class applies the child node to theDynamicContext
context; - 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】
org.apache.ibatis.scripting.xmltags.SqlNode
org.apache.ibatis.scripting.xmltags.DynamicContext
org.apache.ibatis.scripting.xmltags.IfSqlNode
org.apache.ibatis.scripting.xmltags.MixedSqlNode
org.apache.ibatis.builder.xml.XMLScriptBuilder
org.apache.ibatis.scripting.xmltags.ExpressionEvaluator