Mybatis的增删改查扩展功能说明

发布时间:2023年12月28日

专栏精选

Mybatis的快速入门

引入Mybatis

摘要

在这篇文章中,我们将了解Mybatis中CRUD的操作的一些扩展用法,其中的很多观点或内容都能在一定程度上让我们的开发之旅更加轻松方便,这是一个菜鸟提升技术能力,老鸟巩固基础知识的好机会。准备好开启今天的神奇之旅了吗?

引言

大家好,我是奇迹老李,一个专注于分享开发经验和基础教程的博主。这里是我的其中一个技术分享平台,欢迎广大朋友们点赞评论提出意见,重要的是点击关注喔 🙆。今天要和大家分享的内容是Mybatis的增删改查扩展功能说明。做好准备,Let’s go🚎🚀

正文

首图

在上一篇,我们提出当时的代码存在几点问题,通过今天学习学习今天的内容我们就能够回答这几个问题,先回顾一下之前的问题

  1. xml标签中parameterTypeparameterType元素写类全名过长

  2. 列表查询和单个查询中存在重复代码

  3. 删除功能在业务上一般都是逻辑删除

  4. insert语句新增的不一定是单行数据,可能是一个数组或list列表

设置别名

我们可以通过在Mybatis配置文件中设置类的别名来简化类的引用相关的代码,即在mapper映射文件中可以通过别名代替类的全路径名来简化代码,别名的配置如下

<!-- 配置文件中新增内容 -->
<configuration>
    <properties .../>
    
	<settings>
        ...
    </settings>
    
    <!--添加别名-->
    <typeAliases>
        <!--相当于在app和top.sunyog.common.entity.AppTestEntity类之间增加了一个映射-->
        <typeAlias type="top.sunyog.common.entity.AppTestEntity" alias="app"/>
        <!--以下方式最常用-->
        <!--可以使用类文件名代替类全路径名,首字母可小写-->
        <package name="top.sunyog.my.entity"/>
    </typeAliases>
    
    <environments ...>...</environments>
    
    <mappers>...</mappers>
</configuration>

设置别名后的效果和<delete id="deleteById" parameterType="long">的效果类似,这是因为mybatis内部已经预定义了long类型的别名。可在mybatis源码的org.apache.ibatis.type.TypeAliasRegistry类中查看

sql标签用法

在java代码中,如果一段相同的代码被不同的位置反复调用,我们可以通过提取出一个方法来重构。在Mybatis中我们可以对要编辑的SQL语句进行类似的提取操作,这一操作通过 <sql>标签实现。

<mapper>
	<sql id="query_column">
        select id,app_name,app_code,auth_type,create_date,creator from app_test
    </sql>
    
    <select id="queryApp" resultMap="appTestMap">
        <!-- 引用 sql -->
        <include refid="query_column"/>
        ...
    </select>
    
    <select id="queryById" resultType="AppTestEntity">
        <!-- 引用 sql -->
        <include refid="query_column"/> 
        where id=#{id} limit 0,1
    </select>
</mapper>

逻辑删除的写法

逻辑删除就是设置删除标记,或者说修改数据状态,实际是更新操作

-- 添加数据状态字段
alter table app_test
    add app_status char default '0' not null comment '数据状态(0-正常,1-已删除,2-已冻结,3-已过期)';
//mapper接口方法
int changeStatus(Long id,String status);
<mapper ...>
	<update id="changeStatus">
        update app_test set app_status=#{status} where id=#{id}
    </update>
</mapper>    
public class MybatisApp {
	private static void testUpdateStatus(ApplicationRepository mapper) {
        int row = mapper.changeStatus(1L, "1");
        System.out.println("状态修改成功, 影响行数: "+row);
    }
}

如果直接执行这段程序会报错,这里存在一个问题当mapper接口方法中存在多个入参,需要通过@param注解明确标注入参的名称,写法如下:

int changeStatus(@Param("id") Long id,@Param("status") String status);

在业务上,如果只是设置一个删除标记,用不着有多个状态,可以将该字段名称设置为is_del

foreach标签

Mybatis同时也支持集合类型的入参,面对集合类型的参数我们一般通过循环的方式解析这一系列参数,在Mybatis中通过 <foreach>标签实现循环

//mapper接口方法
int addList(List<AppTestEntity> list);
<mapper>
	<sql id="insert_column">
        insert into app_test(app_name,app_code,auth_type,create_date,creator)
    </sql>

    <insert id="addApp" parameterType="top.sunyog.common.entity.AppTestEntity">
        <include refid="insert_column"/>
        values(#{appName},#{appCode},#{authType},#{createDate},#{creator})
    </insert>
    
	<!--foreach标签的用法, 类似于for(T item, collection){}-->
    <!-- 
		参数说明:
		collection--list或array类型的(mapper方法的参数名称,或@Param标注的名称)
		separator--collection标注的list中各个元素的分隔符
		item--collection中的元素名称
		index--以下标的形式获取collection集合元素
		open--foreach的起始字符串
		close--foreach的结束字符串
	-->
    <insert id="addList" parameterType="appTestEntity">
        <include refid="insert_column"/>
        values
        <foreach collection="list" separator="," item="entity" index="index" open="" close="">
            (#{entity.appName},#{entity.appCode},#{entity.authType},#{entity.createDate},#{entity.creator})
        </foreach>
    </insert>
</mapper>	
public class MybatisApp {	
	private static void testAddList(ApplicationRepository mapper) {
        AppTestEntityBuilder builder = new AppTestEntityBuilder();
        builder.setCreator("admin3").setAuthType("2");
        List<AppTestEntity> list=new ArrayList<>();
        list.add(builder.setAppName("名称1").setAppCode("code-1").build());
        list.add(builder.setAppName("name2").setAppCode("code-2").build());
        list.add(builder.setAppName("jack liu").setAppCode("code-3").build());

        int row = mapper.addList(list);
        System.out.println("数据新增成功,影响行数: "+row);
    }
}

//这里为了代码好看,可以通过builder的方式创建多个集合元素
public class AppTestEntityBuilder {
    private String appName;
    private String appCode;
    private String authType;
    private String creator;

    public AppTestEntityBuilder setAppName(String appName) {
        this.appName = appName;
        return this;
    }

    public AppTestEntityBuilder setAppCode(String appCode) {
        this.appCode = appCode;
        return this;
    }

    public AppTestEntityBuilder setAuthType(String authType) {
        this.authType = authType;
        return this;
    }

    public AppTestEntityBuilder setCreator(String creator) {
        this.creator = creator;
        return this;
    }

    public AppTestEntity build(){
        AppTestEntity res = new AppTestEntity();
        res.setAppName(this.appName);
        res.setAppCode(this.appCode);
        res.setCreateDate(LocalDate.now());
        res.setCreator(this.creator);
        res.setAuthType(this.authType);

        return res;
    }
}

selectKey标签生成主键

上一章内容中提到的新增数据操作依赖于mysql数据库的自增主键,如果在数据库中没有设置自增可以通过以下代码达到同样的效果

<insert id="addApp" parameterType="top.sunyog.common.entity.AppTestEntity">  
    <selectKey keyProperty="id" resultType="long" order="BEFORE">  
        select max(id)+1 as id from app_test  
    </selectKey>  
    insert into app_test(id,app_name,app_code,auth_type,create_date,creator)
    values(#{id},#{appName},#{appCode},#{authType},#{createDate},#{creator})  
</insert>

selectKey标签属性说明

  1. keyProperty——实体类中的主键属性名
  2. resultType——查询结果类型
  3. order——可在BEFORE和AFTER中选择,表示在insert语句之前(或之后)执行
  4. keyColumn——数据库中的字段名
  5. statementType——JDBC的statement类型,可在STATEMENT、PREPARED、CALLABLE中选择
    以上配置可根据实际情况选择使用

新的疑问

提出新的疑问

  1. mapper接口中的方法,入参有几种形式

  2. sql查询的返回值支持几种形式

  3. resultMap标签是否支持复杂对象

  4. 对于状态型的字段,如app_status,是否支持枚举类型

  5. 如果希望跨类型映射,通过什么方式实现

    这里说的跨类型是指,varchar类型的字段,映射为非String类型,如StringBuilder或者其他带有String类属性的类;或者date、datetime类型字段,可以自行选择转换为Date、String、LocalDate、LocaclDateTime、自定义类型等类型

以上这些问题,Mybatis都有自己的解决方案,我们将在后续的文章中一一介绍。

总结

在这篇文章中我们介绍了Mybatis的几个对CRUD的扩展功能,这些操作也是日常开发中经常用到的,Mybatis引入这些功能的目的也是在一定程度上简化业务开发工作。相对的,这些功能在简化开发的同时我么也应该知道它们存在的不足,比如

  1. <foreach>标签虽然能实现对集合类型的循环,但是对于元素数量过大的集合类型使用foreach还是会造成性能瓶颈,而且不同数据库对SQL语句长度也是有限制的。因此在使用 <foreach>标签之前应该对集合的长度进行限制
  2. selectKey标签虽然能用来生成主键,但是在分布式环境下,selectKey不能保证主键的全局唯一性。因此在分布式环境中,推荐使用雪花算法生成ID,可以通过自定义插件的方式将雪花算法集成进Mybatis中。(插件功能将在后续的文章中介绍)

📩 联系方式
邮箱:qijilaoli@foxmail.com

?版权声明
本文为原创文章,版权归作者所有。未经许可,禁止转载。更多内容请访问奇迹老李的博客首页

文章来源:https://blog.csdn.net/qq_43408971/article/details/135223915
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。