数据库主键ID自增,两种方法获取插入数据库那条数据自动生成的主键ID值

目录

1. 前言

2. 适用于 MyBatis 框架

2.1 获取单条插入语句生成的ID

2.2 获取集合插入生成的多条数据的ID

3. 适用于 MyBatisPlus 框架

3.1 获取单条数据插入生成的ID

3.2 获取集合插入数据生成的多条数据的ID

4. 小结


1. 前言

在开发过程中,我们可能会遇到这样的一种情况,我们保存一条数据。

如果这条数据的主键ID是由用户决定的,这样我们在获取主键ID的时候,只需要让前端的同时传递给我们就可以了;

如果主键ID设置为自增,是在用户新增数据操作时自动生成的,在后续业务逻辑中需要使用生成的主键ID值,我们又该如何获取呢?本篇我们就来说说两种常用方法获取自动生成的主键ID;

2. 适用于 MyBatis 框架

2.1 获取单条插入语句生成的ID

在SQL映射文件中添加 useGeneratedKeys="true" keyProperty="id"

如下,我定义一个插入Product 实体接口

// @Mapper 注释标注当前类为数据访问层接口
@Mapper
public interface ProductMapper {
    // 定义一个插入接口
    Integer insertProduct(@Param("product") Product product);
    
}

在对应的 ProductMappper.xml SQL映射语句中,只需要在 <insert> 中添加 useGeneratedKeys="true" keyProperty="id" 这两个属性即可。

SQL语句中并没有传入ID。

<?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.haust.mapper.ProductMapper">

    <insert id="insertProduct" useGeneratedKeys="true" keyProperty="id" parameterType="com.haust.entity.Product">
        insert into product (`name`,`price`,`color`) values (#{product.productName},#{product.productPrice},#{product.productColor})
    </insert>

</mapper>

我们来做个测试,可以看到,创建的实体对象中我并没有传入ID值,只传递了 name,price,color 三个属性值

    @Test
    public void testInsertProduct(){
        Product product = new Product();
        product.setProductName("电视机");
        product.setProductPrice(2000.00);
        product.setProductColor("red");
        productMapper.insertProduct(product);
        System.out.println(product);
    }

运行测试方法,就可以在控制台看到打印的商品信息,如下图,数据库自动生成的ID=14;

2.2 获取集合插入生成的多条数据的ID

在 ProductMapper 接口中自定义 insertAll 插入多条数据接口

@Mapper
public interface ProductMapper extends BaseMapper<Product> {
    Integer insertAll(@Param("productList") List<Product> productList);
}

 在对应的 ProductMapper.xml 文件中编写对应的 SQL 语句,使用动态SQL语句的写法

<insert id="insertAll" parameterType="com.haust.entity.Product" useGeneratedKeys="true" keyProperty="id">
        insert into product (name,price,color)
        values
        <foreach collection="productList" item="product" separator="," >
            (#{product.productName},#{product.productPrice},#{product.productColor})
        </foreach>
</insert>

编写测试类

    @Test
    public void testInsert(){
        ArrayList<Product> list = new ArrayList<Product>();
        Product product = new Product();
        product.setProductName("电脑");
        product.setProductPrice(5999.00);
        product.setProductColor("white");
        list.add(product);
        Product product2 = new Product();
        product2.setProductName("洗衣机");
        product2.setProductPrice(999.00);
        product2.setProductColor("red");
        list.add(product2);
        Product product3 = new Product();
        product3.setProductName("冰箱");
        product3.setProductPrice(1999.00);
        product3.setProductColor("black");
        list.add(product3);
        productMapper.insertAll(list);
        System.out.println(list);
        // 获取ID集合
        ArrayList<Long> ids = new ArrayList<Long>();
        list.forEach(item ->{
            ids.add(item.getId());
        });
        System.out.println(ids);
    }

运行方法,可以在控制台看到批量插入成功,并通过遍历获取到自动生成的ID集合; 

3. 适用于 MyBatisPlus 框架

3.1 获取单条数据插入生成的ID

MyBatisPlus 框架自带的插入方法会在插入成功之后将方法回写到实体对象参数中;

我们都知道,MyBatisPlus 为提供了单表的增上改查方法,在MyBatis框架的基础上做了增强,我们仍以刚才的 Product 表为例,使用MyBatisPLus 实现获取自动生成主键ID。

第一步:修改实体类,添加注释

@Data
@TableName("product") // @TableName 注释是MyBatisPlus提供的注释,用于标注当前实体类对应数据库的哪张表
public class Product {
    // @TableId("id") 指定数据主键为 id,类型type为自增
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;

    // @TableField("name") 标注当前String字段name为普通字段,对应product数据库表中的字段name,下方同理
    @TableField("name")
    private String productName;

    @TableField("price")
    private Double productPrice;

    @TableField("color")
    private String productColor;

    @TableField("production_date")
    private Date productionDate;
}

第二步:修改Mapper接口,继承BaseMappper接口

@Mapper
public interface ProductMapper extends BaseMapper<Product> {
}

单表增上改查接口都在BaseMapper接口中定义好了,直接继承使用即可,不需要写xml文件,除非是自定义新增接口需要额外写;

    @Test
    public void testInsert(){
        Product product = new Product();
        product.setProductName("电脑");
        product.setProductPrice(6999.00);
        product.setProductColor("black");
        int insert = productMapper.insert(product);
        System.out.println(product);
    }

运行测试方法,打印 product 商品信息,可以发现我们没有传入主键ID的值,数据自动生成的ID=15,并写入到了 product 对象中,我们打印 product 就会显示出来ID,接上了刚才的14。

在实际的开发过程中,如果需要使用ID,在执行完插入操作之后,直接调用 product.getId() 即可获取到生成的主键ID值。

3.2 获取集合插入数据生成的多条数据的ID

MyBatisPlus 提供了多条插入数据,但是在 Service 业务层接口方法,mapper 层只提供了单条数据插入接口,要使用集合插入,需要继承 IService 接口,泛型为实体泛型 Product。

public interface ProductService extends IService<Product> {
}

实现类继承 ServiceImpl 类并添加两个泛型,第一个泛型填写对应的 Mapper 接口,第二个泛型填写对应的实体类 Product 泛型;

@Service
public class ProductServiceImpl extends ServiceImpl<ProductMapper, Product> implements ProductService {
}

书写测试类

    @Test
    public void testInsert(){
        ArrayList<Product> list = new ArrayList<Product>();
        Product product = new Product();
        product.setProductName("电脑");
        product.setProductPrice(6999.00);
        product.setProductColor("black");
        list.add(product);
        Product product2 = new Product();
        product2.setProductName("洗衣机");
        product2.setProductPrice(999.00);
        product2.setProductColor("black");
        list.add(product2);
        Product product3 = new Product();
        product3.setProductName("冰箱");
        product3.setProductPrice(1999.00);
        product3.setProductColor("black");
        list.add(product3);
        productService.saveBatch(list);
        System.out.println(list);
        // 获取ID集合
        ArrayList<Long> ids = new ArrayList<Long>();
        list.forEach(item ->{
            ids.add(item.getId());
        });
    }

运行测试类,打印 list 集合,如果要获取所有ID,遍历 list 集合即可,代码中我已经写好了,运行如下图,可以看到获取到了生成的ID集合。

4. 小结

其实上述两种方法没有本质区别,只是框架不一样。

如果在实际开发过程中,你的公司没有使用 MyBatisPlus 框架,那就选择第一种方法加入 useGeneratedKeys="true" keyProperty="id" 即可;

如果你的公司使用了 MyBatisPlus 框架,基本不需要做额外操作,因为实际开发过程中也很少会有插入语句需要去自定义的,直接使用 MyBatisPlus 提供的足以应对业务需求;

### SQL 数据库主键的实现方法 在不同的关系型数据库管理系统(RDBMS)中,实现主键方法有所不同。以下是针对几种主流数据库系统的具体实现方式。 #### MySQL 中的主键 在 MySQL 中,可以通过定义字段为 `AUTO_INCREMENT` 来实现主键功能。此属性通常与 `INT` 类型一起使用,并且该字段必须作为主键的一部分[^1]。 ```sql CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(50), email VARCHAR(100) ); ``` 如果需要重置主键的初始,在清空表数据后可执行以下操作: ```sql -- 查看当前表中的最大主键 SELECT MAX(id) FROM users; -- 修改主键起始 ALTER TABLE users AUTO_INCREMENT = 1; ``` 上述语句可用于重新初始化主键序列[^3]。 --- #### SQL Server 中的主键 对于 Microsoft SQL Server,可以利用 `IDENTITY` 属性来设置列为主键并启用自行为。通过指定两个参数 `(种子, 步长)` 定义初始和每次递[^2]。 ```sql CREATE TABLE employees ( id INT IDENTITY(1, 1) NOT NULL PRIMARY KEY, first_name NVARCHAR(50), last_name NVARCHAR(50) ); ``` 在此例子中,`id` 列被设定为从 1 开始,每新一条记录则加 1 的模式长。 --- #### Oracle 中的主键模拟 Oracle 并未原生支持类似于其他 RDBMS 的自动量特性,因此需借助序列(Sequence)对象配合触发器(Trigger)共同完成这一需求[^4]。 第一步:创建一个用于生成唯一编号的 Sequence 对象。 ```sql CREATE SEQUENCE seq_employee_id START WITH 1 INCREMENT BY 1 NOCACHE; ``` 第二步:建立目标表格结构。 ```sql CREATE TABLE employees_oracle ( employee_id NUMBER PRIMARY KEY, full_name VARCHAR2(100) ); ``` 第三步:编写 Insert 前触发逻辑以填充主键。 ```sql CREATE OR REPLACE TRIGGER trg_emp_before_insert BEFORE INSERT ON employees_oracle FOR EACH ROW BEGIN :NEW.employee_id := seq_employee_id.NEXTVAL; END; / ``` 每当向 `employees_oracle` 插入新行时,触发器会调用 Sequence 自动生成下一个可用数赋予给 `employee_id` 字段。 --- #### PostgreSQL 中的主键 PostgreSQL 提供了一种特殊的伪类型——serial 和 bigserial,它们简化了创建具有默认的整数列的过程,这些列的行为就像 MySQL 的 AUTO_INCREMENT[^6]。 下面展示了一个简单的实例: ```sql CREATE TABLE products ( product_no SERIAL PRIMARY KEY, name TEXT, price NUMERIC ); ``` 这里声明了 `product_no` 是 serial 类型,默认情况下它将关联到名为 `products_product_no_seq` 的序列上,从而实现了自动化管理序号分配的功能。 当遇到超出 int 范围的情况,则应考虑采用 BIGSERIAL 替代之。 --- #### 处理主键达到上限的情形 假如现有表内的主键已经接近其类型的极限范围,那么可能要考虑升级存储容量更大的数据类型比如 bigint 或 unsigned integer;或者重构整个架构迁移到更大规模的支持环境下去运行业务流程[^5]。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值