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

本文涉及的产品
RDSClaw,2核4GB
RDS AI 助手,专业版
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
简介: 【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。通过使用RDS,您可以获得稳定、可靠和安全的企业级数据库服务,可以更加专注于发展核心业务,无需过多担心数据库的管理和维护。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。 &nbsp; 相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情:&nbsp;https://www.aliyun.com/product/rds/mysql&nbsp;
相关文章
|
8月前
|
存储 关系型数据库 MySQL
在CentOS 8.x上安装Percona Xtrabackup工具备份MySQL数据步骤。
以上就是在CentOS8.x上通过Perconaxtabbackup工具对Mysql进行高效率、高可靠性、无锁定影响地实现在线快速全量及增加式数据库资料保存与恢复流程。通过以上流程可以有效地将Mysql相关资料按需求完成定期或不定期地保存与灾难恢复需求。
605 10
|
9月前
|
SQL 存储 缓存
MySQL 如何高效可靠处理持久化数据
本文详细解析了 MySQL 的 SQL 执行流程、crash-safe 机制及性能优化策略。内容涵盖连接器、分析器、优化器、执行器与存储引擎的工作原理,深入探讨 redolog 与 binlog 的两阶段提交机制,并分析日志策略、组提交、脏页刷盘等关键性能优化手段,帮助提升数据库稳定性与执行效率。
231 0
|
9月前
|
SQL 人工智能 关系型数据库
如何实现MySQL百万级数据的查询?
本文探讨了在MySQL中对百万级数据进行排序分页查询的优化策略。面对五百万条数据,传统的浅分页和深分页查询效率较低,尤其深分页因偏移量大导致性能显著下降。通过为排序字段添加索引、使用联合索引、手动回表等方法,有效提升了查询速度。最终建议根据业务需求选择合适方案:浅分页可加单列索引,深分页推荐联合索引或子查询优化,同时结合前端传递最后一条数据ID的方式实现高效翻页。
459 0
|
11月前
|
缓存 NoSQL 关系型数据库
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
美团面试:MySQL有1000w数据,redis只存20w的数据,如何做 缓存 设计?
|
11月前
|
存储 SQL 缓存
mysql数据引擎有哪些
MySQL 提供了多种存储引擎,每种引擎都有其独特的特点和适用场景。以下是一些常见的 MySQL 存储引擎及其特点:
285 0
|
10月前
|
Java 数据库连接 数据库
Spring boot 使用mybatis generator 自动生成代码插件
本文介绍了在Spring Boot项目中使用MyBatis Generator插件自动生成代码的详细步骤。首先创建一个新的Spring Boot项目,接着引入MyBatis Generator插件并配置`pom.xml`文件。然后删除默认的`application.properties`文件,创建`application.yml`进行相关配置,如设置Mapper路径和实体类包名。重点在于配置`generatorConfig.xml`文件,包括数据库驱动、连接信息、生成模型、映射文件及DAO的包名和位置。最后通过IDE配置运行插件生成代码,并在主类添加`@MapperScan`注解完成整合
1553 1
Spring boot 使用mybatis generator 自动生成代码插件
|
XML Java 数据库连接
微服务——SpringBoot使用归纳——Spring Boot集成MyBatis——基于注解的整合
本文介绍了Spring Boot集成MyBatis的两种方式:基于XML和注解的形式。重点讲解了注解方式,包括@Select、@Insert、@Update、@Delete等常用注解的使用方法,以及多参数时@Param注解的应用。同时,针对字段映射不一致的问题,提供了@Results和@ResultMap的解决方案。文章还提到实际项目中常结合XML与注解的优点,灵活使用两者以提高开发效率,并附带课程源码供下载学习。
977 0
|
前端开发 Java 数据库连接
Java后端开发-使用springboot进行Mybatis连接数据库步骤
本文介绍了使用Java和IDEA进行数据库操作的详细步骤,涵盖从数据库准备到测试类编写及运行的全过程。主要内容包括: 1. **数据库准备**:创建数据库和表。 2. **查询数据库**:验证数据库是否可用。 3. **IDEA代码配置**:构建实体类并配置数据库连接。 4. **测试类编写**:编写并运行测试类以确保一切正常。
716 2
|
SQL JSON Java
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
这篇文章介绍了如何在Spring Boot项目中整合MyBatis和PageHelper进行分页操作,并且集成Swagger2来生成API文档,同时定义了统一的数据返回格式和请求模块。
844 1
mybatis使用三:springboot整合mybatis,使用PageHelper 进行分页操作,并整合swagger2。使用正规的开发模式:定义统一的数据返回格式和请求模块
|
SQL Java 数据库连接
mybatis使用二:springboot 整合 mybatis,创建开发环境
这篇文章介绍了如何在SpringBoot项目中整合Mybatis和MybatisGenerator,包括添加依赖、配置数据源、修改启动主类、编写Java代码,以及使用Postman进行接口测试。
318 0
mybatis使用二:springboot 整合 mybatis,创建开发环境

推荐镜像

更多
下一篇
开通oss服务