MyBatis主键生成策略中useGeneratedKeys和<selectKey>的区别

 更新时间:2025年01月22日 10:36:15   作者:山高自有客行路  
本文主要介绍了MyBatis主键生成策略中useGeneratedKeys和<selectKey>的区别,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧

useGeneratedKeys

机制与原理

  • JDBC特性useGeneratedKeys利用了JDBC的getGeneratedKeys()方法,该方法是在执行INSERT语句后获取由数据库自动生成的主键值。
  • 自动设置属性:MyBatis会自动将获取到的主键值设置到映射文件中定义的keyProperty所指向的对象属性上。
  • 适用场景:适用于支持自增主键或序列(如MySQL的AUTO_INCREMENT、PostgreSQL的SERIAL)的数据库。

实例与细节

考虑一个简单的用户表:

CREATE TABLE users (
  id INT AUTO_INCREMENT PRIMARY KEY,
  username VARCHAR(50) NOT NULL,
  email VARCHAR(100)
);

对应的Java实体类:

public class User {
    private Integer id;
    private String username;
    private String email;

    // getters and setters...
}

Mapper XML配置:

<insert id="insertUser" useGeneratedKeys="true" keyProperty="id">
  INSERT INTO users (username, email)
  VALUES (#{username}, #{email})
</insert>

注意事项

  • 事务管理:确保你的插入操作在一个事务中进行,以避免部分成功的情况。
  • 批量插入:对于批量插入,你可能需要特别处理,因为getGeneratedKeys()返回的结果集可能会包含多个生成的键。可以通过<foreach>标签来实现批量插入,并通过ResultSet逐个获取生成的键。
<insert id="batchInsertUsers" useGeneratedKeys="true" keyProperty="id" keyColumn="id">
  INSERT INTO users (username, email)
  <foreach collection="list" item="user" separator=",">
    (#{user.username}, #{user.email})
  </foreach>
</insert>

批量插入后的主键处理

List<User> users = // ... your list of users to insert
SqlSession sqlSession = sqlSessionFactory.openSession();
try {
    UserMapper mapper = sqlSession.getMapper(UserMapper.class);
    for (User user : users) {
        mapper.insertUser(user);
        // MyBatis will automatically set the generated ID into the 'user' object
    }
    sqlSession.commit();
} finally {
    sqlSession.close();
}

异常处理

  • 捕获异常:如果插入失败,比如违反唯一性约束,MyBatis将抛出异常,你需要捕获并处理这些异常。
  • 回滚机制:确保在发生异常时,事务能够正确回滚,以保持数据的一致性。
try {
    sqlSession.insert("insertUser", user);
    sqlSession.commit();
} catch (PersistenceException e) {
    sqlSession.rollback();
    throw e;
} finally {
    sqlSession.close();
}

性能考量

  • 减少查询次数:尽量减少额外的查询,例如在批量插入时合理使用getGeneratedKeys()
  • 优化连接池:确保JDBC连接池配置得当,以应对高并发情况下的性能需求。
  • 批处理优化:对于批量操作,可以使用JDBC的批处理功能来提高性能。
<insert id="batchInsertUsers" parameterType="java.util.List">
  INSERT INTO users (username, email)
  VALUES
  <foreach collection="list" item="user" separator=",">
    (#{user.username}, #{user.email})
  </foreach>
</insert>

<selectKey>

机制与原理

  • 自定义SQL<selectKey>允许你编写任意的SQL来生成主键值,并且可以指定这个查询是在INSERT之前还是之后执行。
  • 灵活性:它适合于任何需要特定逻辑来生成主键的情况,或者当数据库不支持自增字段时使用。

实例与细节

假设我们有一个Oracle数据库,并使用序列user_seq来生成主键:

Mapper XML配置:

<insert id="insertUserWithSequence">
  <selectKey keyProperty="id" resultType="int" order="BEFORE">
    SELECT user_seq.NEXTVAL FROM dual
  </selectKey>
  INSERT INTO users (id, username, email)
  VALUES (#{id}, #{username}, #{email})
</insert>

对于某些数据库(如PostgreSQL),你可以直接使用RETURNING子句来简化代码:

<insert id="insertUserWithReturning" parameterType="User">
  INSERT INTO users (username, email)
  VALUES (#{username}, #{email})
  RETURNING id
</insert>

性能考量

  • 减少查询次数:尽量减少额外的查询,比如使用RETURNING子句代替<selectKey>
  • 缓存序列:如果使用序列生成主键,考虑在应用层实现序列缓存以减少对数据库的压力。
  • 并发控制:考虑到并发环境下的序列分配问题,确保你的序列设计能够正确处理高并发场景。

异常处理

  • 空值检查:确保在调用<selectKey>后检查返回的主键是否为空或无效。
  • 并发控制:考虑到并发环境下的序列分配问题,确保你的序列设计能够正确处理高并发场景。
  • 事务管理:确保在发生异常时,事务能够正确回滚,以保持数据的一致性。
<selectKey keyProperty="id" resultType="int" order="BEFORE">
  SELECT COALESCE(MAX(id), 0) + 1 FROM users -- 简单示例,实际生产环境中应避免这种方式
</selectKey>

数据库兼容性

不同的数据库有不同的特性和限制,比如Oracle的序列机制、MySQL的自增字段、PostgreSQL的RETURNING语法等。在设计主键生成策略时,务必考虑到目标数据库的具体特性。

  • Oracle:通常使用序列和触发器来生成主键。
  • MySQL:使用自增字段。
  • PostgreSQL:支持SERIAL类型和RETURNING子句。
  • SQL Server:使用IDENTITY列或SEQUENCE对象。

监控与日志

在生产环境中,监控主键生成的相关操作非常重要。良好的日志记录可以帮助快速定位和解决问题,特别是当涉及到并发控制或性能瓶颈时。

log.info("Generated ID for new user: {}", user.getId());

综合比较

特性/方面useGeneratedKeys<selectKey>
适用数据库支持自增主键或序列的数据库所有类型的数据库
配置复杂度简单较复杂
性能更高效,减少额外查询可能引入额外查询,影响性能
灵活性依赖数据库特性高度灵活,适应各种复杂场景
维护成本较低,易于维护较高,可能增加维护负担

注意事项

批量插入与主键生成

对于批量插入,useGeneratedKeys<selectKey>都有其特定的挑战。对于useGeneratedKeys,你需要确保正确处理结果集中返回的多个主键值。而对于<selectKey>,你可能需要为每个要插入的记录单独生成主键,这可能导致性能问题。因此,在批量插入的情况下,最好评估具体的性能需求并选择最合适的策略。

事务边界与一致性

无论是useGeneratedKeys还是<selectKey>,都应确保它们的操作在一个明确的事务边界内完成,以防止部分成功导致的数据不一致。特别是在分布式系统中,跨服务的事务管理尤为重要。

数据库兼容性

不同的数据库有不同的特性和限制,比如Oracle的序列机制、MySQL的自增字段、PostgreSQL的RETURNING语法等。在设计主键生成策略时,务必考虑到目标数据库的具体特性。

优化建议

  • 批量操作:使用JDBC的批处理功能来提高批量插入的性能。
  • 序列缓存:对于使用序列生成主键的数据库,可以在应用程序层面实现序列缓存,减少频繁访问数据库的开销。
  • 异步处理:对于大规模数据插入,可以考虑异步处理以减轻数据库压力。
  • 索引优化:确保插入操作不会导致大量索引重建,影响性能。

到此这篇关于MyBatis主键生成策略中useGeneratedKeys和<selectKey>的区别的文章就介绍到这了,更多相关MyBatis useGeneratedKeys和<selectKey>内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家! 

相关文章

  • Java ArrayList扩容机制原理深入分析

    Java ArrayList扩容机制原理深入分析

    在Java中,ArrayList是最常用的集合之一。它是一种容器,它的内部定义了一个Object类型的数组elementData,因此可用于存储任意类型的数据。我们知道,数组是长度恒定的。而ArrayList相当于是一个长度可变的动态数组,一起来看看的它的扩容机制
    2023-02-02
  • springboot如何读取配置文件(application.yml)中的属性值

    springboot如何读取配置文件(application.yml)中的属性值

    本篇文章主要介绍了springboot如何读取配置文件(application.yml)中的属性值,具有一定的参考价值,有兴趣的小伙伴可以了解一下
    2017-04-04
  • 如何自定义Spring Authorization Server登录页

    如何自定义Spring Authorization Server登录页

    这篇文章主要介绍了如何自定义Spring Authorization Server登录页,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧
    2025-05-05
  • Kotlin 基础教程之异常

    Kotlin 基础教程之异常

    这篇文章主要介绍了Kotlin 基础教程之异常的相关资料,需要的朋友可以参考下
    2017-06-06
  • java求数组元素重复次数和java字符串比较大小示例

    java求数组元素重复次数和java字符串比较大小示例

    这篇文章主要介绍了java求数组元素重复次数和java字符串比较大小示例,需要的朋友可以参考下
    2014-04-04
  • SpringCloud之@FeignClient()注解的使用详解

    SpringCloud之@FeignClient()注解的使用详解

    @FeignClient是SpringCloud中用于声明一个Feign客户端的注解,用于解决模块方法互相调用的问题,Feign是一个声明式的WebService客户端,通过Feign,只需要创建一个接口,并使用注解来描述请求,就可以直接执行HTTP请求了
    2024-11-11
  • SpringBoot整合jasypt实现敏感信息的加密详解

    SpringBoot整合jasypt实现敏感信息的加密详解

    一般公司的核心业务代码中,都会存在与数据库、第三方通信的secret key等敏感信息,如果以明文的方式存储,一旦泄露,那将会给公司带来巨大的损失。本篇文章通过讲解:Springboot集成Jasypt对项目敏感信息进行加密,提高系统的安全性
    2022-09-09
  • 详解SpringBoot优雅编码之Lombok加持

    详解SpringBoot优雅编码之Lombok加持

    这篇文章主要介绍了详解SpringBoot优雅编码之Lombok加持,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-06-06
  • Mybatis使用update更新值为null时不生效问题解决

    Mybatis使用update更新值为null时不生效问题解决

    这篇文章主要介绍了Mybatis使用update更新值为null时不生效问题解决,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-06-06
  • Java利用Spire.Doc for Java实现Word文档转换为常见图像格式

    Java利用Spire.Doc for Java实现Word文档转换为常见图像格式

    在现代软件开发中,尤其是在构建企业级应用和内容管理系统时,处理 Word 文档是家常便饭,本文将深入探讨如何利用 Java 高效、高质量地将 Word 文档转换为 JPG、PNG 和 SVG 等主流图片格式,大家可以根据需要进行选择
    2025-10-10

最新评论