关于MyBatis动态元素与Where 1=1的作用

在工作中有时候会用到动态SQL标签,此处写明一些关于以前用的少的动态标签详解与用处。

以下详情请查看·:https://www.hxstrive.com/subject/mybatis/231.htm

关于Mybatis的SQL动态标签之Where 元素

如果我们有下面一个示例:

复制代码
 1 <select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
 2     SELECT * FROM BLOG
 3     WHERE
 4     <if test="state != null">
 5         state = #{state}
 6     </if>
 7     <if test="title != null">
 8         AND title like #{title}
 9     </if>
10     <if test="author != null and author.name != null">
11         AND title like #{author.name}
12     </if>
13 </select>
复制代码

 如果这些条件都没有匹配上将会发生什么?这条 SQL 结束时就会成这样:

1 SELECT * FROM BLOG
2 WHERE

这会导致查询失败。如果仅仅第二个条件匹配是什么样的?这条 SQL 结束时就会是这样:

1 SELECT * FROM BLOG
2 WHERE
3 AND title like "someTitle"

这个查询也会失败。这个问题不能简单的用条件来解决,如果你从来没有这样写过,那么你以后也不会这样来写。

MyBatis 有一个简单的处理,这在 90%的情况下都会有用。而在不能使用的地方,你可以自定义处理方式。加上一个简单的改变,所有事情都会顺利进行:

复制代码
 1 <select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
 2     SELECT * FROM BLOG
 3     <where>
 4         <if test="state != null">
 5             state = #{state}
 6         </if>
 7         <if test="title != null">
 8             AND title like #{title}
 9         </if>
10         <if test="author != null and author.name != null">
11             AND title like #{author.name}
12         </if>
13     </where>
14 </select>
复制代码

<where> 元素知道如果由被包含的标记(如:<if>标签)返回了任意内容,则<where>标签仅仅插入“WHERE”字符串。如果 <where> 标签包含的标签的内容以“AND”或“ OR”开头的内容,那么 MyBatis 会将 where 后面紧接的 <if> 标签的内容前面的 AND 和 OR 移除。

示例代码

(1)MyBatis 配置文件 mybatis-cfg.xml 内容如下:

复制代码
 1 <?xml version="1.0" encoding="UTF-8" ?>
 2 <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
 3   "http://mybatis.org/dtd/mybatis-3-config.dtd">
 4 <configuration>
 5     <properties resource="database.properties"/>
 6     <environments default="MySqlDatabase" >
 7         <environment id="MySqlDatabase" >
 8             <transactionManager type="JDBC" />
 9             <dataSource type="POOLED">
10                 <property name="driver" value="${jdbc.driver}"/>
11                 <property name="url" value="${jdbc.url}"/>
12                 <property name="username" value="${jdbc.username}"/>
13                 <property name="password" value="${jdbc.password}"/>
14             </dataSource>
15         </environment>
16     </environments>
17     <mappers>
18         <mapper resource="com/hxstrive/mybatis/dynamic_sql/demo3/UserMapper.xml" />
19     </mappers>
20 </configuration>
复制代码

(2)Java 实体Bean UserBean.java,代码如下:

复制代码
 1 package com.hxstrive.mybatis.dynamic_sql.demo3;
 2  
 3 public class UserBean {
 4    private Integer userId;
 5    private String name;
 6    private String sex;
 7    private Integer age;
 8    // 忽略 getter 和 setter
 9    @Override
10    public String toString() {
11       return "UserBean{" +
12             "userId=" + userId +
13             ", name='" + name + '\'' +
14             ", sex='" + sex + '\'' +
15             ", age=" + age +
16             '}';
17    }
18 }
复制代码

(3)定义 Mapper 文件

a、UserMapper.java

复制代码
1 package com.hxstrive.mybatis.dynamic_sql.demo3;
2  
3 import org.apache.ibatis.annotations.Param;
4 import java.util.List;
5  
6 public interface UserMapper {
7    List<UserBean> getUserList(@Param("username") String username, @Param("userId") int userId);
8 }
复制代码

b、UserMapper.xml

复制代码
 1 <?xml version="1.0" encoding="UTF-8"?>
 2 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
 3    "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
 4 <mapper namespace="com.hxstrive.mybatis.dynamic_sql.demo3.UserMapper">
 5    <!-- 映射结果 -->
 6    <resultMap id="RESULT_MAP" type="com.hxstrive.mybatis.dynamic_sql.demo3.UserBean">
 7       <id column="user_id" jdbcType="INTEGER" property="userId" />
 8       <result column="name" jdbcType="VARCHAR" property="name" />
 9       <result column="sex" jdbcType="VARCHAR" property="sex" />
10       <result column="age" jdbcType="INTEGER" property="age" />
11    </resultMap>
12  
13    <!-- 动态添加 where 条件 -->
14    <select id="getUserList" resultMap="RESULT_MAP">
15       select `user_id`, `name`, `age`, `sex` from `user`
16       <where>
17          <if test="username != null and username != ''">
18             and `name` like #{username}
19          </if>
20          <if test="userId > 0">
21             and `user_id`=#{userId}
22          </if>
23       </where>
24    </select>
25  
26 </mapper>
复制代码

(4)客户端代码如下:

复制代码
 1 package com.hxstrive.mybatis.dynamic_sql.demo3;
 2  
 3 import org.apache.ibatis.io.Resources;
 4 import org.apache.ibatis.session.SqlSession;
 5 import org.apache.ibatis.session.SqlSessionFactory;
 6 import org.apache.ibatis.session.SqlSessionFactoryBuilder;
 7 import java.io.InputStream;
 8 import java.util.List;
 9  
10 public class DynamicSqlDemo {
11  
12    public static void main(String[] args) throws Exception {
13       String cfgName = "com/hxstrive/mybatis/dynamic_sql/demo3/mybatis-cfg.xml";
14       InputStream input = Resources.getResourceAsStream(cfgName);
15       SqlSessionFactoryBuilder factoryBuilder = new SqlSessionFactoryBuilder();
16       SqlSessionFactory sqlFactory = factoryBuilder.build(input);
17       getUserList(sqlFactory);
18    }
19  
20    private static void getUserList(SqlSessionFactory sqlFactory) {
21       SqlSession sqlSession = sqlFactory.openSession(true);
22       UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
23       List<UserBean> userBeanList = userMapper.getUserList(null, 1);
24       for(UserBean userBean : userBeanList) {
25          System.out.println(userBean);
26       }
27    }
28  
29 }
复制代码

运行客户端代码,输出结果如下:

复制代码
 1 2020-09-10 22:07:51,251 DEBUG [org.apache.ibatis.logging.LogFactory] - Logging initialized using 'class org.apache.ibatis.logging.slf4j.Slf4jImpl' adapter.
 2 2020-09-10 22:07:51,292 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
 3 2020-09-10 22:07:51,292 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
 4 2020-09-10 22:07:51,292 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
 5 2020-09-10 22:07:51,292 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - PooledDataSource forcefully closed/removed all connections.
 6 2020-09-10 22:07:51,511 DEBUG [org.apache.ibatis.transaction.jdbc.JdbcTransaction] - Opening JDBC Connection
 7 2020-09-10 22:07:51,959 DEBUG [org.apache.ibatis.datasource.pooled.PooledDataSource] - Created connection 1297149880.
 8 2020-09-10 22:07:51,962 DEBUG [com.hxstrive.mybatis.dynamic_sql.demo3.UserMapper.getUserList] - ooo Using Connection [com.mysql.jdbc.JDBC4Connection@4d50efb8]
 9 2020-09-10 22:07:51,963 DEBUG [com.hxstrive.mybatis.dynamic_sql.demo3.UserMapper.getUserList] - ==>  Preparing: select `user_id`, `name`, `age`, `sex` from `user` WHERE `user_id`=? 
10 2020-09-10 22:07:52,023 DEBUG [com.hxstrive.mybatis.dynamic_sql.demo3.UserMapper.getUserList] - ==> Parameters: 1(Integer)
11 2020-09-10 22:07:52,063 DEBUG [com.hxstrive.mybatis.dynamic_sql.demo3.UserMapper.getUserList] - <==      Total: 1
12 UserBean{userId=1, name='赫仑', sex='男', age=27}
复制代码

上面示例中,执行 getUserList 时,参数 username=null,userId=1,将返回如下 SQL 语句:

1 select `user_id`, `name`, `age`, `sex` from `user` WHERE `user_id`=?

 按照上面 Mapper xml 的定义,如果 userId 大于 0,则输出 “and `user_id`=#{userId}”,与其他 SQL 语句拼接在一起,则应该如下:

1 select `user_id`, `name`, `age`, `sex` from `user`
2 where
3 and `user_id`=#{userId}

上面 SQL 是有问题的。但是,MySQL 自动将 “where and `user_id`=#{userId}”之前的 and 去除掉了。也就导致上面示例运行成功了!!

 

除了以上方法以外也可不用Where元素标签,增加Where 1 = 1语句,如:

复制代码
 1 <select id="findActiveBlogLike" parameterType="Blog" resultType="Blog">
 2     SELECT * FROM BLOG
 3     WHERE 1 = 1
 4     <if test="state != null">
 5       AND state = #{state}
 6     </if>
 7     <if test="title != null">
 8         AND title like #{title}
 9     </if>
10     <if test="author != null and author.name != null">
11         AND title like #{author.name}
12     </if>
13 </select>
复制代码

尚且不清Where 1 = 1的效率,与Where标签的效率哪个高,这里以后在做讨论

posted @   无火祭祀场  阅读(199)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
点击右上角即可分享
微信分享提示