如何通过JPA GenerationType.AUTO提供初始值或增量ID

时间:2019-04-04 11:24:32

标签: java hibernate jpa post spring-data-jpa

我正在使用以下代码来定义MyEntity

@Entity
@Table(name = "MY_TABLE")
public class MyEntity {

@Id
@GeneratedValue(strategy=GenerationType.AUTO)
@Column(name = "MY_TABLE_ID")
private Integer myTableId;

@Column(name = "MY_TABLE_NM")
private String myTableName;

//Getters Setters
}

对于我的应用程序启动后的第一个POST,我创建了MyEntity一切正常,MY_TABLE_ID从1开始并按预期工作。

我的问题是,如果有人在执行POST之前手动插入数据,那么我会得到重复键异常,因为已将myTableId输入为1。 / p>

我的主要问题是我现在无法创建database sequence来使用GenerationType.SEQUENCE来解决此问题,因为现在无法更改数据库。 我尝试了GenerationTypeTableGenerator的各种组合,但无法成功解决。

initialValue设置为更大的数字以避免重复的值可以暂时解决我的问题,但我也做不到。

如果有人可以在initialValueAUTO的帮助下为我提供帮助,或者在不更改数据库的情况下为我提供其他更好的解决方案,那将是很棒的:)

4 个答案:

答案 0 :(得分:1)

如果需要更多控制,也可以实现自己的生成器。 请参见此界面IdentifierGenerator。 因此,您可以获取记录计数,例如通过@NamedQuery。 然后,您可以自己生成一个标识符。

public class MyEntityKeyGenerator implements IdentifierGenerator {
@Override
public Serializable generate(SessionImplementor session, Object object) {
    // SELECT count(ent) from MyEntity ent;
    Long count = (Long) session.getNamedQuery("count-query").uniqueResult();
    // calc and return id value
   }
}

实体:

class MyEntity {
@Id
@GenericGenerator(name = "my_generator",
        strategy = "org.common.MyEntityKeyGenerator")
@GeneratedValue(generator = "my_generator")
private Long id;...

别忘了锁。

答案 1 :(得分:1)

由于MY_TABLE_ID是一个标识列,因此以下注释将起作用。

@Entity
@Table(name = "MY_TABLE")
public class MyEntity {

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY) <-- IDENTITYinstead of AUTO
@Column(name = "MY_TABLE_ID")
private Integer myTableId;

@Column(name = "MY_TABLE_NM")
private String myTableName;

//Getters Setters
}

标识列将在提交事务后立即自动分配一个值。您不要为标识列设置任何值,因为它是数据库分配值的工作。因此,您也无需考虑任何初始值(对于标识列完全忽略它们)

答案 2 :(得分:0)

我使用生成类型Identity,这基本上意味着db负责ID生成。

@AllArgsConstructor
@NoArgsConstructor
@Getter
@Setter
@MappedSuperclass
@EntityListeners(EntityListener.class)
@EqualsAndHashCode(of = {"id", "createdAt"})
public abstract  class AbstractEntity<ID extends Serializable> implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private ID id;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "CREATED_AT", updatable = false)
    private Date createdAt;

    @Temporal(TemporalType.TIMESTAMP)
    @Column(name = "UPDATED_AT")
    private Date updatedAt;

}

您还可以使用序列生成:

@Entity
@SequenceGenerator(name="seq", initialValue=1, allocationSize=100)
public class EntityWithSequenceId {
    @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="seq")
    @Id long id;
}

答案 3 :(得分:0)

在这里提供的答案中以及在stackoverflow和其他论坛上的类似问题中,我尝试了各种选择,

我没有什么限制,

  1. 由于数据库更改被冻结,我无法创建数据库序列。
  2. 我不想引入新的Custom IdGenerator类,因为它会使与我一起工作的其他人感到困惑。

已通过以下更改解决了该问题:

GenericGenerator策略中添加increment对我有所帮助,我对代码进行了以下更改。

@Entity
@Table(name = "MY_TABLE")
public class MyEntity {

@Id
@GeneratedValue(strategy = GenerationType.AUTO, generator="seq")
@GenericGenerator(name = "seq", strategy="increment")
@Column(name = "MY_TABLE_ID")
private Integer myTableId;

@Column(name = "MY_TABLE_NM")
private String myTableName;

//Getters Setters
}

它帮助了我,因为, 来自Hiberbate DOCs

  

增量

     

一个IdentifierGenerator,它返回一个long,通过计数来构造   从启动时的最大主键值开始。不安全用于   集群!

因为,即使它是手动插入的,它也会增加已经存在的myTableId,这解决了我的问题。