insert插入数据并自动生成唯一主键id
时间: 2025-06-27 12:03:06 浏览: 8
### 如何在 SQL 中实现 `INSERT` 操作时自动生成唯一主键 ID
#### 使用数据库内置功能生成主键
许多关系型数据库提供了内置的功能用于生成唯一的主键字段。例如,在 MySQL 和 SQL Server 中可以使用 `AUTO_INCREMENT` 或者 `IDENTITY` 属性来定义列,使其能够自动增加并保持唯一性。
对于 MySQL 数据库而言,可以通过设置某一列为 `PRIMARY KEY AUTO_INCREMENT` 来实现这一目标[^1]:
```sql
CREATE TABLE example_table (
id INT PRIMARY KEY AUTO_INCREMENT,
name VARCHAR(255) NOT NULL
);
```
当向上述表格插入数据时无需指定 `id` 值,数据库会自动为其分配一个递增的整数值作为主键。
#### 利用 MyBatis 插件机制实现主键生成逻辑
如果项目中采用了 MyBatis 作为持久层框架,则还可以借助插件的方式来自定义主键生成策略。具体来说就是创建一个拦截器类继承 `org.apache.ibatis.plugin.Interceptor` 接口,并重写其中的方法完成对原始对象的操作前后的处理工作[^2]。
下面是一个简单的例子展示了如何通过编写自定义拦截器来为新增记录动态填充 UUID 类型字符串形式的主键值:
```java
@Intercepts(value={
@Signature(type = Executor.class, method="update", args={MappedStatement.class, Object.class})
})
public class AutoIdInterceptor implements Interceptor {
private static final Logger logger = LoggerFactory.getLogger(AutoIdInterceptor.class);
public Object intercept(Invocation invocation) throws Throwable {
MappedStatement mappedStmt = (MappedStatement)invocation.getArgs()[0];
String sqlCommandType = mappedStmt.getSqlCommandType().name();
if ("INSERT".equalsIgnoreCase(sqlCommandType)){
Object parameterObject = invocation.getArgs()[1];
MetaObject metaParamObj = SystemMetaObject.forObject(parameterObject);
Field[] fields = parameterObject.getClass().getDeclaredFields();
boolean hasPrimaryKeyField=false;
for(Field f :fields){
Column column=f.getDeclaredAnnotation(Column.class);
Id id=f.getDeclaredAnnotation(Id.class);
if(id!=null && !metaParamObj.hasGetter(f.getName())){
String generatedValue=UUID.randomUUID().toString();
metaParamObj.setValue(f.getName(),generatedValue );
break;
}
}
}
return invocation.proceed();
}
}
```
此代码片段中的核心部分在于遍历参数实体的所有属性查找标记有 JPA 注解 `@Id` 的成员变量;一旦发现符合条件的目标字段尚未被赋初值则随机生成一段独一无二的文字串赋予之。
#### 获取刚插入行所产生的主键值
除了让 DBMS 自动计算外键之外有时我们也希望能够在应用程序层面捕获到刚刚成功提交的新纪录对应的主键编号以便进一步操作关联子项等内容。此时可利用 JDBC API 提供的相关方法达成目的[^3]:
```java
PreparedStatement pstmt = conn.prepareStatement(
"INSERT INTO orders(order_date,customer_id,status)" +
"VALUES(CURDATE(),?,?)",
Statement.RETURN_GENERATED_KEYS );
pstmt.setInt(1, customerId);
pstmt.setString(2,"PENDING");
int affectedRows=pstmt.executeUpdate();
if(affectedRows==0 ){
throw new SQLException("Creating user failed,no rows affected.");
}
ResultSet rs=pstmt.getGeneratedKeys();
long orderId=-1;
if(rs.next()){
orderId=rs.getLong(1);
}else{
throw new SQLException("Cannot obtain auto-generated key");
}
System.out.println("New Order Created With ID:"+orderId);
```
上面这段程序演示了怎样调用 PreparedStatement 对象上的 getGeneratedKeys() 函数检索最近一次执行 DML 指令之后产生的新条目所携带的关键字信息。
#### 定义非连续字符类型的主键约束条件
最后值得注意的一点是在设计模式允许的情况下也可以考虑采用固定长度或者变长但是具备一定规律性的文本序列充当主键角色而不是单纯依赖于数字累加方式构建索引结构。比如下述范例就规定了一个名为 `id` 的字段接受最多一百个字母组成的任意组合并且附加说明该栏位需满足唯一性校验标准[^4]:
```sql
CREATE TABLE users (
`id` varchar(100) COLLATE utf8_estonian_ci NOT NULL COMMENT '唯一不重复',
username VARCHAR(50),
password_hash CHAR(60), -- Assuming bcrypt hash length is fixed at 60 chars.
email_address TEXT UNIQUE,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
CONSTRAINT pk_user PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci ;
```
这样做的好处是可以有效避免因频繁更新而引发的数据迁移成本同时也便于跨平台移植以及与其他系统的集成对接等工作场景下的应用需求匹配问题解决思路探讨.
阅读全文
相关推荐


















