【JavaEE】Mybatis 动态SQL

发布于:2025-03-29 ⋅ 阅读:(24) ⋅ 点赞:(0)


Mybatis动态SQL官方文档:Mybatis动态SQL官方文档

一、 if 标签

在我们的数据库表中有些字段不是必须要填的,数据库可以在不填的时候自动帮我们赋值。
那如果在添加⽤⼾的时候有不确定的字段传⼊,程序应该如何实现呢,这时候就需要动态SQL来实现。

if 标签就跟 if 语句一样,满足条件执行标签里面的内容。

    <insert id="insertOne1">
        insert into user_info (username, password, age 
                               <if test="gender != null">
                                   ,gender
                               </if>
                                ) values (#{username},#{password},#{age}
                                          <if test="gender != null">
                                              ,#{gender}
                                          </if>
                                          )
    </insert>

测试方法:

    @Test
    void insertOne1() {
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(13);
        userInfo.setPassword("1313");
        userInfo.setUsername("1313");
        userInfo.setGender(null);
        Integer result = userMapperXML.insertOne1(userInfo);
        System.out.println("增加函数:"+ result+", 增加数据的id:"+userInfo.getId());
    }

结果:

可以看到结果中匹配的SQL语句中并没有gender字段。
注意事项:

  • if 标签中test属性就相当于判断条件,里面的内容必须是java类的属性名,不能是字段名。
  • 在使用插入语句时,一定要注意values前后对应字段都要有if标签,否则在不满足if条件的时候,前后字段数量就不对应了。
  • 使用注解直接在上面的SQL语句加上script标签放入注解。

二、 trim标签

在上面的 if 标签里面我们有可能写出下面的代码:

    <insert id="insertOne1">
        insert into user_info (
        <if test="gender != null">
            age
		</if>
        
		<if test="gender != null">
			,gender
		</if>
       ) values (
        		 <if test="gender != null">
                 	#{age}
	              </if>
                 <if test="gender != null">
                 	,#{gender}
	              </if>
        )
    </insert>

这样的代码,我们无法在age不满足,gender满足的条件下去掉逗号,这会导致这种情况下SQL语句错误。
这种时候就需要 trim 标签了。
trim 标签中有如下属性:

  • prefix:表⽰整个语句块,以prefix的值作为前缀
  • suffix:表⽰整个语句块,以suffix的值作为后缀
  • prefixOverrides:表⽰整个语句块要去除掉的前缀
  • suffixOverrides:表⽰整个语句块要去除掉的后缀
    <insert id="insertOne2">
        insert into user_info
            <trim prefix="(" suffix=")" suffixOverrides=",">
            username, password,
                <if test="age != null">
                    age,
                </if>
                <if test="gender != null">
                    lgender
                </if>

            </trim>
        values
        <trim prefix="(" suffix=")" suffixOverrides=",">
            #{username},#{password},
            <if test="age != null">
                         #{age},
                     </if>
                     <if test="gender != null">
                         #{gender}
                     </if>

                 </trim>
    </insert>

测试方法:

    @Test
    void insertOne2() {
        UserInfo userInfo = new UserInfo();
        userInfo.setAge(13);
        userInfo.setPassword("1313");
        userInfo.setUsername("1313");
        userInfo.setGender(null);
        Integer result = userMapperXML.insertOne2(userInfo);
        System.out.println("增加函数:"+ result);
    }

结果:

三、 where标签

当我们使用条件查询的时候,有以下SQl语句的时候。

select * Ffrom user_info where gender = 1 and phone = 0

我们需要根据传入的参数来进行条件查询,我们的xml文件写的如下:

    <select id="selectWhere" resultType="com.example.springmybatisdemo.model.UserInfo">
        select * from user_info where
        
            <if test="gender != null">
                gender = #{gender}
            </if>
             <if test="phone != null">
                    and phone = #{phone}
            </if>
    
    </select>

但是我们可以预料到,当gender不符合 if 条件,phone符合条件和两个都不符合条件时的SQl语句是一定会错的。

这个时候就需要使用到where标签了。

  • where 标签 只会在⼦元素有内容的情况下才插⼊where⼦句,⽽且会⾃动去除⼦句的开头的 and 或 or
    <select id="selectWhere" resultType="com.example.springmybatisdemo.model.UserInfo">
        select * from user_info
        <where>
            <if test="gender != null">
                and gender = #{gender}
            </if>
             <if test="phone != null">
                    and phone = #{phone}
            </if>
        </where>
    </select>

测试方法:

    @Test
    void selectWhere() {
        UserInfo userInfo = new UserInfo();
        userInfo.setGender(1);
        //userInfo.setPhone("0");
        userMapperXML.selectWhere(userInfo);
    }

结果:

四、 set标签

当我们使用update - set进行更新操作的时候。
我们有以下的SQL语句:

update user_info 
set username = 'username', password = 'password' , gender = 'gender' where id = 11

转化成xml文件如下:

    <update id="updateTwo">
        update user_info set 
            <if test="username != null">
                username = #{username}
            </if>
            <if test="password != null">
                ,password = #{password}
            </if>
            <if test="gender != null">
                ,gender = #{gender}
            </if>
        where id = #{id}
    </update>

可以看出当我们的username 不符合条件的时候,会在set后面多出一个逗号,让我们SQL语法错误。

  • set 标签动态的在SQL语句中插⼊set关键字,并会删掉额外的逗号. (⽤于update语句中)
    <update id="updateTwo">
        update user_info
        <set>
            <if test="username != null">
                username = #{username}
            </if>
            <if test="password != null">
                ,password = #{password}
            </if>
            <if test="gender != null">
                ,gender = #{gender}
            </if>
        </set>
        where id = #{id}
    </update>

测试方法:

@Test
    void updateTwo() {
        UserInfo userInfo = new UserInfo();
        userInfo.setId(13);
        userInfo.setPassword("6666");
        //userInfo.setUsername("6666");
        userInfo.setGender(1);
        Integer result = userMapperXML.updateTwo(userInfo);
    }

结果:

五、foreach标签

当我们要使用批量增删改查的时候,例如下面的SQL语句:

select * from user_info where id in (1,2,3)

select * from user_info where id = 1 or id = 2 or id = 3 
# <foreach collection="ids" item="id" separator="or">
# 	id = #{id}
# </foreach>

select * from user_info where (username ,password) in 
( ('admin','admin'),('zhangsan','zhangsan'),('lisi','lisi'))
# <foreach collection="userInfos" item="userInfo" separator=",">
# 	(#{userInfo.username}, #{userInfo.password})
# </foreach>

我们转换成xml文件,就需要使用 foreach 标签。
foreach 标签有如下属性:

  • collection:绑定⽅法参数中的集合,如 List,Set,Map或数组对象
  • item:遍历时的每⼀个对象
  • open:语句块开头的字符串
  • close:语句块结束的字符串
  • separator:每次遍历之间间隔的字符串

如第一个SQL语句的xml文件如下:

    <select id="selectEach" resultType="com.example.springmybatisdemo.model.UserInfo">
        select * from user_info where id in
        <foreach collection="ids" open="(" close=")" item="id" separator=",">
            #{id}
        </foreach>
    </select>

测试代码:

    @Test
    void selectEach() {
        List<Integer> ids = new ArrayList<>();
        ids.add(1);
        ids.add(2);
        ids.add(3);
        userMapperXML.selectEach(ids);
    }

结果:

六、include标签和sql标签

当我们的代码中有很多重复片段时,可以对重复的代码⽚段进⾏抽取,将其通过 sql 标签封装到⼀个SQL⽚段,然后再通过 include 标签进⾏引⽤。

  • sql 标签 定义可重⽤的SQL⽚段
  • include 标签通过属性refid,指定包含的SQL⽚段
    <sql id="sqlSelect">
        select * from
    </sql>
    <select id="selectAll" resultType="com.example.springmybatisdemo.model.UserInfo" resultMap="UserMap">
        <include refid="sqlSelect"></include>
        user_info
    </select>

测试方法:

    @Test
    void selectAll() {
        System.out.println(userMapperXML.selectAll());
    }

结果

MyBatis generator插件

MyBatis generator官方文档:MyBatis generator官方文档
引入依赖:

<plugin>
                <groupId>org.mybatis.generator</groupId>
                <artifactId>mybatis-generator-maven-plugin</artifactId>
                <version>1.3.6</version>
                <executions>
                    <execution>
                        <id>Generate MyBatis Artifacts</id>
                        <phase>deploy</phase>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                    </execution>
                </executions>
                <configuration>
                    <!--generator配置⽂件所在位置-->

                    <configurationFile>src/main/resources/mybatisGenerator/generatorConfig.xml</con
                            figurationFile>
                    <!-- 允许覆盖⽣成的⽂件, mapxml不会覆盖, 采⽤追加的⽅式-->
                    <overwrite>true</overwrite>
                    <verbose>true</verbose>
                    <!--将当前pom的依赖项添加到⽣成器的类路径中-->
                    <includeCompileDependencies>true</includeCompileDependencies>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>mysql</groupId>
                        <artifactId>mysql-connector-java</artifactId>
                        <version>8.0.33</version>
                    </dependency>
                </dependencies>

            </plugin>

引入xml文件配置:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE generatorConfiguration
        PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN"
        "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd">
<!-- 配置生成器 -->
<generatorConfiguration>

    <!-- 一个数据库一个context -->
    <context id="MysqlTables" targetRuntime="MyBatis3Simple" defaultModelType="flat">
        <!--去除注释-->
        <commentGenerator>
            <property name="suppressDate" value="true"/>
            <property name="suppressAllComments" value="true" />
        </commentGenerator>

        <!--数据库链接信息-->
        <jdbcConnection driverClass="com.mysql.jdbc.Driver"
                        connectionURL="jdbc:mysql://127.0.0.1:3306/java_blog_spring?serverTimezone=Asia/Shanghai&amp;nullCatalogMeansCurrent=true"
                        userId="root"
                        password="root">
        </jdbcConnection>

        <!-- 生成实体类 -->
        <javaModelGenerator targetPackage="com.example.demo.model" targetProject="src/main/java" >
            <property name="enableSubPackages" value="false"/>
            <property name="trimStrings" value="true"/>
        </javaModelGenerator>
        <!-- 生成mapxml文件 -->
        <sqlMapGenerator targetPackage="mapper" targetProject="src/main/resources" >
            <property name="enableSubPackages" value="false" />
        </sqlMapGenerator>
        <!-- 生成mapxml对应client,也就是接口dao -->
        <javaClientGenerator targetPackage="com.example.demo.mapper" targetProject="src/main/java" type="XMLMAPPER" >
            <property name="enableSubPackages" value="false" />
        </javaClientGenerator>
        <!-- table可以有多个,每个数据库中的表都可以写一个table,tableName表示要匹配的数据库表,也可以在tableName属性中通过使用%通配符来匹配所有数据库表,只有匹配的表才会自动生成文件 -->
        <table tableName="user">
            <property name="useActualColumnNames" value="false" />
            <!-- 数据库表主键 -->
            <generatedKey column="id" sqlStatement="Mysql" identity="true" />
        </table>
    </context>
</generatorConfiguration>

保持pom文件与xml文件中的路径名称一致。

  • 记得在xml文件中修改要使用的数据库,以及密码。
  • 实体类的路径
  • Mapper的路径
  • 操作的表名

在双击插件即可生成:

要想生成动态sql语句,直接将xml配置 中的Simple去掉即可。