Postgresql JPA:生成非pk唯一和随机字母数字值
我想在不使用主键的情况下唯一标识一个实体。所以我考虑生成一个唯一的随机值。此外,该值必须易于读取/手动复制,预计长度为6或7个字符 设计 我的实体A:Postgresql JPA:生成非pk唯一和随机字母数字值,postgresql,jpa,eclipselink,jpa-2.0,Postgresql,Jpa,Eclipselink,Jpa 2.0,我想在不使用主键的情况下唯一标识一个实体。所以我考虑生成一个唯一的随机值。此外,该值必须易于读取/手动复制,预计长度为6或7个字符 设计 我的实体A: public class A{ // ... @Column(name="value", unique=true, nullable=false, insertable=false, updatable=false) private String value; // ... public String g
public class A{
// ...
@Column(name="value", unique=true, nullable=false, insertable=false, updatable=false)
private String value;
// ...
public String getValue(){
return value;
}
protected void setValue(String value){
this.value = value;
}
}
在数据库中由表表示
CREATE TABLE IF NOT EXISTS schema.mytable{
-- ...
value TEXT NOT NULL DEFAULT generate_unique_value_for_mytable(),
-- ...
CONSTRAINT "un_value" UNIQUE (value),
-- ...
}
我想让数据库处理这个,然后获取值
问题
在当前设计中,值在数据库中正确生成,但当JPA获取实体时,值字段为空
public class Aejb{
public void create(A entity){
// method kind of ensures randomness
String value = MyUtil.generateRandomValue();
A isThereAnyoneHere = findByValue(value);
while(isThereAnyoneHere != null){
String value = MyUtil.generateRandomValue();
isThereAnyoneHere = findByValue(value);
}
// unicity is ensured
entity.setValue(value);
em.persist(entity);
}
}
问题
如果我理解正确的话,@Generated注解应该可以做到这一点。此注释根据数据库默认字段值设置值 例如:
@Generated(GenerationTime.INSERT)
@Column(name="value", unique=true, nullable=false, insertable=false, updatable=false)
private String value;
但是有一个缺点:如果您决定用Java设置字段的值,它将被Hibernate使用数据库中默认值的结果覆盖。如果我理解正确,@Generated annotation应该可以。此注释根据数据库默认字段值设置值 例如:
@Generated(GenerationTime.INSERT)
@Column(name="value", unique=true, nullable=false, insertable=false, updatable=false)
private String value;
但也有一个缺点:如果您决定用Java设置字段的值,它将被Hibernate使用数据库中默认值的结果覆盖。自动回答以将问题标记为关闭
最终解决方案 我们最终选择了两种方法的结合
- 存储过程:数据库将生成值。该过程还确保该值在整个表中是唯一的
- 命名查询:通过过程获取生成的值。我没有使用NamedStoredProcess,因为我们使用的是PostgreSQL,PostgreSQL JDBC驱动程序不支持名称参数,这会引发一些问题
- Oracle触发器:我们正在使用PostgreSQL:(
- UUID:我们的唯一和随机代码具有可读性的限制。假定最终用户能够手动重写它。因此,我们不能拥有像UUID这样的长字符串
- PrePersist:其他业务操作在同一事务中的代码生成之后发生,这意味着这些操作需要在发生冲突时重新执行。我对管理JPA异常(事务范围等)不是很有信心,所以我不想玩它
- @Generated:这是一个特定于Hibernate的功能。我们正在使用EclipseLink
- 数据库触发器:如果代码纯粹是在数据库级别生成的,我会遇到与不获取值相同的问题:值正确地生成为数据库级别,但实体的值将为
null
最终解决方案 我们最终选择了两种方法的结合
- 存储过程:数据库将生成该值。该过程还确保该值在整个表中是唯一的
- 命名查询:通过过程获取生成的值。我没有使用NamedStoredProcess,因为我们使用的是PostgreSQL,PostgreSQL JDBC驱动程序不支持名称参数,这会引发一些问题
- Oracle触发器:我们正在使用PostgreSQL:(
- UUID:我们有一个限制条件,那就是必须让我们唯一的、随机的人类代码可读