You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Hibernate使用PreparedStatement插入时未自动生成UUID ID的问题排查

问题:使用PreparedStatement插入记录时,Hibernate无法自动生成UUID主键

我正在学习Hibernate,计划使用PreparedStatement向数据库插入记录,但发现插入查询无法自动为记录生成UUID。相关代码如下:

实体类User

@Data
@Entity
@NoArgsConstructor
@AllArgsConstructor
@Table(name = "user_details")
@SuperBuilder(toBuilder = true)
public class User extends Base {

    @NonNull
    @Column(unique = true)
    private String userName;
}

父类Base

@Data
@MappedSuperclass
@NoArgsConstructor
@SuperBuilder(toBuilder = true)
public class Base {

    @Id
    @GeneratedValue(generator = "uuid")
    @GenericGenerator(name = "uuid", strategy = "uuid2")
    private String id;
}

Dao实现类

private static final String SAVE_USER = "INSERT INTO user_details(user_name) VALUES(?)";

@Override
public UserDto saveUser(User user) {
    Connection connection = null;
    PreparedStatement ps = null;
    ResultSet resultSet = null;

    try {
        connection = source.getConnection();
        ps = connection.prepareStatement(SAVE_USER);
        ps.setString(1, user.getUserName());

        try {
            ps.execute();
        } catch (Exception e) {
            log.error("Failed to save user to db");
        }
        return findUserByName(user.getUserName());
    } catch (SQLException e) {
        throw new RuntimeException(e);
    } finally {
        try {
            closeAll(resultSet, ps, connection);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

原因分析

你直接用JDBC的PreparedStatement执行原生SQL插入,完全绕开了Hibernate的实体管理机制:

  • 你在Base类中配置的@GeneratedValue和@GenericGenerator是Hibernate专属注解,只有当Hibernate负责处理实体持久化(比如调用session.save()或entityManager.persist())时,才会触发这些注解的逻辑,自动生成UUID并填充到id字段,再执行插入操作。
  • 而现在的代码直接通过JDBC连接执行原生INSERT,Hibernate没有参与这个过程,自然不会解析实体类的注解、生成UUID。如果数据库的id字段没有设置默认生成规则,就会因为id为空导致插入失败或id为null。

解决方案

方案1:改用Hibernate持久化API(推荐)

既然用了Hibernate,推荐利用它的ORM能力,避免直接写JDBC代码:

@PersistenceContext
private EntityManager entityManager;

@Override
public UserDto saveUser(User user) {
    try {
        entityManager.persist(user);
        entityManager.flush(); // 可选,立即触发数据库操作
        return findUserByName(user.getUserName());
    } catch (Exception e) {
        log.error("Failed to save user to db", e);
        throw new RuntimeException(e);
    }
}

这样Hibernate会自动处理id的生成,无需手动干预。

方案2:手动生成UUID(保留PreparedStatement)

如果必须使用原生JDBC,需要自己生成UUID并添加到INSERT语句中:

  1. 修改SQL语句,包含id字段:
private static final String SAVE_USER = "INSERT INTO user_details(id, user_name) VALUES(?, ?)";
  1. 在代码中手动生成UUID并设置参数:
// 生成UUID字符串
ps.setString(1, UUID.randomUUID().toString());
ps.setString(2, user.getUserName());

另外也可以在数据库层面给id字段设置默认值(比如MySQL用DEFAULT UUID(),PostgreSQL用DEFAULT gen_random_uuid()),这样即使INSERT语句不指定id,数据库会自动生成,但要注意和Hibernate的生成逻辑保持一致。


内容的提问来源于stack exchange,提问作者houhou

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 13:22:08