1. 什么是 SqlNode ?
SqlNode 是Mybatis源码里面的一种业务模型,他用来描述我们写在xml文件里面的动态SQL语句。
下面用一个SQL语句举例子
<select id="selectUser" resultType="com.hdu.User">
select * from users
<where>
<if test="id != null">
and id = #{id}
</if>
<if test="name != null">
and name = #{name}
</if>
<if test="age != null">
and age = #{age}
</if>
</where>
</select>
2. 代码示例
StaticTextSqlNode
@Test
public void testStaticTextSqlNode() {
StaticTextSqlNode staticTextSqlNode = new StaticTextSqlNode("select * from user");
DynamicContext context = new DynamicContext(configuration, null);
staticTextSqlNode.apply(
context
);
System.out.println(context.getSql());
/**
* select * from user
*/
}
内部实现:
@Override
public boolean apply(DynamicContext context) {
// 直接执行拼接操作
context.appendSql(text);
return true;
}
TextNode
@Test
public void testTrimSqlNode() {
TextSqlNode textSqlNode = new TextSqlNode("select * from ${table_name}");
Map<String, String> params = new HashMap<>();
params.put("table_name", "testTable1");
DynamicContext context = new DynamicContext(configuration, params);
textSqlNode.apply(
context
);
System.out.println(context.getSql());
/**
* select * from testTable1
*/
}
IfSqlNode
IfSqlNode 就对应 xml 里面的 if 标签
@Test
@Test
public void testIfSqlNode() {
User user = new User();
user.setId("1");
MixedSqlNode finalSqlNode = new MixedSqlNode(Arrays.asList(
new StaticTextSqlNode("select * from user"),
new IfSqlNode(new StaticTextSqlNode("id = #{id}"), "id != null")
));
DynamicContext context = new DynamicContext(configuration, user);
finalSqlNode.apply(context);
System.out.println(context.getSql());
/**
* select * from user id = #{id}
*/
}
内部实现:
@Override
public boolean apply(DynamicContext context) {
// 会先判断给定的 test 表达式是否成立, 如果成立 执行 拼接 sql操作
// id != null
if (evaluator.evaluateBoolean(test, context.getBindings())) {
// 执行拼接操作 拼接 id = ?
contents.apply(context);
return true;
}
return false;
}
WhereSqlNode
@Test
public void testWhereSqlNode() {
User user = new User();
user.setId("1");
user.setName("张三");
StaticTextSqlNode staticTextSqlNode = new StaticTextSqlNode("select * from user");
IfSqlNode idIfSqlNode = new IfSqlNode(new StaticTextSqlNode(" and id = #{id}"), "id != null");
IfSqlNode nameIfSqlNode = new IfSqlNode(new StaticTextSqlNode(" and name = #{name}"), "name != null");
MixedSqlNode mixedSqlNode = new MixedSqlNode(Arrays.asList(idIfSqlNode, nameIfSqlNode));
WhereSqlNode whereSqlNode = new WhereSqlNode(configuration, mixedSqlNode);
MixedSqlNode finalSqlNode = new MixedSqlNode(Arrays.asList(staticTextSqlNode, whereSqlNode));
DynamicContext context = new DynamicContext(configuration, user);
finalSqlNode.apply(
context
);
System.out.println(context.getSql());
/**
* select * from user WHERE id = #{id} and name = #{name}
*/
}
内部实现:
@Override
public boolean apply(DynamicContext context) {
// 先将SQL暂存
FilteredDynamicContext filteredDynamicContext = new FilteredDynamicContext(context);
// 执行 WhereSqlNode的逻辑,得到的sql先暂存到 filteredDynamicContext
boolean result = contents.apply(filteredDynamicContext);
// 对最终的sql进行一些修剪操作,比如删除多余的 AND, 开头添加一个 WHERE
filteredDynamicContext.applyAll();
return result;
}
ForEachSqlNode
@Test
public void forEachTest() {
Map<Object, Object> params = new HashMap<>();
params.put("list", Arrays.asList(1, 2, 3, 4, 5));
DynamicContext context = new DynamicContext(configuration, params);
new StaticTextSqlNode("select * from user where id in").apply(context);
ForEachSqlNode forEachSqlNode = new ForEachSqlNode(
configuration,
new StaticTextSqlNode("#{item}"),
"list",
null,
"item",
null,
"(",
")",
","
);
forEachSqlNode.apply(context);
System.out.println(context.getSql());
/**
* select * from user where id in
* ( #{__frch_item_0} ,
* #{__frch_item_1} ,
* #{__frch_item_2} ,
* #{__frch_item_3} ,
* #{__frch_item_4}
* )
* 同时他会往变量集里面添加参数映射关系
* #{__frch_item_0} -> 1
* #{__frch_item_1} -> 2
* #{__frch_item_2} -> 3
* #{__frch_item_3} -> 4
* #{__frch_item_4} -> 5
*/
}
最终示例
@Test
public void testTotal() {
StaticTextSqlNode staticTextSqlNode = new StaticTextSqlNode("select * from user");
WhereSqlNode whereSqlNode = new WhereSqlNode
(
configuration,
new MixedSqlNode
(
Arrays.asList
(
new IfSqlNode(new StaticTextSqlNode(" and id = #{user}"), "id != null"),
new IfSqlNode(new StaticTextSqlNode(" and name = #{name}"), "name != null"),
new IfSqlNode(new StaticTextSqlNode(" and age = #{age}"), "age != null")
)
)
);
MixedSqlNode finalMixedSqlNode = new MixedSqlNode(Arrays.asList(staticTextSqlNode, whereSqlNode));
User user = new User();
user.setId("1");
user.setName("张三");
user.setAge(18);
DynamicContext context = new DynamicContext(configuration, user);
finalMixedSqlNode.apply(context);
System.out.println(context.getSql());
/**
* select * from user
* WHERE id = #{user}
* and name = #{name}
* and age = #{age}
*/
}