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语句中:
- 修改SQL语句,包含
id字段:
private static final String SAVE_USER = "INSERT INTO user_details(id, user_name) VALUES(?, ?)";
- 在代码中手动生成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
相关产品推荐
相关产品推荐

