【MySQL用法】MyBatis 多对多 中间表插入数据,添加记录后获取主键ID

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 【MySQL用法】MyBatis 多对多 中间表插入数据,添加记录后获取主键ID

一、需求内容

有一个很常见的需求,即添加记录后获取添加后的主键ID,特别是在一次前端调用中需要插入多个表的场景。除了添加单条记录时获取主键值,有时候可能需要获取批量添加记录时各记录的主键值,MyBatis从3.3.1版本开始支持批量添加记录并返回各记录主键字段值。

比如我在做这个员工管理系统的时候,由于user和role是多对多关系,且user主键是自增的,所有我们没办法提前知晓这个user_id,所以插入的时候,就需要先插入user,然后再找到刚插入的id拿出来,再插入中间表user_role,这样才能将表关系对应起来,才能算一个完整的插入的过程。

问题是对于刚刚插入到数据库中的一条记录,我怎么知道这个user_id,再怎么拿出来,再插入中间表user_role。(当然一种做法是,执行完一条插入数据后,再执行查询的操作,不推荐这种方法),其实如果用的是MyBatis框架,本身就有这个功能。

二、实现方法

2.1 方法

在MyBatis中要用到insert和update元素下的3个属性:分别是useGeneratedKeys,keyPropertykeyColumn。这三个属性(仅对 insert 语句和 update语句 有用)。

2.2 含义

useGeneratedKeys:这会令 MyBatis 使用 JDBC 的 getGeneratedKeys 方法来取出由数据库内部生成的主键,默认值:false。如果将useGeneratedKeys设置为true,在执行添加记录之后可以获取到数据库自动生成的主键ID。

keyProperty:唯一标记一个属性,MyBatis 会通过 getGeneratedKeys 的返回值或者通过 insert 语句的 selectKey 子元素设置它的键值,默认:unset。对应它的值是Java对象中的属性值。

keyColumn:通过生成的键值设置表中的列名,这个设置仅在某些数据库(像 PostgreSQL)是必须的,当主键列不是表中的第一列的时候需要设置。对应它的值是数据库中表的字段值。

三、具体实现

在MyBatis中,允许设置名称为“useGeneratedKeys”参数存在3个位置:

1、在settings元素中设置useGeneratedKeys参数

2、在xml映射器中设置useGeneratedKeys参数

3、在接口映射器中设置useGeneratedKeys参数

在不同位置设置的useGeneratedKeys参数,最终结果相同,但是影响范围不同。

3.1 在settings元素中设置

在settings元素中设置useGeneratedKeys参数

在settings元素中设置useGeneratedKeys是一个全局参数,但是只会对接口映射器产生影响,对xml映射器不起效。

<settings>
    <!-- 允许JDBC支持自动生成主键,需要驱动兼容。 如果设置为true则这个设置强制使用自动生成主键,
         尽管一些驱动不能兼容但仍可正常工作(比如 Derby)。 -->
    <setting name="useGeneratedKeys" value="true" />
</settings>

此时,在接口映射中添加记录之后将返回主键ID。

public interface TacticsMapper {
    // 受全局useGeneratedKeys参数控制,添加记录之后将返回主键id
    @Insert("insert into op_tactics_info (name,remark, create_time,update_time) values (#{name},#{remark},#{createTime},#{updateTime})")
    Integer insertTactics(Tactics tactics);
}

但是,请注意如果此时在接口映射器中又明确设置了useGeneratedKeys参数,那么注解映射器中的useGeneratedKeys参数值将覆盖settings元素中设置的全局useGeneratedKeys参数值。

例如:先在settings元素中设置全局useGeneratedKeys参数值为true,再在接口映射器中设置useGeneratedKeys参数值为false,添加记录之后将不能返回注解ID。

public interface TacticsMapper {
    // 在接口映射器中设置的useGeneratedKeys参数值将会覆盖在settings元素中设置全局useGeneratedKeys参数值
    @Options(useGeneratedKeys = false, keyProperty = "id", keyColumn = "id")
    @Insert("insert into op_tactics_info (name,remark, create_time,update_time) values (#{name},#{remark},#{createTime},#{updateTime})")
    Integer insertTactics(Tactics tactics);
}

另外,在settings元素中设置的全局useGeneratedKeys参数对于xml映射器无效。如果希望在xml映射器中执行添加记录之后返回主键ID,则必须在xml映射器中明确设置useGeneratedKeys参数值为true。

3.2 在xml映射器中配置

在xml映射器中配置useGeneratedKeys参数

1. <insert id="insertTactics" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
2. insert into op_tactics_info
3.     (tactics_name,remark, create_time,update_time)
4. values
5.     (#{tacticsName},#{remark},#{createTime},#{updateTime})
6. </insert>

xml映射器中配置的useGeneratedKeys参数只会对xml映射器产生影响,且在settings元素中设置的全局useGeneratedKeys参数值对于xml映射器不产生任何作用。

3.3 在接口映射器中设置

在接口映射器中设置useGeneratedKeys参数

    // 设置useGeneratedKeys为true,返回数据库自动生成的记录主键id
    @Options(useGeneratedKeys = false, keyProperty = "id", keyColumn = "id")
    @Insert("insert into op_tactics_info (name,remark, create_time,update_time) values (#{name},#{remark},#{createTime},#{updateTime})")
    Integer insertTactics(Tactics tactics);

注意: 在接口映射器中设置的useGeneratedKeys参数会覆盖在<settings>元素中设置的对应参数值。

3.4 代码示例

3.4.1 插入user表,可以看到我们并没有插入user_id这个属性,因为是自增的。

<insert id="insert" useGeneratedKeys="true" keyProperty="user_id" keyColumn="user_id">
    insert into user
    (user_name,user_gender,user_email,user_phone,user_address,user_birthday,department_id)
    values(#{user_name},#{user_gender},#{user_email},#{user_phone},#{user_address},#{user_birthday},#{department_id})
</insert>

3.4.2 重点是中间表user_role ,可以看到,我们直接就使用user下面的user_id了,我们也没有做查询操作,所以我们并不知晓它的具体值。

<insert id="insertUserRole">
    insert into user_role values(#{user.user_id},#{role.role_id})
</insert>

3.4.3 test类,为了方便大家更好的理解,我们可以做一次测试。

通过下面代码可以看到:我们在插入user后,就能够把user_id打印出来,再插入到中间表中,并没做其他诸如查询的操作。

public class testUserRole {
    public static void main(String[] args) {
        Date date = new Date();
        User user = new User("Jack", "male", "axxxx@163.com", "183xxxxxxxx", "chengdu", date, 1);
        Role role = new Role();
        role.setRole_id(3);
        //插入user
        service.insert(user);
        //打印user_id
        System.out.println("user_id----->>>>" + user.getUser_id());
        //插入中间表
        service.insertUserRole(user, role);
    }
}

结果:可以看到我们直接插入后,就能取得user_id了,然后再插入中间表,这就解决了这个问题。

当然由于插入一个新的user,必须同时满足user和role的映射,所以这里使用Spring transaction来保证这个插入过程的完整性。

使用注解方式实现。

@Transactional(propagation=Propagation.REQUIRED,isolation=Isolation.READ_COMMITTED)
public void insertUserRole(User user, Role role) {
    this.insert(user);
    mapper.insertUserRole(user, role);
}

 

【参考资料】

1、深入浅出mybatis之useGeneratedKeys参数用法

2、MyBatis 多对多 中间表插入数据


相关实践学习
如何快速连接云数据库RDS MySQL
本场景介绍如何通过阿里云数据管理服务DMS快速连接云数据库RDS MySQL,然后进行数据表的CRUD操作。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
26天前
|
SQL Java 数据库连接
MyBatis-Plus高级用法:最优化持久层开发
MyBatis-Plus 通过简化常见的持久层开发任务,提高了开发效率和代码的可维护性。通过合理使用条件构造器、分页插件、逻辑删除和代码生成器等高级功能,可以进一步优化持久层开发,提升系统性能和稳定性。掌握这些高级用法和最佳实践,有助于开发者构建高效、稳定和可扩展的企业级应用。
67 13
|
29天前
|
存储 关系型数据库 MySQL
MySQL主键谁与争锋:MySQL为何钟爱自增主键ID+UUID?
本文深入探讨了在MySQL中使用自增类型主键的优势与局限性。自增主键通过保证数据的有序性和减少索引维护成本,提升了查询和插入性能,简化了数据库管理和维护,并提高了数据一致性。然而,在某些业务场景下,如跨表唯一性需求或分布式系统中,自增主键可能无法满足要求,且存在主键值易预测的安全风险。因此,选择主键类型时需综合考虑业务需求和应用场景。
46 2
|
2月前
|
监控 关系型数据库 MySQL
MySQL自增ID耗尽应对策略:技术解决方案全解析
在数据库管理中,MySQL的自增ID(AUTO_INCREMENT)属性为表中的每一行提供了一个唯一的标识符。然而,当自增ID达到其最大值时,如何处理这一情况成为了数据库管理员和开发者必须面对的问题。本文将探讨MySQL自增ID耗尽的原因、影响以及有效的应对策略。
200 3
|
2月前
|
存储 监控 关系型数据库
MySQL自增ID耗尽解决方案:应对策略与实践技巧
在MySQL数据库中,自增ID(AUTO_INCREMENT)是一种特殊的属性,用于自动为新插入的行生成唯一的标识符。然而,当自增ID达到其最大值时,会发生什么?又该如何解决?本文将探讨MySQL自增ID耗尽的问题,并提供一些实用的解决方案。
83 1
|
3月前
|
Java 关系型数据库 MySQL
springboot学习五:springboot整合Mybatis 连接 mysql数据库
这篇文章是关于如何使用Spring Boot整合MyBatis来连接MySQL数据库,并进行基本的增删改查操作的教程。
495 0
springboot学习五:springboot整合Mybatis 连接 mysql数据库
|
3月前
|
SQL XML Java
Mybatis的<where>,<if>等标签用法
这篇文章详细解释了Mybatis中<where>和<if>等标签的用法,展示了如何在SQL动态构建中有效地过滤条件和处理逻辑分支。
323 1
|
3月前
|
存储 SQL 关系型数据库
mysql中主键索引和联合索引的原理与区别
本文详细介绍了MySQL中的主键索引和联合索引原理及其区别。主键索引按主键值排序,叶节点仅存储数据区,而索引页则存储索引和指向数据域的指针。联合索引由多个字段组成,遵循最左前缀原则,可提高查询效率。文章还探讨了索引扫描原理、索引失效情况及设计原则,并对比了InnoDB与MyISAM存储引擎中聚簇索引和非聚簇索引的特点。对于优化MySQL性能具有参考价值。
|
2月前
|
SQL 关系型数据库 MySQL
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
mysql编写sql脚本:要求表没有主键,但是想查询没有相同值的时候才进行插入
40 0
|
3月前
|
SQL Java 数据库连接
Mybatis的<insert>,<update>,<delete>标签用法
这篇文章详细讲解了Mybatis中<insert>, <update>, <delete>标签的使用方法,并提供了示例代码来展示如何执行数据库的增删改操作。
258 0
|
2天前
|
缓存 关系型数据库 MySQL
【深入了解MySQL】优化查询性能与数据库设计的深度总结
本文详细介绍了MySQL查询优化和数据库设计技巧,涵盖基础优化、高级技巧及性能监控。
27 0