mybatis-plus/mybatis 自定义 sql 语句、动态 sql

每一个成功人士的背后,必定曾经做出过勇敢而又孤独的决定。

放弃不难,但坚持很酷~

Java 开发使用 mybatis-plus 来执行 sql 操作,往往比 mybatis 能够省时省力,因为 mybatis-plus 封装了很多常用的接口。但对于一些更为复杂的查询来说,mybatis-plus 也相形见绌,还得需要我们自定义 sql 语句。本文就来介绍一下在使用了 mybatis-plus/mybatis 的情况下,如何自定义 sql 语句、动态 sql 等。

一、准备工作

MyBatis-Plus(简称 MP)是一个 MyBatis 的增强工具,在 MyBatis 的基础上只做增强不做改变,为简化开发、提高效率而生。在 Java 项目内,配置如下:

1、添加 pom 依赖
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.2.0</version>
</dependency>
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.17</version>
</dependency>
<!-- 免写getter/setter等方法,使用注解自动搞定 -->
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>
2、修改配置文件
spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://localhost:3306/spring_boot_study?allowMultiQueries=true&useUnicode=true&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=Asia/Shanghai&characterEncoding=utf8
    username: root
    password: mycat123

mybatis-plus:
  # 自定义xml文件路径
  mapper-locations: classpath:/mapper/*Mapper.xml
  # 自定义xml文件中用到的实体类路径
  type-aliases-package: com.study.spring.entity
  configuration:
    # 开启驼峰映射
    map-underscore-to-camel-case: true
    cache-enabled: false
    # 返回map时,true:当查询数据为空时字段返回为null;false:不加这个查询数据为空时,字段将被隐藏
    call-setters-on-nulls: true
    # sql日志打印
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

其中 spring.datasource.url 的某些参数说明如下:

  • useUnicode:是否使用 Unicode 字符集,如果需要指定编码,则本参数值必须设置为 true 。

  • characterEncoding:当 useUnicode 设置为 true 时,指定字符编码。比如可设置为 utf8 。

  • serverTimezone:指定 mysql 的时区,默认是 UTC ,与北京时间相差八个小时。平时使用时可设置为 GMT%2B8 或 Asia/Shanghai 。

二、自定义 sql

自定义 sql 分为两种,一种是注解类型,一种是自定义 xml 类型。

1、注解类型

注解类型比较简单,在 mapper 层的接口类方法上使用 @Select、@Update、@Insert、@Delete 等注解并加上自定义的 sql 语句,即可代表 查询、更新、存储、删除 等操作。如下图所示:

虽然使用注解类型也可以实现动态 sql 的写法,但总归是太乱了,没有自定义 xml 类型条理清晰。接下来介绍自定义 xml 类型的写法。

2、自定义 xml 类型

由于配置文件内 mybatis-plus.mapper-locations 定义的 xml 文件路径是:classpath:/mapper/*Mapper.xml 。所以需要先创建 resources/mapper 目录,在这里面创建 xxxMapper.xml ,来自定义 sql 语句。

  • select – 映射查询语句

  • insert – 映射插入语句

  • update – 映射更新语句

  • delete – 映射删除语句

1)首先要指定 mapper 接口文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">

<mapper namespace="com.study.spring.mapper.NovelMapper">
    ...
</mapper>

这样该 xml 文件就与 NovelMapper.java 这个接口类绑定了。接口类里面的方法名与下文 xml 文件里面的 id 值一一对应。

2)自定义查询 sql
<select id="findMaxId" resultType="Integer">
    select
    max(id) maxId
    from
    novel_type
</select>

id 为接口类里面的方法名;resultType 指定 sql 返回的结果类型。

3)动态查询 sql

动态查询 sql 通常会使用 <where> 和 <if> 标签。

where 元素只会在至少有一个子元素的条件返回 SQL 子句的情况下才去插入 “WHERE” 子句。而且,若语句的开头为 “AND” 或 “OR”,where 元素也会将它们去除。

使用 <if> 标签来判断查询字段是否符合查询条件。<if> 标签里面的 test 为判断语句。

xml 里面的变量用 #{} 表示。下面的查询语句的参数类型是 hashmap,参数可直接用 key 值表示。如果接口方法参数里面使用了 @Param("xxx"),则 xml 里面的参数也要加上 xxx。比如:#{xxx.dl},其中 dl 是 hashmap 的 key 。

<select id="getDownloadList" resultType="com.study.spring.entity.NovelEntity" parameterType="hashmap">
    select
    id, download, introduce, novelauthor, novelname, type
    from
    novel_type
    <where>
        <if test="query.dl != null and query.dl != ''">
            download = #{query.dl}
        </if>
        <if test="query.nu != null and query.nu != ''">
            and novelauthor = #{query.nu}
        </if>
    </where>
</select>

还有一个知识点要说一下:<resultMap> ,定义 <resultMap> 可以解决类的属性名和数据库列名不一致的问题。

比如我将 NovelEntity 实体类的 novelAuthor 属性修改为 novel_author,这时,返回的 novel_author 字段是接收不到 sql 查询的 novelauthor 值的。但我们可以用 <resultMap> 来解决这种不一致的问题。

<!-- 定义的resultMap,可以解决类的属性名和数据库列名不一致的问题-->
<!-- type值为实体类 -->
<resultMap type="NovelEntity" id="getDownloadList">
    <!-- property值为实体类属性,column值为数据库表字段 -->
    <result property="novel_author" column="novelauthor"/>
</resultMap>

<!-- 用 resultMap 代替 resultType -->
<select id="getDownloadList" resultMap="getDownloadList" parameterType="map">
    select
        id, download, introduce, novelauthor, novelname, type
    from
        novel_type
    where
        download = #{query.dl}
</select>
4)动态插入 sql
<!-- if标签内的判断条件是NovelEntity里面的属性,而不是表字段-->
<insert id="saveNovel" parameterType="com.study.spring.entity.NovelEntity">
    insert into novel_type(
    download
    <if test="introduce != null and introduce != ''">
        ,introduce
    </if>
    <if test="novelAuthor !=null and novelAuthor != ''">
        ,novelauthor
    </if>
    <if test="novelName != null and novelName != ''">
        ,novelname
    </if>
    <if test="type != null and type != ''">
        ,type
    </if>
    )
    values (
    #{download}
    <if test="introduce != null and introduce != ''">
        ,#{introduce}
    </if>
    <if test="novelAuthor !=null and novelAuthor != ''">
        ,#{novelAuthor}
    </if>
    <if test="novelName != null and novelName != ''">
        ,#{novelName}
    </if>
    <if test="type != null and type != ''">
        ,#{type}
    </if>
    )

</insert>
5)动态更新 sql

假如当只有 novel_author 参数有值,<set> 标签会将 <if> 标签内的 逗号 隐藏,不会使 sql 语句报错。set 元素会动态前置 SET 关键字,同时也会删掉无关的逗号

<update id="updateNovelByName" parameterType="com.study.spring.entity.NovelEntity">
    update novel_type
    <set>
        <if test="download != null and download != ''">
            download = #{download},
        </if>
        <if test="introduce != null and introduce != ''">
            introduce = #{introduce},
        </if>
        <if test="novel_author !=null and novel_author != ''">
            novelauthor = #{novel_author},
        </if>
        <if test="type != null and type != ''">
            type = #{type}
        </if>
    </set>
    where
    novelName = #{novelName}
</update>
6)动态删除 sql
<delete id="deleteNoveBy" parameterType="com.study.spring.entity.NovelEntity">
    DELETE FROM novel_type
    <where>
        <if test="download != null and download != ''">
            download = #{download}
        </if>
        <if test="introduce != null and introduce != ''">
            and introduce = #{introduce}
        </if>
        <if test="novel_author !=null and novel_author != ''">
            and novelauthor = #{novel_author}
        </if>
        <if test="type != null and type != ''">
            and type = #{type}
        </if>
        <if test="novelName != null and novelName != ''">
            and novelName = #{novelName}
        </if>
    </where>
</delete>
三、参考资料
  • https://mybatis.org/mybatis-3/zh/dynamic-sql.html

  • https://www.cnblogs.com/rollenholt/p/3365866.html

  • https://mybatis.org/mybatis-3/zh/sqlmap-xml.html

自定义 sql 语句、动态 sql,其实还是用的 mybatis 的那套东西,mybatis-plus 只是将 mybatis 的某些部分又封装了一遍,简便了平时开发。

以上描述的两种自定义 增删改查 SQL 类型在工作中很常用,之所以整理,也是为了系统地了解、测试一遍,希望也能对大家有帮助!


 热 文 推 荐 

☞ Spring IOC,看完这篇文章,我才算是懂了!

☞ Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

☞ Spring 中如何使用 @Scheduled 创建定时任务

☞ Git使用教程:最详细、最傻瓜、最浅显、真正手把手教!

☞ 程序员如何保持竞争力

☞ 看完这篇文章还不会给spring boot配置logback,请你吃瓜!

☞ Kylin配置Spark并构建Cube(修订版)

☞ 看完您如果还不明白 Kerberos 原理,算我输!


???? ???? ????

欢迎大家留言讨论

???? ???? ????

你点的每个“在看”,我都认真当成了喜欢
MyBatis-Plus中配置自定义SQL插入语句通常可以通过实现`IsqlInjector`接口来自定义SQL片段,然后在Mapper接口中使用自定义SQL语句进行插入操作。以下是基本步骤: 1. 创建一个自定义的`IsqlInjector`实现类,该类继承自`DefaultSqlInjector`。在该类中重写`inspectInject`方法,添加自定义SQL注入器。 ```java public class CustomSqlInjector extends DefaultSqlInjector { @Override public List<AbstractMethod> getMethodList(Class<?> mapperClass) { List<AbstractMethod> methodList = super.getMethodList(mapperClass); // 添加自定义的插入方法 methodList.add(new InsertBatchSomeColumn()); return methodList; } } ``` 2. 在自定义的`AbstractMethod`实现类中,重写`InjectMappedStatement`方法,用于定义自定义的插入SQL语句。 ```java public class InsertBatchSomeColumn extends AbstractMethod { @Override public MappedStatement injectMappedStatement(Class<?> mapperClass, Class<?> modelClass, TableInfo tableInfo) { // 自定义SQL逻辑 String sql = "INSERT INTO " + tableInfo.getTableName() + " (<foreach collection=\"list\" item=\"item\" index=\"index\" separator=\",\" >" + " <if test=\"item.column1 != null\">column1,</if>" + " <if test=\"item.column2 != null\">column2,</if>" + "</foreach>) VALUES " + " <foreach collection=\"list\" item=\"item\" index=\"index\" open=\"(\" separator=\",\" close=\")\"> " + " <if test=\"item.column1 != null\">#{item.column1},</if>" + " <if test=\"item.column2 != null\">#{item.column2},</if>" + "</foreach>"; // 获取列名和值 // ... // 注入MappedStatement // ... return new MappedStatement(); } } ``` 3. 在MyBatis的配置文件中,将`CustomSqlInjector`设置为自定义SQL注入器。 ```xml <bean id="sqlSessionFactory" class="com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean"> <!-- 其他配置项 --> <!-- 自定义SQL注入器 --> <property name="sqlInjector" ref="customSqlInjector" /> </bean> <bean id="customSqlInjector" class="你的包名.CustomSqlInjector"></bean> ``` 4. 在Mapper接口中使用自定义的插入方法。 ```java public interface YourMapper extends BaseMapper<YourEntity> { // 使用自定义的插入方法 int insertBatchSomeColumn(List<YourEntity> list); } ``` 这样配置后,就可以使用自定义的`insertBatchSomeColumn`方法进行批量插入操作了。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

create17

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值